Software Metrics

Why Technical Debt is Not Our Fault. Or is it?

What is Technical Debt?

Technical debt reflects a painful reality – a trade off between the short-term benefit of rapid software delivery and long-term value. When a developer writes a new software feature, there are two options: the easy route, writing lousy, messy code just to get something working. And the harder route – investing in design, architecture and proper coding practices, and producing a high quality program. The delta in effort between these two routes is technical debt.

5 Reasons Technical Debt is Not Our Fault

There are many reasons for the accumulation of technical debt. What’s common to all of them is that whomever you ask will tell you: they’re not our fault. Let’s look at five common reasons and see who is really to blame, and what you can do about it.

Inheritance from Waterfall

Legacy systems are the classic source of technical debt. If you’re working on a 15-year-old system with millions of lines of code, built using waterfall practices, it’s obvious you’re suffering from technical debt.

Why it’s not our fault

The typical way of thinking about legacy systems is “if it ain’t broke, don’t fix it”. Developers are afraid to touch legacy code and, inadvertently, end up adding more and more legacy code that is very similar to the original.

Taking responsibility

Treating legacy systems as a holy cow that should not be touched, causes us to join the original culprit and continue accumulating technical debt.

Ask yourself – even if there is a huge quantity of technical debt, what is our direction? One week later, one month later, or one year later, will we have less technical debt, or more? If your direction is positive, you are chipping away at technical debt and improving your situation, you are taking responsibility for the problem, and, eventually, it will go away.

Missing Documentation

A common form of technical debt is missing documentation. We built a feature, it works, but nobody knows exactly how it works. Or it was documented in such a way that only the developers who worked on the feature really understand it.

Why it’s not our fault

Almost all developers inherit previous documentation, and few of them are pleased with their inheritance. If documentation was written by previous teams who worked in this project, or other teams who work on adjacent projects, it’s not our fault, right?

Taking responsibility

Over the lifecycle of a software project, most if not all features are touched, modified, improved, replaced or augmented. If you touch a feature, even if you didn’t substantially revise it, revisit the documentation at that point. You’re now familiar with the feature, you’ve seen the code, you understand what it does. Take the time to write proper documentation now – or no-one ever will.

Moving progressively through documentation and adding bits and pieces that relate to our current work on the project will, eventually, mitigate the problem. And it won’t require shutting down development for a massive docs rewriting project. Only a few minutes or hours (depending on the scope) here and there can go a long way.

The Definition of Done

A leading cause of technical debt is the Definition of Done (DoD) agreed in a team. Defining a DoD puts us between a rock and a hard place:

  • If we load many mandatory items into a Definition of Done, making it an endless checklist, people will inevitably ignore parts of the list to get things done.
  • If we define items as “recommended”, more often than not they will be pushed aside by sprint pressures.
  • If we keep to only a minimal list of critical items – for example, unit and acceptance testing – other considerations which may be much more important for the long term, such as design and architecture, may be ignored.

Why it’s not our fault

We didn’t define the Definition of Done, right? Or at least, we didn’t do it alone? It’s the entire team’s responsibility. And if the DoD is not realistic, how can we be expected to finish the sprint without adding technical debt?

Taking responsibility

Each and every team member can make conscientious decisions that affect work on the sprint and reduce technical debt. No DoD is perfect. But within a sprint, developers can make smart decisions – they can determine which items in the DoD can safely be ignored right now, even if they are mandatory. Or which items must be done now, even if they are only recommended, or do not appear in the DoD at all.

Taking on Too Much Work

Agile teams working in sprints often find themselves biting off more than they can chew. Either stories were underestimated, or management increases pressure to deliver, and the team ends up committing to more work than can actually be done during the sprint.

Because delivery is meant to be “predictable” and sprints are often shipped to end users, there is often no choice but to complete the sprint scope – even while cutting corners to get there. This very common behavior results, in the long term, in huge technical debt.

Why it’s not our fault

Taking on more work than we can handle is usually not a conscious or voluntary decision. It is caused by pressure from high-up to “increase velocity”, by scope creep which happens gradually within the release cycle, or by underestimating or misunderstanding what is required to develop specific features.

Taking responsibility

If you need someone for repairs in your home, a good plumber or electrician is one who can say no – if they can’t do the job on time, or can’t do it well, they won’t take it. And if they do take it, they’ll take full responsibility to get the job done well and on time.

It’s the same with dev teams – even with the complexity and unpredictability of software engineering, responsible teams have the courage to simply say “no” to unreasonable management demands, and conduct sprint planning carefully to investigate and validate story estimations. If you do this properly, you know that there will be occasional, unexpected overage, and can make a focused effort to resolve it, understanding it’s the exception and not the rule.

Poor Software Quality

An insidious form of technical debt is software that works, but is riddled with bugs. Some of these might be discovered in production shortly after launch, and others may lie dormant for months or even years, before surprising us with a catastrophic production fault.

Why it’s not our fault

With the growing complexity of software systems, it’s impossible to test everything. Whether you focus on comprehensive unit test coverage, integration tests between major components, UI test automation, or some combination, you are bound to miss some parts of the system or some junctions which are critical for functionality, stability or performance.

Taking responsibility

Quality is a tough one, because writing tests takes time, time we don’t have within the limited scope of a sprint. How can you use the precious time available to identify exactly the right tests that will prevent production problems and leave customers happy?

The answer lies in a new category of tools called Quality Intelligence Platforms, which can analyze test execution data, code changes in recent builds, and actual uses of features in production, and predict where disaster is likely to strike next.

Technical Debt Reduction with Quality Intelligence

Quality Intelligence can identify areas of quality risk in a software product. For example, it can identify parts of a product which have recently changed, are used frequently in production and are not been tested, and alert development teams to add tests in those areas.

Conversely, Quality Intelligence can can help discover areas which are adequately tested, have not recently changed or are not actively used in production, and so an investment in testing is just not needed.

SeaLights is a leading Quality Intelligence Platform that analyzes data from tests, builds and from your production deployment, and provides a clear visualization of quality risks. Get a live demo to see how SeaLights can help you focus testing efforts and reduce technical debt.