Long Term Software Development

Long-lived software, from industrial control systems to web apps, demands conservative choices in tooling, dependencies and architecture to remain maintainable over decades. Commenters argue for boring, simple code, minimal third‑party libraries, aggressive but controlled toolchain upgrades, and strong documentation and testing, contrasting this with fragile stacks plagued by “dependency hell” and rapid churn. The thread highlights trade‑offs between rolling your own components versus relying on widely used libraries, the risk and cost of deep dependency trees, and how practices differ between safety‑critical systems and typical commercial software.

Software evolution & long-term view

  • Several commenters point to Lehman’s Laws and related research on software evolution as empirical backing for the article’s themes.
  • Others recommend books on legacy systems and empirical software engineering, reinforcing that long-lived systems are common (banking, aerospace, elections, archiving).

Dependencies, versioning, and “DLL hell”

  • Many see deep, fast‑moving dependency trees as the main enemy of longevity, citing Python, Node, and ML stacks as fragile and short‑lived.
  • The historical “DLL Hell” on Windows is used as analogy; some argue it’s largely solved now via versioned assemblies and app‑local DLLs, while others note it was “solved” mostly by bundling private copies.
  • Rust’s model (multiple versions of a crate in one binary, name‑mangled) is praised for safety but criticized as encouraging sprawling, slow‑compiling dependency graphs.
  • Reproducible builds are proposed as a counter to dependency drift, but others point out they do not solve security updates or abandoned libraries.

Third‑party libraries vs in‑house code

  • A strong contingent argues for minimizing third‑party deps, especially in performance‑critical C/C++ systems or long‑lived infrastructure, citing:
    • Poor performance and scalability of many OSS libs.
    • Harder observability and debugging across many libraries.
    • Supply‑chain and maintenance risk, especially when tooling must be aggressively updated.
  • Counter‑arguments stress that some domains (auth, crypto, image parsing, ML libraries) are too hard or risky to re‑implement, and that popular, well‑scrutinized libs are safer than bespoke code.
  • There’s nuanced middle ground: use a few “platform‑level” mature deps, vendor or replace narrow ones, and accept interim libs as stopgaps.

Simplicity, documentation, and style

  • Many reinforce “write boring, simple, obvious code” and avoid premature optimization or over‑architected layers.
  • Some warn not to conflate “simple” with “easy”; a good architecture can be “clever” in service of making application code simple.
  • Documentation is widely seen as crucial for longevity; disagreement focuses on avoiding meaningless boilerplate vs providing high‑level intent and system context.
  • Style uniformity is de‑emphasized; learning to work with mixed styles is considered more valuable than rigid enforcement.

Critical systems vs typical web/apps

  • Commenters note a gap between practices for life‑critical / industrial systems (assertions, no dynamic allocation, highly conservative change) and the more pragmatic mitigation‑oriented advice suitable for typical web and business software.