Back to all posts

Streamlining Development Workflows: The Secret to Taming Multi-Repo Chaos

By Eli SchleiferOctober 30, 2023
Code Quality

How many code repos do you maintain at your company? 10? 50? 100? When each microservice, frontend, open source project, SDK, and custom tool ends up living in its own repo, the complexity skyrockets. There are benefits to this such as modularity and scalability, but as you scale, maintaining all of these repos in different languages and tools becomes an issue. You have to maintain code quality, security, code scanning, and code formatting, all in different languages, across dozens of repositories, all with different owners. This inconsistency can lead to internal and external issues.

Repo Gatekeeping

Every repo starts with good intentions. An individual or a team sees the need for compartmentalizing this particular piece of code away from the rest of the codebase. They choose the tooling and workflow for the code and build it into the repository. Over time these practices drift into siloed ecosystems - leading to “repo fiefdoms” where everything becomes subtly different. 

Two Python projects might use different versions, or one uses Black while another uses autopep8. Both tools format python code, but each produces subtly different output unless explicitly configured to be the same. In these situations, individual teams become gatekeepers, making it a challenge to maintain consistency in tool usage and development practices.This situation leads to escalating switching costs and tool rot.

Switching costs

Having inconsistent tooling adds tremendous friction to the engineering workflow. If an engineer is working on one repo today and then switches to another project, what happens if the tooling is inconsistent?

Let’s say one repository is using Python 2 and another Python 3. Now, the engineer has to manage their Python versions independently, with the massive headaches that come with that. Every time they move from one repo to another, they have to remember to use a different version. Since Python 2 is very different from Python 3, and has been deprecated for several years, this will cause even more pain down the road.

While major Python versions are significantly different, changes don’t have to be so dramatic to cause frustration. Even trivial discrepancies, such as different versions of GitHub CLI or ESLint, require additional setup time, affecting developer productivity and adding to the friction.

Finally, if you’re a new developer on the team and don’t have any of the tools required for the repo you must now spend several days setting up your linters and versions and security checks; all just to use the repo. Then, when you switch to another piece of code and have to go through setup all over again.

The hidden pitfalls of Tool rot

Tool rot occurs when you pin your code to an old version of a tool. When we studied tool rot across open-source projects last year, we found 82% of these projects suffered from tool rot. Repository owners might pin a version of a linter or runtime on day one and never think about it again. This does not mean the repo stagnates. It can still be used daily by dozens (thousands in the case of SDKs) of people. Even though the code itself is frequently updated and the repository remains active, the outdated tooling can pose long-term problems.

At first glance, using an older version of ESLint, like 8.49.0 instead of 8.50.0, might appear innocuous. However our study showed that the issue compounds over time. Alarmingly, we discovered that 31,000 repositories were using version 7 of ESLint (the current is 8.52). More worrying, we found almost 10k repositories that were using ESLint 4 or lower (last published in 2018) and therefore were susceptible to a ReDoS attack.

Out of date tools are a problem because of security. You’ve pinned your tools to a version that, further down the line, might be shown to have a vulnerability. If you have no system in place to highlight these vulnerabilities, the affected version will continue to be used for years, unknown to later users.

Ignoring tool updates doesn't just compromise security; it also degrades the quality of your code. ESLint, for instance, has seen significant improvements. Version 8 comes with support for top-level await, line comment directives, and eliminated outdated APIs to optimize package size. Running the latest version of ESLint will lead to higher quality code.

XKCD comic showing Likelihood you will get code working based on how you're supposed to install it.

Introducing a Unified Approach With Trunk

Instead of fiefdoms, you need provinces. You want every repo to be able to manage its own tooling, but with a base layer of rules and tools shared across the organization. This is what you get with Trunk Check.

Here’s how it works: As an organization, you can deploy a universal configuration that all the repositories can import.You can decide at a high level the best tools for your needs and share them with your entire team.  A plugin.yaml file in a plugins repo defines all the main tools that should be in use across all languages within the organization.  Each repo then imports this tooling list. While not every tool is applicable to each repo (given their technology stacks), every repository will benefit from a standardized, automatically updated core set of tools. This fixes both tool rot and drastically decreases switching costs between projects.

Each repo can then have a minimalist trunk.yaml that points to this centralized plugin repo, allowing you to sync tooling across an organization. Keeping everyone up to date with hermetic installs for each and every tool is as easy as syncing one tag. See Creating Organization Configs for more details.

Using Trunk Check almost erases switching costs because you only have to clone a repo and type trunk install. Any of the dependencies that you don’t have locally are added and you can get to work seamlessly. New developers can just do the same without hunting down and installing twenty new tools themselves. Do trunk install and it’s all set up automatically.

Consistent developer experiences, internally and externally

The need for consistency goes beyond your internal team. It also impacts your external developers and customers. Inconsistent code snippets of SDKs can lead to increased support requests and diminished trust in the quality and reliability of your products.

Such was the case faced by WorkOS. Their customers found malfunctioning code snippets in the SDK documentation. They had set up different repositories in different languages for each of these SDKs, but they didn't implement an internal tooling mechanism to enforce quality.

The developer team lacked the requisite knowledge in all the SDK languages to fix the problem on their own.

“We couldn't rely on our developers understanding enough of each language to actually help catch issues and understand what patterns are required to implement solid SDKs in each language. We needed linters to provide guardrails for the team.” 

- Vitor Capretz, a Software Engineer working on the DevEx Squad at WorkOS at the time

Realizing the scope of the challenge, they turned to Trunk for help. Within a few hours, they configured Trunk Check to manage linters, environment variables, and versioning for all SDKs. Now Trunk Check is an integral component of every SDK repo. The linters and tooling run on every update, and the snippets always work for customers.

A universal layer of quality and security

Defining tool lists isn’t about some top-down absolute decree. It is about building consistent quality across your organization for both internal and external developers. You want to give every developer who interacts with your code the best possible experience, which means giving them the best possible tools.

Maintaining and managing this tooling through Trunk also gives peace of mind around security. You can push updates when needed to every piece of code when needed and know your code is covered.

Conclusion

Managing multiple code repositories doesn't have to be a bottleneck for your organization. With Trunk Check, you can standardize tooling and eliminate the common pitfalls of tool rot, high switching costs, and inconsistent code quality. Take control of your repositories by unifying your DevTools today.

Ready to eliminate tool fragmentation? Start by trying out Trunk Check for your organization to help you scale and maintain code quality. Every developer in your organization and beyond gets a better developer experience, and you get a better product.

Share your experiences in our Slack community and let's build better products together!


Try it yourself or
request a demo

Get started for free

Try it yourself or
Request a Demo

Free for first 5 users