Perfect software may be built at universities, but the business reality is different. B2B software development depends on deadlines. Due to the market reality, applications are released at a fast pace and need further improvements.
To ship a product faster, development teams take various shortcuts. The resulting technical debt is hard to get rid of from the dev cycle, but can and should be controlled.
What is technical debt? The definition
According to definition coined by renowned programmer Ward Cunningham, technical debt is a code which is not quite right, written to ship a software product faster.
This may be caused by either a need for a prototype, or to catch a narrow shopping window. Of course there are thousands of reasons, but this is not a place to list them all.
Whenever diagnosed, technical debt (or code debt) needs to be managed. Follow us to learn about some real-life examples of its occurrence at Prograils.
Overwriting of requirements
We build software based on project specs. The more detailed one, the better. However, during executing, testing or user-testing, a program often turns out to have been missing some edge cases.
In such situations, we rarely rebuild those functionalities from scratch. More often we modify them to take these cases into account.
To make it clear - this happens all the time. And the larger the project, the greater the chance of affecting several functionalities - by accident or not.
This is the first signal that you should start paying your technical debt. This situation is pretty common, as no project specification is ideal and exhausts the list of possible scenarios.
The product owner and dev team should take a few steps back, gather all knowledge and clean out the code to make it more up-to-date, readable and faster.
In an ideal world, the project’s budget is high enough and the client ready to spend its part on refactoring. The code debt is, then, under constant control and it doesn’t hurt to pay it. But it’s not always the case.
The most common origin of technical debt is when things are rushed, with lots of last-minute refinements. It’s incredible how much you can achieve by only doing something that is “good enough”. The product meets, say, 80% of requirements, and the client is fine with that.
At the request of a client under pressure from investors, we once prepared a proof-of-concept in a few days. It worked and they bought it.
But that’s only a part of the story. We only deployed that functionality because no one cared if it had been done correctly. Once it was released, every change in the original concept required more time than usually.
The fewer users an application has, the easier it is to develop it, and the less profound the consequences of its “good enough” modifications. If the user count is soaring and you feel the urge of making fast changes, think twice.
Technical debt in mature projects
A fast feedback loop is a great advantage of the “good enough” approach.
But it comes with a drawback: code changes, often made after hours (as it’s difficult to exit the flow seeing quick gains), are rarely well-planned. It is especially visible in mature projects.
The drawbacks will surface sooner or later in your application. Functionality A, designed in haste, will let you know about itself while you work on functionality F. The refactoring work, done the same way, is unlikely to eliminate the flaws for good.
If this process is repeated, it brings frustration to all parties involved: software developers, project managers, the client, and end users. Those mentioned at the end will be the first to experience the app’s shortcomings.
Code debt and information security threats
Large-scale, mature applications would suffer first from ad hoc changes in codebase.
This sort of code debt could even expose a worldwide system like Physitrack to security threats. Disclosure or loss of user data could be the most extreme ones.
As an ISO 27001 certified software development company, we want to prevent such leaks.
If a project makes profit, we encourage our clients to spend a part of annual funds for making a few steps back and cleaning out the codebase. Summer holidays are a good period for that, though are not always enough.
Code debt and knowledge transfer
The worst case of technical debt? The one in which a client is aware of its existence, but deliberately refuses to pay it.
This is the ‘red flag’ situation we have been through several times. Everything is perfect as long as software is built at a fast pace. Each time we remind our partners of the need of refactoring, tensions rise. The refactoring-related tasks are stuck in the product backlog for months until the amount of debt reaches its critical mass.
A business relationship ends, but this is only the beginning of serious issues. Code and knowledge transfer to a new team can be a real pain in the neck when software is not tested or tested only to a certain extent, and the need for refactoring neglected. Sometimes it is even impossible to properly transfer knowledge and how-tos.
Again, ad-hoc changes in the codebase are rarely well-planned and often ill-documented. The developers who have been building the system up until now knew all the shortcuts taken en route. The new dev team often faces issues interpreting and developing the code further.
We were on both ends of the above situation and we wish no one to step into our shoes.
Managing technical debt
Tech debt can appear in your software project very early, but become visible only after some time. There are at least a couple of ways and practices to handle it.
Test, test, test
The deployed code should be thoroughly tested. Clients insist on ad hoc modifications, but there is no excuse for half-baked functionalities to be released. A code that in some part passes the tests, while failing in the other, is problematic when the project is being taken over by a new team. Code transfer without passing on the domain-specific knowledge? Nope.
Communicate the debt and make it visible
It is vital to communicate the debt from the earliest stages of development. Make sure every non-standard code decision and cut corner is visible to your client.
In an individual project, tech debt should be added to the product backlog as an usual task. To make it visible, we use the “refactor” labels for task tickets. As the laid off debt grows over time, the best practice is to start paying it and not generate the new one. This can be done by reserving a part of each sprint or annual budget for refactoring.
Track your debt
Source code review is a quality assurance activity that helps track down and eliminate code defects. Proper code review may suggest new solutions to certain problems that, eventually, lead to better compliance with the quality guidelines and project specs.
Syntax analyzers, such as Rubocop for software written in Ruby, are helpful in this process.
Takeaway: Technical debt can and should be reduced
Technical debt is like taking a loan. You get a speedy profit, like an earlier release of a software product, but must be aware of the interest you will have to pay. The sooner, the better.
Until some time, tech debt is invisible, but it’s very easy to overlook the moment when its size is monstrous. The costs may range from broken features of an application to months of code refactoring.
To take on technical debt, a product owner must have a strong cause for it and keep its levels low. At Prograils, whenever debt is traced, we encourage our customers to make it a part of the product backlog and devote a part of each sprint to code refactoring.
It is important to keep the client informed about what technical debt is and why should they care about it. This is why open communication and close involvement of business partners in the development process is so important.
Happily, both are underlying values at Prograils. Let us know about your project!