The metaphor of Technical Debt has been widely accepted as part of the current reality of software development. Programmers agree that they frequently need to make sacrifices in order to meet deadlines, and the consequences of these sacrifices are modules that should be redesigned in the future. In order to “pay” the technical debt, Refactoring became a routine in the development process, and Test-Driven Development helps assure that these constant refactorings do not break working code.
I don’t feel comfortable with this reality. I think that software developers should not incur technical debt so easily. And I think software developers are wasting too many efforts with constant refactorings, what has been called “Refactor Distractor”. In my opinion, the right way to fight technical debt is to accumulate Technical Savings.
Technical Savings: Well-designed code, planned to satisfy future needs. Technical Savings are a form of wealth that makes a module more maintainable, extensible or reusable.
Now the question is: How do we accumulate Technical Savings?
We can save money when we earn more than we spend. If our earnings are the result of our work, then if we are saving money we could say that we are actually working more than we need. But we all understand the importance of having savings in our bank account, because we know that we may have more needs in the future.
Exactly in the same way, Technical Savings are the result of some extra work. We must invest in the design of our modules so that they are indeed more maintainable, extensible and reusable. But we must believe that this investment will pay itself in the future. If done right, the efforts invested in accumulating Technical Savings should be smaller than the efforts required in the alternative of incurring technical debt and then paying this debt through successive refactorings.
Technical Savings and Adaptable Design Up Front
In some of my previous posts, I’ve described my approach of Adaptable Design Up Front (ADUF). The key idea is that software systems must evolve, and that this evolution must be supported through well planned, adaptable designs.
In other words, there will always be changes, either in the form of new features or modifications in the original requirements. One option is to implement these successive changes as they happen, what inevitably will cause technical debt and the need for refactoring. Another option is to be aware that these changes will happen, and to plan our systems to accommodate these changes as easily as possible. A design that is planned to accommodate change is an adaptable design.
In one of my posts I explain how adaptable designs can be implemented through frameworks and platforms. In this same post I talk about the importance of decoupling through Design Patterns and about the need of Domain Modeling.
In another post I explain how adaptable designs should actually be an application of the Open-Closed principle. Our design will be really adaptable only if it has some parts that do not need to be changed, and if the parts that may change are easy to change.
It is possible to avoid the trap of constant debt and refactoring. We may accumulate Technical Savings, a form of wealth that makes our modules more maintainable, extensible and reusable. One approach to acquire these Technical Savings is trough Adaptable Design Up Front.