Choosing dependencies

Decision

The decision, which dependencies to add to the codebase, is left to each team owning that code.

To decide, the following checklist is recommended. Only if all checks are confirmed, the dependency should be added. The checklist should be added to the PR which introduces the dependency.

- [ ] Would implementing the functionality ourselves without help of the dependency take us more than one day?
- [ ] Is the dependency used by enough people to build trust into its functionality (typically >10,000 monthly downloads on npm)?
- [ ] Is the dependency licensed under MIT license or another [permissive license](https://en.wikipedia.org/wiki/Permissive_software_license)?
- [ ] Has the dependency either recently been updated (during the last 6 months), or do we expect no update needs due to stability (e.g. a library with helper functions that already covers most use cases)?
- [ ] Is the dependency either open source or maintained by a company we have a support contract with?
- [ ] Would the team feel comfortable making changes in the dependency's code, e.g. is the code understandable?

Problems

When writing code, we are often tasked with either building something ourselves, or importing a dependency that already does what we need.

Writing code ourselves takes time, both for writing the code, as well as for maintaining it. We might underestimate the effort needed to build something, as we don't have much experience in the specific domain (e.g. when writing a library to create XML, we might not know the XML standard as well as someone who wrote a library focused solely on this).

At the same time, adding dependencies is not without drawbacks either: There are security risks, as dependencies (and their dependencies and so on) are maintained and hosted externally. There might be features missing, and adding those to an external dependency is much harder than adding them to an internal one.

Teams need to be able to decide when to rely on external dependencies, and how to decide which ones to use.

Context

Since our code is written exclusively in JavaScript, libraries are typically hosted on npm.

Options

  • Centrally approve dependencies
  • Provide guidelines for which dependencies to use
  • Leave dependency decisions up to each team

Reasoning

Why leave the decision up to each team

Based on our values, we trust teams to take ownership of their area, which includes security concerns.

Even with central decisions on dependencies, we would most likely not catch significantly more problems, as the JavaScript ecosystem strongly depends on dependencies, so a dependency of a dependency might be vulnerable.

If we were to either check every dependency in detail (including all of their dependencies, the dependencies of their dependencies and so on), or not rely on dependencies at all and instead wiret all of the code ourselves, we would be slowed down significantly. The risk of not being able to maintain and improve our software is higher than the risk of a supply chain attack.

Why have the specific guidelines we have

Would implementing the functionality ourselves without help of the dependency take us more than one day?

Very simple dependencies like one-liners are easier to maintain inside our own codebase, and the process to verify and maintain an external dependency becomes bigger than just writing the code ourselves.

If we estimate dependencies to take longer than a day to build, it is likely that it will take even longer, in addition to the added complexity for maintenance.

Is the dependency used by enough people to build trust into its functionality (typically >10,000 monthly downloads on npm)?

Monthly downloads is one potential proxy for how often a dependency is used by others. If it is used enough, this indicates less bugs due to more testers. The line at 10,000 monthly downloads is arbitrary and based on experience with libraries that had a couple thousand downloads and were immature.

Is the dependency licensed under MIT license or another permissive license?

We are not allowed to use code without a license, and other licenses like copyleft licenses, e.g. GPL, might force us to make all of our proprietary code available under a copyleft license as well, which we don't want.

Has the dependency either recently been updated (during the last 6 months), or do we expect no update needs due to stability (e.g. a library with helper functions that already covers most use cases)?

When taking on a dependency, we are in some cases left to rely on the maintainer to do updates, e.g. a library that uses React, but does not update with React, might stop us from being able to update React ourselves. The line at 6 months is arbitrary and based on personal experience.

In some cases, libraries have not been updated recently just because they do not rely on dependencies themselves and are feature-complete. These will usually have had a lot of updates before.

Is the dependency either open source or maintained by a company we have a support contract with?

This should almost never be a problem as almost every single dependency we could take from npm nowadays is open-source on GitHub. Some may not be, and this makes it really hard to maintain them in case we need to take over maintenance.

The only exception are libraries maintained by companies we have a support contract with, e.g. if we use a tool and use an SDK published by that company. But even in these cases, the code usually will be available on GitHub.

Would the team feel comfortable making changes in the dependency's code, e.g. is the code understandable?

If a dependency is no longer maintained, or we need to fix a security bug on short notice, we can't rely on the maintainer to take care. Worst case, we will have to either fork the library and maintain our own version, or to rip out the implementation and replace it with our own. Therefore, the code needs to be in a state where we feel comfortable to jump in and maintain it ourselves.

Consequences

Not having an extensive central review for each dependency leaves us open to some software supply chain attacks. At a later point, we should check for automatic tools to prevent supply chain attacks which support teams in this decision.

It also speeds up our development.

Related