DDD Reference is quite good reminder of rules and practices of DDD. You can get it from Domain driven language site, but do be aware that it is not meant as a DDD introduction or full description. This post is also meant to be a reminder of most overlooked and crucial aspects of DDD and small discussion of new terms introduced in Domain Driven Design Referance. I won’t introduce DDD here, there is an introduction to DDD available on half a million blogs (more or less), and there is a linked to a presentation on my linkedin profile site.
I recently read a few interesting articles about architecture and DDD (Domain-Driven Design Revisited, The Biggest Flaw of Spring Web Applications, Whoops! Where did my architecture go). These show how complex is to design good software. Many projects end with big ball of mud, we follow new approaches (see Monolith First, response to this article or interesting view by Sander Mak). My opinion is similar to Sanders. We have the tools most of the time we develop software, we just don’t use the right tools or we are constrained to use the right tools by standards, lack of people or stubbornness of senior staff, maybe lack of time to find the proper tool using exploratory development or sacrificial architecture. There are many different reasons.
Should you start with monolith or microservices – it depends. But you should start with a good design, and here Domain Driven Design can help us. One of the fundamental building blocks of DDD are bounded contexts, explicitly defined contexts that distinguish and separate parts of bigger model. Each bounded context can be developed independently, can use different implementation. Integration between bounded contexts is described as context map. So one way to approach the monolith vs microservice dilemma is to start with designing bounded contexts, design modules accordingly (bounded context <> module), and then we have a good foundation to go towards more coarse grained or more fine grained modules. DDD context map will set constraints on integration and this way we can avoid tangled modules that will not allow us to extract microservices and use heterogeneous cluster deployments, where one service or set of services is deployed on more instances as it needs to process more requests, or use other benefits of microservices architecture.
Domain Driven design also gives hits on designing each of the bounded contexts. I would like to focus on layered architecture and the use of packages as a way to hide classes that should not be visible outside the package. This rule, about which Oliver Gierke reminds us, is an excellent way to mark boundaries and interfaces between bounded contexts in monolithic architectures allowing us to evolve toward microservices should it prove to be viable. This simple rule can shield internal details of our bounded context from being used not the way we intended them to be used. In a non-trivial project this will be even more beneficial. We would not need some tools to check rules set by the designer of bounded context because compiler would not allow for introducing invalid dependencies. On the other hand checking dependency correctness can be a little bit harder as some rules will not be check by compiler inside the slice. Fortunately there are tools to help us here like Sonar, Structure101, Dependomenter, Sonargraph to name a few.
In my opinion Domain Driven Design gives us a lot of good rules to follow in order to build good software. Going toward monolith or toward microservices should not be a problem once you have solid foundations. But remember that Domain Driven Design is a tool – if used in wrong context it can be an burden.