The Cost of Technical Debt
As a perfectionist in my first month in school for software development, I was naturally drawn to discussions of code smells and refactoring. Some may argue that the time I spend making sure my code follows the rules is a waste (when uglier code could run perfectly fine). But there’s evidence that making the investment in writing quality code saves developers time and businesses money in the long run.
Maintainability can be quantified in three major ways:
- Extensibility — how hard is it to add features?
- Stability — how hard is it to make changes?
- Understandability — how hard is it for someone else to pick up your code?
When maintenance in an app is deferred, “technical debt” inevitably builds up. In the beginning, new features can be rolled out quickly when using sloppy practices. However, as the codebase gets more complicated, adding features becomes more and more difficult. Eventually, it will take less time per feature if each one is done carefully and thoughtfully.
Like financial debt, technical debt builds interest exponentially. Notice on the graph above that the green “solidly done” line quickly diverges from the red “weakly done” line over time. In other words, the longer problems are ignored, the more they build on each other.
In one worst-case scenario for technical debt (which a friend of mine is going through now at his workplace), a company refuses to invest the developer time to update a technology that’s key to their stack, despite the fact that the technology will soon be unsupported. Now that their app has been dug into a hole and is stuck with outdated technology, it’s very hard to get out. That compounds with the fact that the best developers can see the train wreck coming. They’re being asked to work extra hours and train new people, and many of them will soon leave.
“If you can get today’s work done today, but you do it in such a way that you can’t possibly get tomorrow’s work done tomorrow, then you lose.”
– Martin Fowler, Refactoring: Improving the Design of Existing Code
Technical debt may be caused by a number of factors, including
- Business focus on release date over quality
- Lack of planning & documentation
- Not writing (and/or not automating) tests
- Lack of collaboration & mentoring of junior devs
- Delayed refactoring
- Outdated technology
- Poorly defined requirements
Technical debt inevitably leads to
- Inflexible code — hard to change or add features to
- Missed deadlines — when trying to accomplish one task, old problems that were swept under the carpet may resurface
- Increased software support costs and lost customers (due to bugs & outages)
- Possible costly legal battles (HIPAA noncompliance, security breaches, unsafe airplanes, failure to satisfy SLAs — reliability guarantees)
- Outdated technology is difficult to maintain. The best developers want to learn the most relevant technologies of the day, and you pay a high price for a specialist who knows an old language.
- Difficulty on-boarding new developers, and dependence on employees who become specialists in dealing with the codebase’s intricacies
- Low morale & engagement — when adding new features becomes a slog instead of an exciting venture. People are not motivated to provide quality work on top of a heap of garbage.
So what can you do about it as a lowly developer, when management is constantly pushing for the next deadline?
- Avoid code smells as you go, and practice regular refactoring. Don’t Repeat Yourself (DRY), use clear & consistent variable & method names, practice Test Driven Development (TDD), follow the Single Responsibility Principle (SRP), avoid long/complex methods, and maintain thin interfaces / don’t hard-code.
- Conduct code reviews. Several studies showed 80–90% reductions in errors when code reviews were introduced! Don’t consider a feature done until it satisfies the functionality, a code review is done, there is fully automated test coverage, and the documentation is up-to-date.
- Use automated testing. Thorough testing makes it easy to isolate where a problem is coming from and reduces the need for manual QA (which is slow & expensive).
- Focus on the issues that are most prevalent/racking up the most technical debt first. Add these to the list of user stories for a sprint so that they get tackled in the normal pipeline instead of as a nagging afterthought. Keep a backlog of hacks to undo later (and do so).
- When you’re looking for your next opportunity, consider the Joel Test when evaluating potential employers:
- Do you use source control?
- Can you make a build in one step?
- Do you make daily builds?
- Do you have a bug database?
- Do you fix bugs before writing new code?
- Do you have an up-to-date schedule?
- Do you have a spec?
- Do programmers have quiet working conditions?
- Do you use the best tools money can buy?
- Do you have testers?
- Do new candidates write code during their interview?
- Do you do hallway usability testing?
But why should you even care? Code can last shorter than you’d hope, but often longer than you’d expect. The code you write as an intern may stick around and be built upon for years. Almost all the code you write is linked to you through version control, and people know who to blame when a bug is introduced. Coworkers talk, and they disperse to other companies. Not to mention recruiters and hiring managers can check out your style on GitHub at any time. So start Marie Kondo’ing your code today, and you can attract the companies that will keep their employees & customers happy for more than just a few months.
For more information, see the articles below: