DDD and Code ReUse
- The Fallacy Of ReUse (Udi Dahan)
- WebCast on SOA in the E-VAN (Udi Dahan)
- Feature by Feature (Oren Eini)
Different kinds of Code ReUse
You can split your code with different concern :
- Object model extensions
- Technical Infrastructure
- Application code
The first two are good candidates for Code ReUse.
By Object model extensions I’m talking about things that make your code writing less tedious at language level or object model level.
Example of such code are :
- IEnumerable and Enumerable
- Reflection helpers
- Dependency Injection framework
By Technical Infrastructure I mean things that make your code run in its environment :
- Generic Service Host,
- ORM, Data Layer
- Format serializers / deserializers
- Configuration helpers
- Communication frameworks (WCF, Service Buses)
- UI frameworks (MVC, WPF)
The last part is Application code, and here, things are really different.
Application Code ReUse
For long I’ve been writing business code in libraries. I began then to notice problems concerning code and data locality.
When you have a single application (process), no problem.
But if two applications need to modify the same entities, the solution would be to use the same library in both applications so that there is no code duplication. It seems good practice but you quickly stumble on several problems – I’m sure you already experienced it :
- Synchronization : the same data will be accessed in the same db from two application, how do you manage conflicts
- Deployment : when you fix bugs or add features, you must redeploy every application that has a dependency on the library. It slows down the release cycle and make it more risky, changes have more impact.
- Code locality : when a problem arises, you have to find which application it comes from.
Let’s examine DDD patterns to see how they fit with reuse :
Let’s start easy. Services are stateless, they should deliver simple action. But to preserve encapsulation the better is to put services as true services in their own process (web service, windows service, service on a service bus..).
This way, synchronization is managed in process, deployment is a breeze, and no problem with code locality – code executes in one place.
Entities are retrieved through a Repository Service, hence, they should follow the same rules as Services.
This way, the implementation of a repository that access the database is truly an implementation details. Anyone who wants to talk to an entity sends a command to it, a handler service get the entity from the repository, and pass the command to the entity. The configuration to access the database is local the to the process.
Here again, same benefits.
Moreover entities should always have different meanings in different bounded contexts, the should have different implementations, so there is no real reason for reuse.
Value objects are a bit different.
Some object are very specific to a bounded context and don’t need to be reuse outside.
Some other can be a good way to encapsulate some shared concepts. Money is usually a good example, but there can also be concepts more specific to the domain (you will find them as words that come in the Ubiquitous Language of different Bounded Contexts).
They can be shared among different contexts, but rarely between different domains. There are exceptions for very very generic concept like money, but even money often needs to be tweaked a bit for each domain…
Service Bus to the rescue
Once each bounded context is split, you need to organize communications between parts. Here comes the Service Bus and Messages, but now, the only shared parts in the application are :
- Object model extensions (to code faster and cleaner)
- Technical infrastructure (so that each process is fully equipped, and there’s not much technical fuss in the application code)
- General use Value Objects (to manipulate domain concepts instead of int and decimal)
- Messages (to communicate between contexts)
You could also use web services, but it makes the overall structure less fault tolerant, harder to deploy, and more tightly coupled.
Once you’ve decoupled bounded context using messages, the rest is just an internal implementation detail, why would you want to reuse it !