Mistakes engineers make in large established codebases
Engineers swapping war stories from million‑line, decade‑old systems largely agree that consistency in patterns and behavior is crucial for safely changing legacy code, even when the “standard way” is imperfect. Many warn that ad‑hoc rewrites, one‑off “clean corners,” and fragmented new patterns tend to increase cognitive load and breakages, arguing instead for incremental, organization‑wide refactors backed by tests, tooling, and shared standards. Others push back that rigid adherence to existing patterns can ossify a codebase and culture, urging a balance between preserving predictable behavior and introducing better abstractions, especially when business pressures, politics, and weak test coverage are in play.
Consistency vs Evolution
- Many strongly agree that inconsistency is the main pain in large codebases: “When in Rome” / “be a chameleon” makes code predictable and reduces mental overhead.
- Counterpoint: rigid consistency norms can freeze bad patterns, block improvements, and turn “consistency” into the tie‑breaker that keeps the status quo forever.
- Several suggest: only introduce a new pattern if you commit to rolling it out systematically (or rolling it back), with a concrete migration plan and buy‑in.
Working in Bad or Inconsistent Codebases
- Some engineers focus first on making even “bad” codebases internally consistent, reporting big reliability gains.
- Others ask how to handle codebases that are consistently bad or already fragmented; advice includes:
- Stay locally consistent in touched areas.
- Isolate new “better” code in well‑documented, reusable modules.
- Get agreement on “best of the existing” patterns rather than inventing a sixth way.
Refactoring vs Rewriting
- Strong skepticism toward full rewrites, especially by new teams unfamiliar with the monolith; several anecdotes of multi‑year failed migrations (auth, permissions, monolith→microservices).
- Successful stories emphasize:
- Deep prior fluency in the old system.
- Strangler‑fig or parallel‑implementation approaches.
- Delivering production value early and incrementally.
Testing Strategies in Large Systems
- Heavy emphasis on tests to de‑risk refactors: unit tests plus integration/end‑to‑end tests.
- Debate over DB‑hitting “unit” tests:
- Some insist on real databases for fidelity.
- Others prefer mockable interfaces to enable fast, thorough unit tests of logic and failure modes.
- Consensus: integration tests are crucial in large, stateful, cross‑cutting systems.
Tooling, Style, and Automation
- Automatic formatting and linters (e.g., Go‑style, .NET/clang tools) are praised for eliminating style debates but seen as orthogonal to deeper behavioral consistency issues.
- Massive mechanical refactors can be enabled by consistent patterns plus code‑mod tooling.
Org Culture, Politics, and Incentives
- Many note that real blockers are organizational: risk‑averse management, “sticky” seniors guarding old patterns, PRs rejected for “inconsistency,” and lack of time for refactoring.
- Some argue that “glue work” and cleanup are undervalued; others caution against random “boyscout” changes that derail feature work without clear benefit.