Distributed monoliths occur when the structure of an organisation and its code is split up whilst still being tightly coupled. This becomes a problem because the scale of the system increases but all of its parts need to be managed together, slowing down and increasing the risk of any changes.
It is important to be able to identify when you are dealing with a distributed monolith but how can we? Lets look at 6 symptoms that your software architecture is a distributed monolith.
1. Lock Step Deployment
When two services need to be deployed together, they are coupled. If they are within a monolith this can be easy to manage. However, deployment can become slow and painful if they are separate services that should actually be managed independently. We can resolve this problem by identifying the cause of the coupling and refactoring our solution.
If the two services use shared code, the solution could be restructuring the code to share a library that is managed separately. If they use shared infrastructure, this could mean splitting the services onto separate hosts.
2. Version Coupling
If Service A directly calls a version of Service B, every time Service B is updated we need to update the configuration of Service A. This coupling of changes can make it complex to manage the lifecycles of both applications but it is possible.
Ideally, Service A should call an endpoint for Service B that isn't a specific version and is also managed by Service B. This can usually be done with DNS by using CNAMES like this:
A1.domain.com > calls > B.domain.com > B1.domain.com
instead of this:
A1.domain.com > calls > B1.domain.com
3. Bi-directional Dependencies
If Service A calls Service B and Service B calls Service A, it can be difficult to test changes to either system. When this happens we have the option of changing the whole environment simultaneously, testing events being sent to through both the old and new versions of software, or significant extra complexity in how to route messages.
4. Shared Database Access
When two services share the same database access it becomes easy to pull data from another domain without calling the service directly. This can lead to coupled services that are connected at the database layer. When a service modifies it's own database structure it shouldn't impact any other services. If it does, then the services are coupled.
There is nothing wrong with sharing a database to save on administrative effort but this should be tightly controlled with security to prevent coupling. A common way to do this with Postgres is by using separate users and schemas per service. If a service wants access to another service's data it should call the downstream service directly.
5. Shared Queues
In the same way that shared database access causes coupling, so too do shared queues. If two services talk to a shared queue directly, it isn't possible for either service to safely modify, change or redirect the messages without risk of breaking both services.
Sharing queues should be avoided as much as possible and any queue should be owned by a single service and not exposed to others.
6. The Enterprise Service Bus
The enterprise service bus (ESB) is another common data storage pattern similar to shared databases and shared queues but on a larger scale. ESBs aim to allow any message to be sent and received via a central bus. This means that once a service sends a message to the bus it is not clear who is consuming the message, what is being done with it, and if it succeeded. These issues can't be easily resolved and mean that our system becomes coupled with not only one other system but more than we may be aware of.
Regardless of your system architecture you should be able to clearly identify if your system is a monolith, microservices, or a distributed monolith. Identifying coupling to other services through shared deployments, shared data, and bidirectional dependencies is critical in this process. Doing so will allow us to structure our architecture so that we can avoid ending up with a distributed monolith.
Follow me here for more content or contact me: