Reproducible Environments
Last updated:
Reproducibility is the point
The same code with different dependency versions is different software. Without pinning, a deployment six months later installs different packages and behaves differently.
“It works on my machine” is nearly always a dependency problem, and a lock file eliminates the whole category.
What good practice looks like
- Isolated environments per project, always
- A lock file with exact versions of everything, including transitive dependencies
- Committed to version control, so builds are reproducible
- Vulnerability auditing on every build
- Scheduled updates, with tests
Update regularly or pay later
Dependencies left for two years cannot be updated individually, because everything has moved several major versions and they depend on each other.
- Security updates within days
- Minor updates monthly, with tests
- Major updates deliberately, one at a time
- Never all at once after a long gap
Python version too
Python releases have defined support periods. Running an unsupported version means no security fixes and increasing incompatibility with current libraries.
Plan the upgrade before support ends rather than after, when it becomes urgent and everything else has moved on too.
Be selective about what you add
| Before adding a package | Ask |
|---|---|
| Is it maintained? | Recent releases, responsive issues |
| How many dependencies does it bring? | Each is more surface |
| Could we write this? | Sometimes twenty lines is better |
| What is the licence? | Occasionally matters commercially |
| Is it widely used? | Abandonment risk |
Frequently asked questions
Which tool should we use?
Should the lock file be committed?
How often should we update?
What about containers?
Dependencies untouched for two years?
That is the point at which updates become a project. Worth addressing before it gets worse.
Related services
What we build for problems like this one