Monorepo vs Polyrepo, Microservices with Monorepo in Go

Monorepo is a software-development strategy in which the code for several projects is stored in the same repository. It is controversial and I admitted that it doesn't fit into any spectrum like polyrepo. In this article, I told my experience while working in monorepo and polyrepo. Maybe you have another experience while working with monorepo. I'm glad to hear your review in the comment section below.

I discussed and debated with my friends about monorepo. From high-level to the low-level discussion. Research many articles on the internet. Of course, getting hands-on monorepo to feel the experience. In short, I can say that polyrepo fits all spectrums or all projects. Maybe you think the same because it is a default strategy for version control. But, there is an advantage in monorepo if it fits the project and team. That advantage is what we looking for. But, we will get into trouble if the monorepo doesn't fit, and it is not easy to escape.

Advantages

Disadvantages

We heard that many high-tech companies like Twitter, Meta, Microsoft, and even Google employ very large monorepos. They built microservices with thousands of developers working in the same repository, and even in the same branch called trunk (master/main). That development workflow is called Trunk-Based Development (TBD). Maybe I will make an article about it in the future. But TBD is also controversial, even though I agreed and worked with that workflow.

Microservices in monorepo are hot these days. But, there are things we need to prepare or consider before we set it up. Like setting some rules. There are many rules that we need to set in the team. One of the general rules is the naming convention. In many naming convention topics, I just want to talk about Git commit messages here to keep it short.

We can force our team to use the same Git commit message naming convention using Git hooks.

#!/bin/sh

commit_regex='(chore:+|docs:+|feat:+|fix:+|Merge+|Initial commit)'
error_message='Your commit message is invalid.'

if ! grep -iqE "$commit_regex" "$1"; then
    echo "$error_message" >&2
    exit 1
fi

The code above is just an example of a Git hook for a commit message. To enable the hook, you can save it to commit-msg, put it on <your-project>/.git/hooks, and set permission on it like chmod ug+x <your-project>/.git/hooks/commit-msg. For more information you can visit, https://git-scm.com/book/en/v2/Customizing-Git-Git-Hooks.

In this article, I create an example of setting up a microservices project with monorepo in Go. Let's say we want to build a Blog. So, I created a file structure like this.

+-- article
|   +-- cmd
|   |   +-- app
|   |   |   +-- main.go
|   +-- internal
|   |   +-- internal.go
|   +-- pkg
|   |   +-- pkg.go
|   +-- go.mod
+-- image
|   +-- cmd
|   |   +-- app
|   |   |   +-- main.go
|   +-- internal
|   |   +-- internal.go
|   +-- pkg
|   |   +-- pkg.go
|   +-- go.mod
+-- pkg
|   +-- pkg.go
+-- user
|   +-- cmd
|   |   +-- app
|   |   |   +-- main.go
|   +-- internal
|   |   +-- internal.go
|   +-- pkg
|   |   +-- pkg.go
|   +-- go.mod
+-- go.work

In Go, all packages in the internal folder cannot be exported. In this example, we have three services; user, article, and image. And we have one global package, pkg. All services have public packages in the pkg directory.

go 1.19

use (
    ./article
    ./image
    ./user
)

The go.work file allows text editors to understand monorepo projects. For more information about go.work files, you can visit https://go.dev/doc/tutorial/workspaces.

module github.com/aristorinjuang/microservices-go/article

go 1.19

require github.com/aristorinjuang/microservices-go/pkg v0.0.0

replace github.com/aristorinjuang/microservices-go/pkg v0.0.0 => ../pkg

Just let the global package, pkg, on the v0.0.0 and use the replace syntax to import it to the sub-project or service.

When we are in a single project or polyrepo of Go, it is easy to build and test the project. Just use go build and go test. When it comes to monorepo, we need to build and test all or several services at once. I suggest you Bazel. It is fast and you can integrate it into your CI/CD. Very impressive.

Related Articles

Comments