Paying Technical Debt

by Dave Sweeton

The concept of "technical debt" has become a popular metaphor in software development in recent years. The idea boils down to the fact that the quality or maintainability of a codebase decreases over time, and you need to spend time refactoring or updating to keep the "debt" at a manageable level.

The "debt" part of the metaphor came about because it can be entirely reasonable to write low quality code (take out a loan) to accomplish short term goals. You then need to refactor (pay down the debt) at a later time. This happens often in software development processes that have sprints or milestones with fixed schedules and fixed deliverables. In order to complete the sprint, you do whatever needs to be done, then at the beginning of the next sprint you schedule time for refactoring.

Technical debt is not always a conscious choice however. Low quality code (e.g. buggy, hard to maintain, hard to read) will likely increase project costs in the future. You might think that a project with only AAA Gold Rated Super Star developers won't ever have technical debt (other than consciously chosen short term debt), but that's actually not the case. There are two other sources of debt which are for the most part inevitable—bit rot and a growing codebase.

Bit rot is actually caused by inaction. A codebase can "age" and become lower quality, even when it hasn't changed at all. This is caused because the environment where the program operates has changed. What were once completely correct technical decisions are now dated legacy issues. Some examples from my own work experience:

  • A desktop application written in the DOS age still works fine, but is no longer an acceptable solution in the current Web/mobile environment.
  • Technology that is so dated it's hard to find people that know it and are willing to support it. COBOL is the usual example here. Those COBOL programs don't stop working, but they aren't good solutions anymore for purely external reasons. You can add a long list of technologies here; from MFC to VB6, COM and even ASP.Net WebForms (which appears headed that way). Okay, that list was all Microsoft (colored by my experience!), but it applies to almost any technology.
  • Framework or library versions can also become issues. I have projects written on ASP.Net MVC version 3, while the current version is 5. Version 3 still works, and we have no practical reason to upgrade, but not upgrading increases maintenance costs because it's not as simple for new developers to get or install older versions.
  • Websites written without AJAX still function adequately but may not have the user experience or performance characteristics that users have come to expect.

The other cause of technical debt is simple growth of the project. In any long (multi-year) project, you inevitably end up with some code that is a far cry from ideal. This can happen as requirements change. If you build features A, B and C months (or years) apart, you may end up with different code (and less reuse) then if you had built them all at the same time with the same mindset.

If debt is inevitable, how should you deal with it? If you are aware of the debt, then postponing dealing with it could be a viable strategy. We had one project that was developed more than 10 years ago on ASP.Net 1.0 Web Forms with no AJAX (because it didn't exist) and an obsolete data access technology (which was state of the art at the time). The project was finished and needed no further development. The application was just moved to a new server every 3-5 years. Then Windows Server 20 came along and the .Net Framework 1.0 was no longer supported. So we undertook a 10 hour project to update the framework (targeted the latest framework and fixed some obsolescence issues) and test against a newer version of the database engine. Ignoring the debt was the absolute right strategy here because the project wasn't under active development.

On the flip side, I have another Web application project of similar vintage that is under constant development. On that one we have a curious case of ancient code (from .Net 1.0) in the same codebase as state of the art. It's got a mix of WebForms and MVC, new and old database access, AJAX with client side frameworks and event driven full page post backs. Here the technical debt is known, and we have varying strategies for dealing with it. On the one side is pure pragmatism. I strongly believe that there is no difference between low quality code that works and perfect quality code that works, until you touch it. So for the dusty corners of the application where requirements don't change and nothing breaks, we leave it alone. For new development we incorporate new technologies and techniques as they make sense, acknowledging that each new "thing" must fully justify the added complexity it brings to the project. When we are required to touch old code, I tend to make a short refactoring and cleanup pass before I add new features.

On other projects under development the best strategy is simply to refactor continuously. Do small cleanups all the time, and make sure to schedule time for bigger refactoring periodically as needed.
© Copyright 1995-2022 - STOUT SYSTEMS DEVELOPMENT INC. - All Rights Reserved
envelopephone-handsetlaptop linkedin facebook pinterest youtube rss twitter instagram facebook-blank rss-blank linkedin-blank pinterest youtube twitter instagram