Is a Monorepo a good idea?
An investigation into how we can store code and share features, services and config between deployed applications to maintain standards and save time.
Imagine we are working on a greenfield project where one of the requirements is to breakdown a large and ageing monolithic application into microservices and a new User Interface — you know the drill :)
The goal is to split the current monolith into many small web applications with fewer responsibilities which will use a new backend microservice architecture to persist data.
Let's start with a few questions
- What problems in the organisation would a Monorepo solve?
- Will storing all the code in a single place rather than individual repositories give unnecessary constraints?
- Should frontend and backend code be in the same code repository?
- Is the organisation structure/hierarchy set up in such a way which could cause conflict on the approach for shared features?
- Do you need to share code and by whom will it be consumed?
- Should code be as close as possible to its consumer and should further abstractions be added when it’s the only option?
NB: I give some opinions based on what we did at the end
To help answer the questions, let’s consider a few things
Is a code repository the document that explains how applications work and should developers find a familiar and consistent pattern across projects within an organisation (and beyond)?
Are you using version control to help manage code (i hope so)?
Will a monorepo make it easier for your organisation to maintain
- Shared Features (eg auth, analytics, forms, utilities)
- Shared Services (Data access, HTTP, PubSub, client state)
- Branding and styling of User Interfaces (UI)
- Consistency for User Experiences (UX)
- Code Linting/Formatting
- External Packages/Dependencies and their versions
- Build times
- Repository metrics and reports
- Deployment config/coordination
- Deployments for different environments
- Prototypes and Spikes
- The responsibility of shared code
- Intellectual property
- Access for internal staff, outsources and contractors
- A codebase with many contributors
Let’s have a look at the available options for storing code
- Reference Repository
- Copy and Paste
Create a single repository to store all the code for all solutions. It might take a lot of work to create something bespoke so it makes sense to investigate tools and frameworks that would help manage applications and libraries within a single repo.
- Easier to maintain external packages/dependencies (complexity is added with more languages)
- Single store for code styles, formatting and linting across solutions
- Everyone knows what everyone is working on via the PR’s on the same repository
- Packages can also be released as NPM packages if required
- Tests can be run across all platforms when a change is made to a shared service/feature/package
- Yet another CLI
- Won’t solve external dependencies issue
- Overly complex for small projects
- IP for all projects in a single place
- Restricting access to apps/libs for certain teams/outsourcers
- Possible longer build times
- Repository size
- Organisation Structure
- Other opinion based reasons :)
Create a reference repo into which all shared features are added eg
- Shared Styles
- Shared Services
- Building apps (base build and deployment config)
Each new project forks the reference app and adds all the other packages required for the rest of the solution. Changes to the reference app can then be merged into the fork.
- Shared packages can be kept in sync across platforms
- Loads of code that might not be required in a fork
- Requires discipline to merge in the reference repo as often as it changes
- The fork can easily get out of sync with the reference app
- Do not know if a change in a shared package will break something in a fork until it is merged, which might mean it will never be merged
Create individual repositories for each solution and use private and/or public Packages to share code between platforms.
- Public packages are good for PR in the engineering community with supporting Articles and Blogs
- Clear responsibilities
- Time-consuming to maintain and developers will always take the path of least resistance
- Another layer of security is required (AuthTokens) when accessing Private packages
Copy and Paste
Copy and Paste similar functionality between projects
- Quick and dirty — easy to get quick results
I started writing the above a while back for work and then made it more generic for the article. I was going to publish it to medium but didn’t think it said anything new or exciting, but to report 4 months later, I hope the following will help someone make a decision on whether they should create a Monorepo.
We ended up using NX to create a Monorepo just for the frontend code and the backend microservices are in separate individual repositories. It is working well for us at the moment.
Our organisation is split into three cross-functional teams, and the frontend Monorepo contains React web applications to view and capture data and a chrome browser extension (all are being used in production already). More web apps are on the horizon as we move more features from the monolith.
We quickly found fortnightly meetings with the frontend engineers to discuss changes and the approach to new work provided a lot of value. We only build for what we know and only add abstractions and shared code when it is needed and not because it seems like something we should do.
We have created shared libraries for an HTTP Client, authentication, forms, styling patterns and features shared between the web apps and browser plugin. The shared libraries, which look like NPM packages when imported in TypeScript, enabled us to turn around a third application in good time as we re-used a lot of form, layout and deployment code.
The web apps use the NX React build config and the browser extension extends the default build config with custom webpack config. The CI/CD pipelines for each application watch specified directories and build/test/lint/deploy only when files in those directories have changed.
We have defined global settings for prettier and eslint config to maintain standards which can be overridden for each application/library if required (we’ve not had to do this).
We also recently updated the NPM packages in the repo using the NX Migrate command which took about 30 minutes (includes minor code updates for API changes).
Is a Monorepo a good idea? As always, it depends… We felt creating a Repository just for the frontend code would give us what we need due to the available tooling.
Some might now debate using the term Monorepo as the repository only contains a subsection of the organisations’ code, but it’s only a name and I would say organise your code in a way that makes sense for your organisation and understand the constraints with what whatever method you chose.
The organisation and engineers also needed to adapt to a new way of working and is providing value for us at the moment with good communication across the teams.
I’m sure the organisation for which I work would like the problems Google, Facebook and Microsoft are having with lots of code, but we’re are not that size. We are aware that some applications and code might not belong in the Monorepo and we have to remind ourselves of the responsibilities, considerations and problems we are trying to solve with having a lot of code in the same repository.
Nx: Extensible Dev Tools for Monorepos
Nx is a set of extensible dev tools for monorepos, which helps you develop like Google, Facebook, and Microsoft. It has…