A problem with Domain-Driven Design (DDD) since the beginning has been the too common hunt for perfect designs, but DDD is not for perfectionists. In order to stop that hunt you need to have some idea of how to create software that is well designed, yet not perfect, Eric Evans noted in his presentation at the recent DDD Europe Conference in Amsterdam, giving some examples from his years working with DDD.
Evans, author of the original DDD book, notes that the original purpose for a Bounded context was to recognize that the environment in which we develop software is rather messy with a lot of legacy and other external systems, as well as other teams that may interfere. The context surrounds a part of a software in which you have conceptual consistency and where a particular word always mean the same thing. As a developer, you should be able to tell if you are inside the boundary of a context and then need to follow the rules specific to that context. This boundary creates freedom to define the rules that apply there; not just the terms used, but also the architecture and the development process. Evans points out that a microservice, which should be autonomous, can be a good bounded context, but emphasizes that this does not mean that a service always is a bounded context, something that developers sometimes interpret it as.
For Evans, there is a relationship between Conway’s law and the concepts of a bounded context, and he want to set up things so that this law is helping him. He describes an example with a system with two contexts; one responsible for credit cards and another for cash accounts. Here we have alignment between the organisational structure, the subdomains, and the bounded contexts. But now the business reorganizes to a focus on market segments, separating business accounts from private accounts and creating a team for each type of account. The two contexts will still be the same, so the teams are now working in both contexts, sometimes stepping on each toe, meaning they need to coordinate their work. He compares this with a three-legged race where coordination is essential to get some speed. A risk here is that this creates a Big ball of mud, a common reason that Evans has observed is lacking clear stewardship over the software. A solution may be to create a new boundary, using an Anti-corruption layer.
Sometimes a model is a little incomplete, lacking the ability to handle all the cases it’s meant to handle. Instead of creating a model that is able to handle more cases but feels awkward, an alternative may be to create a function that deals with cases not handled by the model. Such a function works with lots of if-then-else statements, staying away from any high-level concepts to avoid creating yet another model. An abstraction that is leaking or confusing should not be used at all. Evans notes that it’s better to use if-then-else instead of creating an illusion of an elegant model. Such a model may even prevent finding a working model. He believes that this is a great example of a trade-off, aiming for a good but not perfect design.
Evans does not recommend working with a model until it’s perfect, as then we will not ship any software. We have to get over the idea that design is something which you invest some extra time in upfront and get paid off in the long run. However, we mustn’t go to the other extreme either, just hacking out something horrible and shipping it. We will have a much better result when we are being conscious of the trade-offs in our models and have techniques for what to do when we are not entirely satisfied with the models we have.