Microservices as Deep Modules
Apart from different terminology, the notion of deep modules differs from the micro‐ services pattern in that the modules can denote both logical and physical boundaries, while microservices are strictly physical. Otherwise, both concepts and their underly‐ ing design principles are the same.
The services implementing a single business method, shown in Figure 14-3, are shal‐ low modules. Because we had to introduce integration-related public methods, the resultant interfaces are “wider” than they should have been.
From a system complexity standpoint, a deep module reduces the system’s global complexity, while a shallow module increases it by introducing a component that doesn’t encapsulate its local complexity.
Shallow services are also the reason why so many microservices-oriented projects fail. The mistaken definitions of a microservice as a service having no more than X lines of code, or as a service that should be easier to rewrite than to modify, concentrate on the individual service while missing the most important aspect of the architecture: the system.
The threshold upon which a system can be decomposed into microservices is defined by the use cases of the system that the microservices are a part of. If we decompose a monolith into services, the cost of introducing a change goes down. It is minimized when the system is decomposed into microservices. However, if you keep decompos‐ ing past the microservices threshold, the deep services will become more and more shallow. Their interfaces will grow back up. This time, due to integration needs, the cost of introducing a change will go up as well, and the overall system’s architecture will turn into the dreaded distributed big ball of mud. This is depicted in Figure 14-7.
![]() |
Figure 14-7. Granularity and cost of change
Now that we’ve learned what microservices are, let’s take a look at how domain- driven design can help us find the boundaries of deep services.