My team uses a “monorepo”. Let me clarify why I quote the word: Our company doesn’t share one large repository. Rather, our team decided that all of the project we care for should live in one place.
Let me give an example of why monorepos are great: we use elm-export. This lets our backend generate the part of the Elm code that our frontend uses, and all the encoders and decoders that you can imagine for them. Having both our backend and our frontend in the same repository means that the shared CI tool guarantees that updates to our API are implemented on both sides. No versioning needed here.
On the other hand, another unrelated team also uses some Elm, and they’ve had to patch elm-export for some reason at some point. Had they been in the same repository as us, one of the three would have happened:
- They would have had to fix our code in order to be able to move on,
- We would have been pulled out of what we believe is our priority to fix our code,
- We would have used different build targets for the two projects, effectively making virtual separate spaces inside the monorepo.
I guess everyone agrees that the two first options aren’t very attractive, so let’s focus on the third. Having one repo guarantees a working head only if the CI is applied on the whole repo. Making a diff system is essentially similar to building a versioning system. Building the mother-of-all-CI has a cost. For a collection of separate repositories, it is kind of a waste.
So if the company has separate repos, are we not a monorepo ? Well, I would beg to differ. All the bits that are relevant to our domain and that we can afford to maintain are in our repository. For the remaining bits, they are either unmaintainable by our team, or they don’t change enough to make it valuable to source them.
The point I’m going to here is that monorepositoryness is a spectrum. On one end, you have people making repos and packages out of everything, and living with the resulting dependency hell, and on the other hand, you have Google, with the means (both organizational and technical) to live up to the dream (or do they?).
When we decide to unite a piece of code and its dependency, we essentially assert coupling between these pieces. Coupling comes with a cost in terms of CI length, in terms of the complexity of the system, and in terms of the cost of a single modification. On the other hand, when we segregate a dependency, there is a risk: when we cut apart two things that are coupled, we increase the risk that CI won’t catch mistakes. A good team may make good coupling decisions, but there is no recipe to avoid mistakes.
The balance between risk and cost is not something that people will universally agree on. If you have Google’s deep pockets, you will probably not want to risk bugs. On the other hand, if you have less company buy-in, or simply less money, you may pick the opposite solution.