Introduction
The choice of repository structure plays a pivotal role in shaping the efficiency and scalability of your projects.
A monorepo lets you break your monolithic codebase into well-defined domains or bounded contexts.
In this article, we will outline some benefits of monorepo for your product.
Shared codebase
The workflow to share code among multiple repositories is like this:
- You create a pull request in repo A
- you await the review of your changes
- you merge your changes in repo A
- you make a release to repo A
- you update repo A dependency on repo B
You need 5 iterations to update shared code among polyrepos.
This is a workflow in a monorepo:
- You create a pull request in monorepo
- you await the review of your changes
- you merge your changes in monorepo
In a monorepo, you only need 3 iterations.
However, you earn much than that, you make sure your code will work at first.
When updating a code in repo A, you can't share the changes will be enough for the repo B use case. You could need to go back and forth until you get it right.
New package vs new repo
It is simpler and easier to create a new package inside a monorepo than to create a new repo.
The new package will reuse all the infrastructure already in place. Linter, tests, CI/CD, automation.
The new repo will need to be created from a boilerplate that is probably outdated.
Most developers will avoid creating a new repo as it requires a lot of effort.
Unified Tooling
A monorepo lets you unify your tooling and codebase patterns.
You can have a single lint config, you can have a single CI/CD config. As a result, you have a more unified codebase.
You can use the same test and build configs among packages.
Centralized dependencies
You can keep all your dependencies updated in a monorepo. No need to update the same dependency in many repositories.
Bounded Contexts
You can use packages to provide a public API for each domain or context of your product. And keep the private API unexported.
This will make sure you don't couple your code too much.
Read more about DDD on monorepos here: Domain Driven Design using a monorepo
Refactoring and codemods
A monorepo makes it easy to refactor and apply _codemods _(transformation over AST) to reduce legacy code.
You don't need to apply the same refactor in many repos, just in a single repo.
In the final analysis
A monorepo lets you add more structure to your codebase as you grow. You can start your monorepo with one single package, and add more packages as needed.
You can have one package for each domain.
You can have one package for each service or lambda.
You can have one package for your design system.
How does your monorepo looks like?
Woovi
Woovi is a Startup that enables shoppers to pay as they like. To make this possible, Woovi provides instant payment solutions for merchants to accept orders.
If you want to work with us, we are hiring!
Photo by Amélie Mourichon on Unsplash
Top comments (6)
In 99.9999999% I hate monorepos.
It might be good at the start of your project, but at one point of time it might become a hell for developers to work in such space.
There are few things, which I don't like:
No. We're actively moving away from a monorepo right now because it's a mess. I'll grant that it was mostly ad hoc, and maybe it would've been different if we went into it intentionally, but we didn't and it is what it is.
The main benefit in having multiple repos is that they're isolated. You can make changes to one without worrying about impacting another. You can version them easily - if there's a commit to this repo, you bump the version. If I want to upgrade a dependency in one project without upgrading it in another, it's simple - no concerns about different versions possibly clashing.
Lots of boilerplate? Script it. Create templates. Hell, just do it manually - you only have to do it once per repository.
Are your build files a lot of copy pasta, and you're worried about updating everything when there's a change? Not sure what build system you use, but surely it allows for some kind of plugin system. Use that. If I'm not mistaken, I think Gradle even recommends writing custom plugins for a lot of stuff you'd normally copy and paste, they want you to look at plugins as the "type" of project you're working on.
You're a coder! It's literally your job to take tedious crap and automate it. I don't care what you're writing, you're doing it so that a computer does something that a person can't or won't. Boilerplate and common build functionality is just another example of that.
Your update to your common library now involves more steps before you can use it. So make sure you have your changes tested and documented thoroughly, make sure it passes code review, make sure you don't have to go through it all again. Does that process take a long time? Then work it out with your team! Communicate! Figure out how you can speed up the overall workflow. Don't just hack around the roadblock - you're better than that. Fix it.
Also, make sure you're using good design patterns and principles in your code. You might be able to minimize work in your library projects if you developed them to be easily extended.
I'm sorry, but stuffing everything in a monorepo because you're impatient or don't want the "hassle" of dealing with separate projects is no solution.
Wouldn't that be against DRY principles? What if I need my libraries in multiple projects? Do I have to make the changes in all monorepos and what's the benefit of this?
Then that wouldn't be a candidate for inclusion in a monorepo
Or, you could still include the package if the primary use is in that monorepo, and publish to a private package that can be pulled in elsewhere
Firstly, I recommend you to really think about your libraries. Are they really libraries?
They are libraries otherwise I wouldn't have said it. They have their own repo, their docs, changelogs and so on.
That's why I wondered why they should be included into the main repo of every project instead of their own repo - as the article claimed somehow (the author corrected that in the comments but it wasn't clear at first)