Software libraries provide ready-to-use functionality that you can import into your software projects with ease. With today's package managers it's easier than ever to reuse code. However, as the number of dependencies grows in a project, there is an increasing amount of risk related to the dependencies. The more dependencies you have, the more your project depends on other people - their capability and will of keeping the dependency stable and secure to use.
Let's do a thought experiment. Say you have a project that has 100 dependencies. You are 99% confident that each dependency is safe and stable to use. At a glance it seems that your project should be reasonable stable with this assumption.
But, not so fast. Let's do the math on this. For the sake of the argument, and to make things easy to calculate, our assumption is:
• each dependency is independent from the other dependencies
• each dependency is stable with a probability of 0.99
Now, the probability that all 100 dependencies are safe and stable is 0.99^100 = 0.37, or 37%. In other words, there is a (100% - 37%) = 63% chance you have a problem with your dependencies. That's a high risk. It's more likely than not that there will be a problem.
Of course, life is not this simple. Dependencies are interconnected, the benefits of dependencies might outweigh the risks, the number of dependencies vary, the reliability of your individual dependencies might be well over 99%, the supposed issues I'm concerned about might have very minor affect on your project, you have tests that will catch any critical issues with your dependencies, etc.
I'm not saying we shouldn't use dependencies.
Russ Cox wrote recently an interesting piece about the problem with software dependency management, where he proposes some ways of mitigating risks with dependencies:
• Inspect the dependency
• Test the dependency
• Abstract the dependency
• Isolate the dependency
• Avoid the dependency
• Upgrade the dependency
• Watch your dependencies
As you probably noted, I've gravitated towards the less is more side of the dependency-use-spectrum. This is probably a side-effect of having worked on a long-lived product line (almost 19 years since I first touched the code base, still working on the Nth generation of the same product). In a long-lived product you want to consider carefully which dependencies you want to be updating or refactoring out in the coming years. Through the years I've been through a few cases of purchasing a new version of the dependency to match the IDE upgrade, refactoring out the dependencies, or switching one dependency to another, or cutting out some (non-critical) functionality due to lack of upgrade compatibility in some dependency.
In the later years I've also gotten the chance to enjoy today's abundance of open source libraries, and play catch-me-if-you-can with library updates, fixing issues that broke when we updated the libraries. In some cases our code has been silently broken until an update exposed the broken code, in some cases the dependency update required updating our code to match a new version. Anyway, this reminds me that, while I value the sheer number of software libraries available today, and also use quite a few of them, I'm still at the less is more end of the spectrum.
Dependencies are usually a good thing when they solve a big problem for you. For solving small problems, I'd like to quote Rob Pike's Go proverbs: