Dependency handling for microservices with Golang: monorepo vs multirepo

Golang Microservices

Microservice architecture is famous nowadays, but it has some drawbacks, see my earlier article: Microservice architecture is not a silver bullet. One of the painful complexity is handling the component version dependency.

The component version dependency is more than component dependency, because it specifies which version is used on the dependency. Handling this additional info makes a lot of headache for the engineers.

The components are developed by different teams and it have different version numbering and release dates. It is hard to follow and find the good setup of the component versions. One component can have more referrers which may expect different versions. Let’s take a look below simple system:

Fig. 1: A dependency cycle (from Robert C. Martin: Clean Architecture)

Five components refers to Interactors component. In ideal world the referrers expect same Interactors version. But in the real world, the referrers are tested with different version of Interactors or a new version of Interactors introduces a non-backward-compatible change, but not all referrers are updated to support this change. It’s hard to figure out, can a referrer use a newer referred component version without testing it together.

Another problem is, the inter-component dependency must be defined with version in source code at implementation time and in the deployment config at deployment time, see a citation from Chris Richardson: Microservices Patterns:

In a microservices-based application, changing a service’s API is a lot more difficult. A service’s clients are other services, which are often developed by other teams. The clients may even be other applications outside of the organization. You usually can’t force all clients to upgrade in lockstep with the service. Also, because modern applications are usually never down for maintenance, you’ll typically perform a rolling upgrade of your service, so both old and new versions of a service will be running simultaneously.

It’s hard to keep in sync the version dependencies between two components at different places and time (in the source code during implementation and in config files during deployment) in order to have the expected versions runtime (process view).