Technical Debt

Technical debt is both pervasive and disruptive to the discipline of software engineering. No software Aside from ephemeral software that is discarded after use. is free from technical debt. Despite this, it’s hard for organizations to make productive, impactful changes to the processes and practices that cause technical debt to arise.

It is tempting—and common—to draw parallels between technical debt and financial debt. You can try to apply lessons from Financial Peace University to your code base and technical systems but I think it is more useful to think about of technical debt in terms of its impact on marginal cost.

One of core responsibilities of software engineers is to control the marginal cost Marginal cost, by definition, is the change in the total cost when the quantity produced is increased. The marginal costs of software increase in a nonlinear fashion as the complexity of the system increases i.e. it is much easier to change a simpler thing than a complicated thing. The biggest cost centers are engineering time, cloud computing resources, and licensing fees. of:

  • Extending a system with new functionality
  • Scaling a system for broader use

This helps keep the cost of change low over time. Keeping marginal costs low was one of the claimed benefits of Extreme Programming (XP); a set of practices that predated Agile. There are good ideas in XP but the methodology has fallen out of favor over time. Agile software development should have similar outcomes but often doesn’t. Marginal costs are influenced by:

  • Architecture decisions
  • Process design
  • Implementation choices

Thus “paying down” technical debt involves remediating one of these aspects of the software development life cycle (SDLC). This isn’t a simple problem space but it is prevalent enough that patterns have emerged. That’s why accumulation of technical debt is one of the Bottlenecks of Scaleups.

The only effective way to manage these marginal costs is to periodically and rigorously simplify standing systems through methods like introducing new layers of abstraction, breaking services into smaller component pieces, and depreciating anything you can get away with.