Q:

Decoupling external dependencies

We have a simple REST webapp which is dependent on multiple external services, mostly Kafka messages. An attempt was made to isolate external dependencies by encapsulating all external interactions in a separate webapp, and make the core app communicate with the external interfaces app only through an internal kafka topic. 
    ----------                                   ---------------
   | core app |  <---Internal kafka topic --->  | external      | <--> external kafka topics 
   |          |                                 | interfaces app| 
    ----------                                   ---------------

Now we are slowly coming across more and more requirements where we would need to make synchronous calls to external systems, some REST, some SOAP. Would adding these kinds of requests through the external interfaces app and reading the results back via an internal kafka topic scale well?
What are other strategies we can use here to decouple external dependencies?

A:

Decoupling-wise, what you might want is to create an adapter/abstraction layer only present in the core app package and make your core app depend on this newly created layer.
Moving the management of Kafka to a different project is not a bad idea, however, even then the core app should not directly depend on this newly created web application, but provide the abstraction layer for the internal application and then use this abstraction layer in its code.
The rule of thumb, in a language with namespaces, should a project always have its own base namespace, using which it can be identified, besides a packages or modules layer (or whatever you call the layer in your code), layers providing the abstraction layer for external dependencies, the application should only depend on classes from the same base namespace.
So in a project A, which uses the project B, I would create a modules layer abstracting the B layer to my own needs, suitable to what the project A requires, and then use this abstracted layer in the A codebase.
Later in project C, which uses the project A, I would again create an abstraction layer efectively hiding the A dependency by providing an adapter interface.
By doing that, you do not care very much about minor changes in the external dependencies (method renaming, shifting of method arguments,...), because it is all in one place, the modules abstraction layer only, therefore the fix is very simple.

