Hacker News new | ask | show | jobs
by ZeKK14 1456 days ago
Well, it's not that easy. Let's say you have this layout :

- applications: front, backend, background-worker

- libs: database-orm

In a multi-repo layout, if you want to make a change in database-orm, you'll make your PR in its repo, test, and make a release with your changes.

Nice and easy right ? Well, you're not done. Now you have to make a PR to update the dependency on each repo using this library. If you're lucky, nothing breaks and it's quite quick.

But it's not always so easy : you notice that you actually broke something down the line in the backend. You have to fix it (in your library), and do it all over again. You can also have libraries depending on other libraries, multiplying the effort when you messed up something.

The monorepo handles that, you update one library and you can see what you broke down the line, and fix all of that quicker. Also, changes are easier to follow since one modification impacting several applications or libraries can be made into only one commit.

You can tell me that libraries should have a nice definition and the applications should be independent from the actual internals, but that's rarely the case. It's a tradeoff and lots of companies are going this route.

4 comments

I can assert that from what I have seen during the last 30 years, I rather bet on multi-repos and binary libraries than monorepos.

The processes you describe are great to make teams think twice how to go at a change, instead of "let's change everything and see how it goes" attitude.

That time spent thinking of how to plan a change goes away when you have a monorepository. You literally don't pay that cost as you can work out the change fully locally.

I built a tool to bring up every microservice locally so you could test every change together so the separate repository problem went away. It coordinates vagrant LXC environments.

The version I built at my employer was integrated with chef and Ansible. The version I built at my employer handled cloning and pulling dependencies too. And could build in parallel and deploy to local load balancer haproxies.

But my open source version is barebones by comparison. In the future I shall try build developer tools open source rather than trapping work at my employer.

HTTPS://GitHub.com/samsquire/platform-up

>That time spent thinking of how to plan a change goes away when you have a monorepository

Not entirely. Since the fleet isn't atomically updated to the next version you have to be careful about multiple versions being compatible with each other.

Upgrading software and Postgres databases is a difficult problem in general.

The text itself can be changed but it takes at least 15 minutes to mutate to a deployment. We still cannot generically mutate running code to other running code. Ksplice and other live kernel patching and Chrome's binary patching should be generalised and productised.

Patching methods at runtime is another thing that is possible (ruby, python and Erlang) but I am not aware of a general framework for deploying mutations to servers at runtime.

Thats whats called „dependency management” and it should be built into your CI/CD, in majority of cases (non-breaking changes) after one repo PR merge you create a feature branch in the second one with new dependency already in place and all you have to do is apply feature changes you are working on.

But yes - GitFlow or Environment Branch HELL is so common in the industry - its hard to talk about better approaches.

Or you have a monorepo and you make the change in your backend, then you make the change in your dependencies, then you have one commit, one PR, one test run, and one release.

The solutions to monorepo taking 10x longer to build seem to be "Spend 10x longer on the manual developer parts doing 10x more procedure with more tools, more rules, more work"

Sounds good, doesnt work.

One place change == X possible conflicts.

Ten places over longer period of time (a lot bigger PR) == XXX possible conflicts.

All depends on the size of the team and project.

Tho its hard to find a good place to switch from one approach to the other one.

You assert that it doesn't work however we are in a thread where a major company like Uber has switched to it making your assertion ring hollow.

I do not understand your point about conflicts as 3 commits across 3 projects with 3 different CI pathways is going to cause more conflicts than 1 commit across 1 repo. In my experience managing one code change or project across 3 repos is a 10X difficulty increaser in terms of repo management, conflicts, etc. It's not just 3X harder, it's 10X harder to me. The number of times I've seen a spelling mistake/naming difference/etc in 1 out of 3 repos because the PRs were done separately and no one noticed is too damn high.

The simplicity of having it all together strongly outweighs the benefits of multi repo in most situations IMO. The number of projects/companies/etc that would benefit from some highly engineered microservice-based multi-repo monster is probably less than 100 in my country, and 1000 worldwide.

The issue is pretty simple. If you have 100 ppl working on the same directory, the chance of them conflicting each other is ALOT BIGGER than 100 ppl working on 10 different directories. It's a simple probability.

This is the issue with monorepos -> That over time the more ppl work on them, the higher the chance of the CICD to fail due to conflicts. And till now pretty much NOONE in the world fully resolved the conflicts issue.

Companies introduce merge queues which cripple productivity, because every next merge "can" (but doesn't have to) break all previous PRs.

Instead of having a very easy Feature-Branch pipeline, you have to build some abomination that becomes a bottleneck as soon as the company starts growing.

--- Like I said in other comment - majority of IT still lives in GitFlow/EnvFlow hell. Some of us learnt from those mistakes and do better now.

What you are describing as the good parts sounds to me as what you get from a traditional monolith.

Why build libraries and separate services if an update on some part of the codebase needs changes across all the platform?

This trend of microservices + monorepos sound to me like taking the worst part of everything.

If you do microservices, then let each team have their own stack, their own tools, their own libraries and be independent and just agree on the APIs.

If you want everything super consistent and share as much code as possible, etc then just do a traditional (well architected) monolith, maybe deploy it with different configurations for different scaling needs, etc.

Monorepos are to me a symptom of worse problems.

I worked for a.company where they had a rule that "every repository should be a monorepo". They didn't even understand everything that was wrong with that rule.

Imho, with mono repos you can achieve all the benefits of a monolith with the benefits of a micro service architecture.
Except you're now calling functions across the network. And no more complete tracebacks. And need to deploy 10 things at the same time or everything falls apart.

Yes, you get the benefits, but also all the drawbacks. Those drawbacks might make sense for extremely large teams. I want to cry every time I see a 20 engineers teams wasting company's money with this.

Yes. So if you have to do micro services. Better do it from a mono repo.
> But it's not always so easy : you notice that you actually broke something down the line in the backend. You have to fix it (in your library), and do it all over again. You can also have libraries depending on other libraries, multiplying the effort when you messed up something.

Since this is Go, it's trivial to point in-development branches of downstream projects to an in-development branch of a dependency before merging it for those projects' testing processes. (This still doesn't cover 100% of cases of course, but nothing does. The better answer is not to over-factor in the first place.)