"Know your enemy, know yourself, and in a hundred battles you will never be defeated"
While this describes tech debt well, it doesn't provide common underlying reasons, and for that there are a couple more concepts that have to be taken into consideration.
1. management measurement and estimation tends to only cover the initial development phase of a piece of work, and tends not to explicitly factor the ongoing and end-of-life costs. As such those costs then tend to get baked into the costs for future work that is coupled to it.
an expedient piece of work with respect to initial delivery, if it were to have an impact on all subsequent work, it reduces the ability to deliver since it's ongoing costs need to be added to all future work.
which leads into the second aspect
2. Coupling - often the expedient (technical debt) decisions allow for the coupling of work. By reducing the coupling, the costs associated with new work tend to be self-contained and not factor in prior maintenance. As such the ability to deliver over time improves even if the initial development might be higher for the decoupled work.
eventmodeling.org goes into more detail in a similar vein, but does include a good diagram to help visualise this : https://eventmodeling.org/cost-comparison.jpg
The idea of writing code *clean to refactor* really caught my attention. It is only a small shift of perspective compare to writing *clean* code, but it means looking ahead and anticipating instead of being obsessed with the current state of your problem.
I can relate to that in data science especially, where your understanding of a problem changes as you write code and thus have new results to analyze.
But I would be curious to ask what you recommend in practice to write code *clean to refactor*? I feel that building abstractions before it is really needed is a first trap to avoid.
Also, I think that Ward's quote "If we fail to make the program aligned with what we understand to be the proper way to think about our [...] objects" can be interpreted in two different ways:
1 - not having a proper understanding of the situation
2 - having a proper understand of the situation, but failing to actually implement this understanding.
The result is the same: a code which is not a good fit giving the requirements, but the solution to solve this issue could be different in both cases.
Thanks a lot for this great content Luca, I'll keep reading it with pleasure ;)
I think it's important for us, as techies, to appreciate the company/business stage inorder to fast adopt either alternative.
I'm part of a team where, initially, we'd stuck to "getting the right design from start" until we realized that the product was instead more skewed towards the "rapid evolution" approach.
This article has helped me understand why the "technical debt" is inevitable and why a tech team needs to plan repaying that "debt" very so often least it becomes a time-bomb!
Thank you for writing on the subject, I think there is a lack of rigor and discussions of the principle, and so, in practice, it becomes an excuse for whatever an engineer/manager wants to do or not do.
> He doesn't talk of poor code
He directly calls out bloggers mistake tech debt with "dirty" code and Cunningham mentions he's never in favor of writing code any worse than one's best ability(not "perfect", but still high bar). The debt metaphor is more about understanding of domain and internal inconsistency within different parts of the code base (frequently distributed systems).
DRY is one possible tool for keeping internally consistent implementations.
Was there an old Apple way/ saying - get it to work, then do it right, then make it faster?
Nice article. Well summarized. Above the understanding of technical debt, having ongoing visibility and commitment to clear it are the major problems. Especially in the enterprise space, businesses wouldn't like to prioritize technical debt works when compared with new business features, and this approach continues till they wouldn't move any further with the debt. While writing code that is clean to refactor is important, the shift in the mindset to consider technical debt as an integral part of their journey is also important. By the way, sailor knots is a good metaphor :)
"Writing code that is clean to refactor — which is very different from clean. Such code is similar to those sailor knots who should be strong enough to hold for a while, but easy to dismantle when not needed anymore." amazing example
This situation (Technical debt) is not good. Instead, you can perform situation, take time to build better solutions.
thanks Luca for this apt article. Could it be possible to mention any real world examples as case studies as well for more benefit to us. thank you.