When architects and developers embrace microservices, one of the most challenging questions is: “How big should each service be?” While true, the obvious answer – “it depends” – needs unpacking. Based on guidance I developed for internal use at Monday.com, this post explores the key factors and tradeoffs for service granularity decisions.
Deciding on service granularity isn’t a one-time thing. What starts as a well-sized service can evolve into a monolith as functionality grows. Fortunately, architectures can evolve over time (also see my articles on evolvable architectures), and we can split/unite services as we go along.
At its core, the decision to break apart or combine services revolves around one fundamental concept: friction.
Some forces drive us to break services into smaller ones
- Different functionality
- Different quality of service (QoS) needs
- Different access restrictions
- Different scalability needs (maybe even resulting in different implementation languages)
And some forces push us to keep services big or even unite smaller services into larger ones.
- Overhead exceeds usefulness
- Transactional behavior/ Tight data dependency
- Change together to deliver business workflows
- Avoiding accidental complexity
Let’s look at them in more detail:
Break it down
As mentioned above, friction is the underlying motivator for deciding on granularity. If you worked with a monolith, some of the reasons that drove you to go to services were probably things like:
Common challenges that drive service decomposition:
- Build and Deploy Complexity: Even minor changes require complete codebase rebuilds and redeployments
- Coupled Change Cycles: Different teams become unnecessarily dependent on each other’s deployment schedules
- Difficult Modularization: Maintaining clean architecture becomes increasingly challenging
- Inflexible Scaling: Unable to scale components independently based on their specific needs
- Team Conflicts: Frequent code conflicts and unclear ownership boundaries
- Ambiguous Ownership: Areas of code without clear team responsibility
The same challenges can also occur within smaller services – and there are native forces that can serve as indicators that it is time to split a service.
Different Functionality – Different Reasons for Change
A service should be cohesive, i.e., the functionality that makes its business logic should belong together. A good sign of logic is cohesion is if it feels natural to couple it (while some degree of coupling is acceptable – this is something that you should watch and not let spiral out of control, but that’s another story).
At different abstraction levels, things can look cohesive or different. A guiding principle is how much code and how many developers are working on the functionality. It is good to be vigilant since, over time, seemingly related multiple functional areas in the same code base can evolve in