Software
Modern software is assembled out of other people's software
A small program can pull in hundreds of components written by strangers, and the resolution rules that choose their versions are where the surprises live.

This works through software dependencies in the order the parts actually depend on each other.
The short version
- Most installed code arrives indirectly through dependencies of dependencies.
- A lock file records exactly what was resolved so builds repeat identically.
- Compromising a widely used component reaches everything that includes it.
Nobody writes all of it
Building even a modest application from scratch would mean writing date handling, compression, cryptography and network protocols again. Instead developers declare which existing components they need, and a tool downloads them and makes them available. Each of those components declares its own requirements, which are fetched too, and the process continues downward.
The result is a tree where the majority of installed code was never chosen by anyone on the project directly. That indirect code is the same as any other code once it runs, with the same access and the same consequences.
Version ranges and the resolution problem
Components usually declare a range of acceptable versions rather than one exact version, so improvements arrive automatically. When two parts of a tree require overlapping ranges, the tool must find a set of versions that satisfies everyone.
In the datasheet, some ecosystems allow several versions of the same component to coexist, and others force a single choice for the whole tree. Forcing one choice keeps things small and creates conflicts that cannot be resolved except by waiting for someone to update. Allowing duplicates avoids the conflict and produces applications carrying several copies of the same library.
Lock files pin the answer down
Because ranges change meaning as new versions appear, the same declaration can resolve differently on different days. A lock file records the exact versions chosen, so every later build reproduces the same tree until it is deliberately updated.
The short version: without one, a build that worked yesterday can fail today for reasons nobody on the project changed. Lock files also record checksums, so a component whose contents changed under the same version number is rejected. Updating deliberately then becomes a visible, reviewable event rather than something that happens silently in the background.
The supply chain is the attack surface
Compromising one widely used component reaches every application that includes it, directly or several levels down. Attacks have included publishing packages with names close to popular ones and taking over accounts of inactive maintainers.
Because build tools often execute code from packages during installation, a malicious package can act before anything is run. Defences include pinning versions, reviewing what changes when updating, and restricting what the build environment can reach.
None of this is exotic security work; it is ordinary hygiene that many projects skip because the tooling makes skipping easy.
Abandonment is the quieter risk
Many components are maintained by one person without payment, and interest fades long before the software stops being used. An abandoned component keeps working until something around it changes, at which point nobody is available to adapt it.
Under load, security flaws found in abandoned code may never be fixed, leaving dependents to patch it themselves or replace it. The number of dependents gives no indication of maintenance effort, so popularity is a poor proxy for reliability. Projects that periodically audit their tree for unmaintained components find the problem long before it becomes urgent.
Why this shows up in what you install
Applications carry their dependencies with them on many platforms, which is why simple programs occupy surprising amounts of storage. Bundling avoids conflicts between applications and means a flaw in a shared component must be fixed separately in each one.
At the protocol level, frequent small updates often reflect dependency updates rather than any change to the application's own functionality. Systems that share libraries centrally patch once for everything, at the cost of applications breaking when a shared version moves. Neither approach is wrong, and the choice determines whether updating is a system responsibility or an application one.
The takeaway
You are not choosing a library; you are choosing everything that library chose.
Once you know what it is trading away, the design stops looking arbitrary.
Questions readers ask
Why is a simple app so large?
It probably bundles its own copies of every library it uses, including runtime components, so it does not depend on what the system provides.
Does more dependencies mean less secure?
It means more code you did not review and more maintainers you are trusting. Whether that is a problem depends on which ones.
Also by Junko Ishida
- USB-C solved the connector and not the confusionPower & Batteries
- File formats decide whether your files outlive the softwareSoftware
- Where the electricity goes when everything is switched offPower & Batteries
- The memory effect was real, and it has nothing to do with your phonePower & Batteries





