P-2.5 Dependencies and Reproducible Environments
Standard package-management practice — written September 2026
What this is and why it exists
"It works on my machine" is not a joke about carelessness. It is what happens when the set of installed libraries is part of the program and nobody wrote it down.
This topic is about writing it down. Manifests, lock files, isolated environments, version ranges.
One idea takes longest to land, and it is the one that eventually bites. A version range is a *promise* about compatibility, made by a library author who might break it.
The vocabulary
- Package manager — the tool that installs libraries and records what was installed.
- Manifest — the file recording what your project asked for.
- Lock file — the file recording exactly what it got, down to the version.
- Isolated environment — one project's libraries kept separate from another's.
- Version range — an acceptable set of versions rather than one exact version.
- Transitive dependency — a library your library depends on.
- Reproducible — installs the same way on a machine that has never seen it.
The mental model
Two files do the work, and the difference between them matters. The manifest records what you asked for, often as a range. The lock file records exactly what you got, pinned. Committing the lock file is what makes an install reproducible, because it removes the resolution step that could otherwise produce something different tomorrow.
Then isolation. Two projects on one machine will eventually need different versions of the same library. Install everything globally and one of them breaks — not maybe, eventually. Every language has settled on the same answer: give each project its own set. Do it from the first day of a project, not after the first collision.
Version numbers are the next piece, and they are a communication mechanism. A number says something about compatibility, so accepting a range means trusting authors to keep that promise. They usually do. They occasionally do not, sometimes by accident. The lock file exists precisely for the occasions when they do not, which is why it is committed rather than ignored.
Now the judgement this topic really wants you to have. Every library you add is code you did not write, must keep updated, and are exposed to. That exposure is real when it has a defect or a security problem. That can be an excellent trade. For genuinely small problems it often is not, and the honest comparison is against twenty lines of your own that you would understand completely. Nobody makes this comparison often enough.
End by testing all of it. Clone the repository somewhere fresh, follow only what is written down, and see whether it runs. Whatever you had to remember rather than read is the documentation that is missing, and you have found it the cheap way.
What you should now be able to explain or do
Add a library, and say what the manifest and the lock file each recorded. Explain why the lock file is committed. Set up an isolated environment per project and say what it prevents. Say what a version range is trusting, and what happens when that trust is misplaced. Weigh a small dependency against writing it yourself. Reproduce your project on a clean machine and find the missing documentation.
Check yourself
What is the difference between a manifest and a lock file?
The manifest records what you asked for, often a range. The lock file records exactly what you got. The second is what makes installs reproducible.
Why give each project its own libraries?
Because two projects will eventually need different versions of the same one, and a shared global set means one of them breaks.
What is a version range actually trusting?
That the author's version number honestly describes compatibility. Usually true, occasionally not, which is why the lock file is committed.
What does adding a dependency cost?
Code you did not write, must keep updated, and are exposed to. Often worth it, and for small problems often not.
What does a clean-machine rebuild tell you?
Which steps live only in your head. Anything you had to remember rather than read is documentation that is missing.
Go deeper
Back to Dependencies and Reproducible Environments: work through the checklist