Splitting a codebase. Small, and Focused on Doing One Thing Well.
At 1st Chapter of Building Microservices by Sam Newman, the author described the motivation.
Codebases grow as we write code to add new features, Over time, it can be difficult to know where a change needs to be made because of the codebase is too large. Despite a drive for clear, modular monolithic codebases, all too often these arbitrary in-progress boundaries break down. Code related to similar functions starts to become spread all over making fixing bugs or implementations more difficult.
With a monolithic system, we fight against these forces by tying to ensure our code is more cohesive, often by creating abstractions or modules. Cohesion – the drive to have related code grouped together – is an important concept when we think about microservices. This is reinforced by Robert C. Martin’s definition of the Single Responsibility Principle, which states “Gather together those things that change for the same reason, and separate those things that change for different reasons.”
Actually it is quite important to have solid borders between bounded contexts. It guarantees that nobody crosses the border easily, no one joins 2 entities from different contexts.
Allow us to use the right technology for every service. Or do some experiments with various technologies.
If we want to scale some part of a monolithic application, we have to scale everything together. Even if one tiny part of the system has performance issues. What is wrong with scaling a big app you may ask. First of all, it is a cost, it might be quite costly to instantiate several instances on an application, in terms of CPU and memory consumption. Or even some apps can not be scaled at all because they rely on some shared resources, that are limited, like Oracle DB with licenses policy. If we split the monolith into several services we can scale an app independently and increase the number of instances only for parts that have performance issues.
Ease of Deployment
Even small changes for a monolithic application requires redeployment of the whole application. The bigger the deployment unit the riskier it is. Because of this: it is harder to control what exactly features we are deploying and most important what exactly we are not deploying. And it is quite challenging or sometimes impossible to roll back a big bunch of commits. With microservices, we can deploy relatively small pieces of code, that should decrease the risk.
Reducing deployment time
Every deployment is stressful not only for developers and managers but also for your cluster. You need to switch off an application or, at least, to rebalance streams. If deployment time decreases it means that a cluster will be in an unsafe state less time. And, obviously, microservices require less time for redeployment.
Responsibility can be easily shared among a large team.
organizations which design systems … are constrained to produce designs which are copies of the communication structures of these organizations.
— M. Conway.
If you have a big team most probably you have to split it in some way. Each team will be responsible for some piece of code. The further the teams the more isolated the parts of the system will be. Microservices have quite robust and obvious borders. If one part of the Big team decided to use stack X it does not affect other sub-teams
If you have a monolith and you ought to change API but some of your clients are not ready, you have to support 2 versions of API. It means that the monolith application has some overhead for maintainability. For microservice architecture, you can deploy two versions of the service. One of them supports the old API and another one supports the new version. The new version can evolve despite outdated restrictions for the old API. When there are no clients, who use the old version, we can simply remove the old version of the service.
Optimizing for Replaceability
We’ve seen quite often systems that are obviously outdated, consume tonnes of money for maintenance, but still alive, because it is impossible to rewrite them from scratch because they are too big. The microservice architecture allows you to avoid this issue. Each service can be rewritten separately, and if API remains stable no one client notices that something has been changed.