Microservices are about independence to avoid coupling as much as possible. Therefore it makes sense to keep code in separate repositories. Martin Fowler refers to the microservices architectural style as
an approach to developing a single application as a suite of small services
The key here is that the microservices do not add value independently. It is the whole set of microservices which compose the application that really adds business value.
Would it make sense to have microservices code in a single repository ? Microservices should be deployable independently and this seems complicated with a mono-repository.
On my current project, we have several services forming a single application, each deployable independently. Services are separated by logical or technological boundary.
Each service is hosted on a different repository. Thus each service has its own continuous integration script, its own Merge Requests and its own deployment script.
Since all of these services are part of the same application, each new feature can affect multiple services. As there are multiple repositories, there are multiple Merge Requests about the same feature. Imagine if one merge request is validated and the other one is not ? How can atomicity be guaranteed with such a workflow ?
Mono-repositories to the rescue
With multiple repositories, we had the following advantages :
- repositories arranged around technological stacks (and around skills)
- simple commit history
- fast continuous integration (and fast feedback)
- fewer files to maintain
- clear separation of concerns
How is it possible to have a single repository without giving away the benefits of poly-repositories ?
Typical code reviews in a multirepository architecture happen independently on each service
Features span across multiple services. This is why Merge Requests should also span across multiple services. This is only feasible with a single repository. Services can be placed into different directories while still keeping services independent.
Code reviews have a broader spectrum and give a wider view. Merges can be done atomically. There is no uncomfortable situation where a story is merged for one component but not for the other.
Commit history is helpful for knowing what has happened on an application. In other words a change log. What good is an application change log that spans across multiple repositories ?
Commit history will be clearer with only one repository.
Fast Continuous Integration
Running a CI on a single services is surely faster than for all services. Though not all services need to be built after each push : only the ones that were modified. Modern CI can build services in parallel and build only services which were modified. Fast feedback is available for all services.
Fewer files to maintain
Services files are split on multiple repositories so there aren't really fewer files to maintain, they are simply organized differently.
Separation of concerns
Poly-repositories are organized around services, not applications. By keeping services within the same repository, modifications about the same feature are kept together. Poly-repositories on the contrary do not enforce separation of concerns but separation of technologies.
Simon Brown introduced the concept of a modular monolith. This has a similar approach as services (or components as Simon Brown puts it) are grouped inside the same repository. Each service is independently deployable but form a whole, meaning that one service alone does not add business value.
Repositories should group all services of an application because they have the same life-cycle. Things like continuous integration, merge requests and deployment can be kept together.
Next article will be about migrating microservices and their continuous integration in Gitlab-CI.