7

Our team have been debating approaches to integrating external or third party systems when using DDD. The literature is extensive, but sometimes contradictory. Just like a UL helps us better understand and communicate about the domain, we wanted to do a better job of defining the different approaches, and when we might use each? We are not experts, so would be interested in any insights or feedback the community might have, and confirmation we are on the right track.

When integrating with a third-party technology, we identified three different approaches we have used in the past: Adapters (specifically in regards to the Ports & Adapters Pattern), Anti-Corruption Layer and Bounded Contexts.

Acknowledging that there is overlap between each concept, we defined the following team guidelines:

  • An external system is always a separate bounded context — by its nature, the solution will use a different language to that of our core domain.

When deciding how to integrate, use the following guidance:

  • Adapter: When the technology or interface with the external or third-party system is relatively stable, and any data translation required is minimal, or automated, use a basic port and adapter. If the service is integral to the domain model, provide an interface in the domain (as a domain service). Otherwise call directly from the Application layer. This is analogous to what is sometimes referred to as the infrastructure layer. Also referred to as a gateway. Examples include Repositories, Payment Gateways etc

  • Anti-corruption Layer: If the translation required is more complex in nature, or there is a high level of impedance between your context, and the third-party service, implement an ACL in your bounded context. This will include Adapter(s), and specialised Translation services for performing the complicated data transpositions needed. The ACL may provide a facade to set of more complex services provided by the external system. All communication with the ACL happens in the language of the bounded context. The ACL should limit itself to data translations.

  • Bounded Contexts: If you are looking to expand on the functionality of the third party service then create your own bounded context that wraps the external system, and adds to the feature set. Communication with this bounded context can still happen via an adapter or ACL. Or integration may now be achieved through messaging — your new bounded context can have its own adapter for publishing and consuming messages to and from other contexts.

Does anyone have any constructive feedback or critical ideas that they think would help improve our definitions. Or spots something that is incorrect or problematic?

1 Answer 1

3

These all are not wrong, and have some value, but I feel you're going at it with a wrong attitude.

The domain doesn't care whether something is external to the application or not. Separating "external" things from internal things is an arbitrary decision. It is a technical separation and not inherent to the domain.

An example: Let's say we're writing a middleware software for banking, and we want to enable a functionality to freeze all credit cards of the customer. I would model this thusly:

public interface Customer {
   void freezeAllCreditCards();
}

Now do we care from the perspective of the domain whether the implementation is in-memory, executes an SQL statement, does a SOAP request to a third-party system, or even all of them? I would argue we don't care.

So the guideline should be: Model your domain! Regardless of whether parts of it are external or not, because that should be implementation detail.

9
  • A domain model is a logical abstraction of the functional requirements of a system. The purpose of which is to isolate these requirements from everything else (so no dependencies on anything other than the domain). This not only makes it easy to test, but also that the only reason it would change is because the requirements have changed. So by definition we do care how freezeAllCreditCards is implemented - it must occur in-memory. If our method is talking to external systems then it would be better understood to be part of our "service" layer. Commented Jul 13, 2020 at 20:03
  • @king-side-slide Talking to an external system is a requirement of the system. Commented Jul 13, 2020 at 21:08
  • There are many requirements in a system that are outside the purview of DDD. The domain is just one piece of a system. It is special in that it exists to model your problems. This can always be achieved without I/O (remember the domain model is a logical abstraction). I'm certainly not taking the opinion that OP shouldn't implement the requirements of their system. The question is about "how" that can be achieved idiomatic to DDD. Your answer above suggests simply injecting whatever dependencies are necessary into the domain. This defeats the purpose of the exercise entirely. Commented Jul 14, 2020 at 0:33
  • @king-side-slide I've read the blue book and didn't come away with that interpretation, but I've heard it many times. Seems illogical to me, because why would the business care if some business function is implemented partly outside the application. But I might be wrong concerning DDD. If DDD is what you say it is, I'm definitely not onboard with it. Commented Jul 14, 2020 at 7:07
  • DDD isn't a good fit for every kind of problem! The benefits of the exercise are best-realized for systems where the bulk of the logic is contained within the system itself. This means applications that either don't contain very much logic (CRUD) or those that rely heavily on 3rd party services probably don't need the added overhead. The former is mostly data transfer and the latter is mostly glue. This isn't to say either of the above couldn't benefit from the perspective that DDD seeks to provide, just that the benefit is slight. Commented Jul 14, 2020 at 15:07

Not the answer you're looking for? Browse other questions tagged or ask your own question.