‘Technical debt in software development is implied cost of future work required, by choosing an easy but poor solution instead of better one that could take more time, resource, or effort.’
As business owner, product managers and software engineers, it’s important for you understand what technical debt really means. Having a thorough knowledge on the subject will make you see technical debt as a double edge sword rather than a problem. It’s imperative for us to understand the underlying causes so that we could be equipped to deal with it on a day to day basis and use it to our advantage when required.
Let’s begin by using a hypothetical scenario that’ll illustrates what Technical Debt is and how it accrues overtime in an application development project.
The day begins with a scrum meeting where developers, operations staff, quality engineers and the software architect meet to discuss progress and plan the day’s work. The team us under pressure to meet a deadline owing to a new feature release.
Here are some actions taken by team members under stress of quick delivery.
Developers take shortcuts: The developers decide to take shortcuts in an effort to meet the deadline. They implement a quick solution for a critical component and bypass proper code refactoring and testing to save time.
Operations staff compromise on deployment procedures: The operations staff decide to skip some of the routine deployment procedures — they avoid comprehensive testing of the code in a staging environment owing to time constraints.
Architectural Compromise: Understanding the urgency, the architect approves a temporary architectural compromise. Instead of designing a scalable and modular solution, they decide to go in for a quick fix that satisfies immediate requirements but sacrifices long-term maintainability.
Inadequate Testing: The software testers decide not to test the software extensively and overlook edge cases. This increases the likelihood of bugs and issues arising in the future.
Neglect in Documentation: The developers neglect thorough documentation in a rush to meet the deadline. The code lacks proper comments, and the architectural decisions are not updated in the design documents. This makes it challenging for the future developers to understand the details of the implemented solutions.
The team however managed to deliver the feature release in the given time.
Now let’s outline the consequent accumulation of Technical Debt as a result of the teams actions.
The developers delivered a code that is not optimized — it lacks suitable error handling and may not scale well. The operations staff did not follow deployment procedures which could potentially lead to deployment issues and downtime.
The architectural compromise could lead to a lack of extensibility making it difficult to add features or implement modifications. And the absence of comprehensive documentation and testing could make it difficult for new team members to maintain and improve the system.
Notice how technical debt has a wider scope than code debt — in that, it includes architecture, documentation and testing practices as well.
Grady Brooch, a software engineer known for collaboratively developing the Unified Modeling Language (UML) does a great job at explaining the concept of Tech Debt by using the analogy of evolving cities.
He points out that the concept of technical debt is central to understanding the challenges that impact systems. It often reveals where, how, and why a system is stressed. For instance, in the cities we live in, repairs on infrastructure are often delayed and incremental changes are made rather than full scale permanent ones. Similarly in Software Systems, the users suffer the repercussions of unpredictable complexity, delayed improvements, and insufficient incremental change. Meanwhile, developers working on such systems constantly struggle to produce high-quality code as they are perpetually playing catch-up.
Martin Fowler conceptualized a framework called as the Technical Debt Quadrant that categorizes technical debt based on two dimensions: reckless/prudent and deliberate/inadvertent.
This differentiation is based more on intent and nature of the technical debt, rather than the technical categorization of it.
Here’s a breakdown of each quadrant:
In this quadrant, technical debt is incurred intentionally and with full awareness. It is a conscious decision made by the team for strategic reasons, often to meet short-term goals or due to time and resource constraints.
This is the type of technical debt that’s incurred unintentionally and without complete awareness. It’s a result of the teams’ careless development practices or a lack of understanding of its impact on the software system as a whole and its long-term consequences.
In this case technical debt is unintentional but incurred with a clear understanding of its consequences. It’s the result of an informed decision made by the team due to factors like time constraints or prioritizing immediate goals. In this case the team does have a plan for long term maintainability.
This quadrant includes unintentional technical debt incurred without deliberate intent and without clear awareness of its consequences. It often results from oversights or mistakes made by the team during development.
The Technical Debt Quadrant emphasizes the importance of being deliberate and strategic in managing technical debt. As engineers we should acknowledge that tech debt is not completely avoidable, and prudent decisions are sometimes necessary to achieve business goals.
Technical Debt can also be categorized on a technological plane.
Architectural debt refers to compromises and suboptimal decisions made at the high-level architecture of the software. It involves choices related to the selection of architectural patterns, the arrangement of system components, and the handling of data flow.
Compromises in design decisions of the applications that sacrifice long-term maintainability and scalability for short-term gains.
Code debt include quick fixes or shortcuts in coding that prioritize speed over long-term code quality, that leads to less readable, maintainable, or efficient code.
Neglecting thorough testing or rushing through testing phases to meet deadlines results in inadequate test coverage and increased likelihood of bugs.
Documentation Debt encompasses poor comments, lack of comments, lack of guides, or outdated documentation. Inadequate or missing documentation hinders understanding, maintenance, and troubleshooting.
This may involve skipping necessary steps or not automating deployment. Issues related to deployment processes lead to difficulties during the deployment of new releases.
Challenges arising from the mismanagement of dependencies on external libraries, frameworks, or services. This includes using outdated dependencies or neglecting updates.
Neglecting or inefficiently integrating automated testing practices into the development process results in slower development cycles and increased manual testing efforts.
People Debt are problems related to team dynamics, communication, and technical skills. It includes poor collaboration, lack of communication, or skill gaps within the team.
Till now, we have seen how the engineering teams contribute to accrual of technical debt. But can only they be held responsible for it? Well, sometimes limitations imposed by product managers or business owners leave engineers with no choice but to incur them. Let’s consider some points that elucidate this.
Clients may set deadlines that force the dev teams to prioritize speed over optimal solutions. Businesses operating with tight budgets may limit the resources and time allocated for thorough development and testing of products and feature releases.
Business owners and product managers who are not well versed in software engineering may unknowingly impose requirements that lead to technical debt. They press for product releases and features without understanding the long-term impact on the systems.
To remain competitive in the market, clients must adhere to customer demands. They are often forced to change the project requirements to meet consumer expectations. Diversions from the original application roadmap forces software architects and developers to make adjustments in the system to accommodate these shifting demands, leading to tech debt.
Business owners may be driven by short-term gains and their need to quickly acquire a good market share. They may pressurize the engineering teams for early releases and may tend to focus on short term goals. To attend to these demands, team is compelled to take drastic steps in development and delivery processes.
Collaboration is between the client and the development team is crucial to quality development of applications. Lack of collaboration and transparency may inadvertently cause the client to impose constraints on the developers to deliver faster than possible.
It may begin to appear that only businesses owners and the engineers are responsible for accumulation of tech debt. But there’s another angle to this problem. Sometimes, the customer demand or market conditions force the business owners and their teams to take crucial decisions leading to tech debt.
Quick feature releases could be critical for the survival, growth and success of the enterprise. The customers being completely unaware of the business and the technical problems force the businesses to undertake practices which inherently cause tech debt.
So we could conclude that the development teams, business owners and the customers are the sometimes the likely drivers of technical debt.
Technical Debt is compared with Financial Debt for a good reason. As financial debt is a tool that allows businesses and individuals to borrow from the future, technical debt helps business owners and teams to deliver products and features faster when required.
Let’s understand this with the help of an analogy. Suppose it’s critical for a business to release a feature before the competition does, helping them acquire a good portion of the market share and strengthen the loyalty of its existing customer base. The team understand the criticality of the delivery and makes adjustments in their workflow and code to ship the feature in a short amount of time. The business performs wonderfully as the result of this update. The business’s substantial growth after the release helps them to expand their team and application capabilities.
Here technical debt can be viewed as a tools which the business and its team leveraged to succeed in their feature release endeavor. This wouldn’t have been possible if the team stuck to their proper way of working which may have possibly delayed the release.
Also, one has to remember that technical debt like financial debt has to be managed and paid back. The team in this case could revisit the code and system implementations, and alter and refine it to fit the standards. They could rigorously test the system and update the documentation.
It’s crucial for business stakeholders and software teams to understand the importance of Technical Debt. A deep understanding and identification of its types and forms help us see it as a tool rather than a drawback.
Technical debt should be leveraged to augment business and engineering performance. But like financial debt, technical debt needs to be managed well to ensure stability and growth of the business. Standard procedures should be set to identify good debt from bad ones, and manage them effectively.