Developers often try to minimize the amount of technical debt they take on when building software. Many will even try to have “zero” technical debt. It sounds like a worthwhile goal. Technical debt can be extremely costly in the long term so getting rid of it can be extremely advantageous down the line.
It isn’t possible to have zero technical debt though. That’s because all code is technical debt. Every single line of it.
I’ve briefly touched on this point before, but let’s dig deeper into it. Start with the subject of personal growth.
How far are you into your career? 5 years? 10 years? 20 years?
At 20 years of experience, you still have at least another 20 years left. That only puts you at the halfway point. What do you do for the next 20 years? Keep using the same practices you used for the previous 20? Or do you keep learning new things? Do you continue to strive to be better?
I’ve met developers with 20 years of experience that were marginally better than interns. I’ve also met developers with 20 years of experience that were simply phenomenal.
The reason there is such a huge difference between two different types of developers is due to how our field works. Technology changes fast. 20-30 years ago a developer had to worry about saving 4 bytes of data. They may have even spent a few days or weeks trying to save those bytes.
This is a worthless activity in 99% of software projects worked on today. Computers are faster and have much more memory than they used to. Efficiency is still important, but not to the degree that is was decades ago. We have enough computing resources for us to afford trading away some efficiency for better user experiences or faster development.
Building to optimize for UX or development speed requires different software design than optimizing for execution speed. Even if code optimized for execution speed was built really well, it will be difficult to convert it and optimize it for other things. That code is now sub-optimal because it doesn’t serve the purpose that it needs to serve. That makes that code technical debt, even though the original developers did a great job writing it at the time.
Those developers also now have to learn how to write new code in a different way. Otherwise they can only do a great job writing code for a purpose that no longer exists.
Another example of this is deciding whether to build something yourself or leveraging an existing solution. There were a lot fewer libraries, frameworks, and tools 20 years ago. Getting things done required building things yourself because there were no existing solutions to leverage.
Knowing how to write code is one skillset. Knowing how to evaluate someone else’s software is a different skillset. Today there are a near endless menu of options for leveraging software someone else built. These options tend to have dedicated teams around them too. That means that they will have most likely have done a better job at building the library, framework, or tool than you or I will if we tried to do it ourselves.
You’d have to be crazy (or very very brilliant) to want to build anything that isn’t a core part of your business when an existing solution is available. There are often many solutions available though and evaluating them can be daunting. Writing code is more comforting than trying to sift through all the options and many developers will skew towards building everything themselves instead of trying to find an existing solution.
This can lead to bad decisions though. Even if those developers did great jobs building everything themselves when they needed to 20 years ago, doing so today results in sub-optimal solutions being built and used. Also, the code that uses their home-built solution 20 years ago is now using an inferior solution. It doesn’t matter if that was the only option at the time. There are better options today. That makes that old code suboptimal. That makes that old code technical debt.
Most importantly, the best people in any field don’t hit a point where they go “I’ve learned enough. I’m good.” They never stop learning. Even if the world never changed and we were stuck with the same computing resources and the same tools 20 years from now, developers should still strive to be better tomorrow than they are today.
When a developer learns a better way of doing things, it makes every line of code they have written in the past suboptimal. It doesn’t matter how much care or thought they put into that code. They’ve learned how to make that code better. That existing code is now inferior. That code is now technical debt.
This post was originally published on blog.professorbeekums.com
Top comments (9)
Nice post but I'm still uncertain what you meant by "When a developer learns a better way of doing things, it makes every line of code they have written in the past suboptimal"
Also, you seem to equate technical debt to suboptimal. Aren't those two things different?
Conceptually yes. Practically no. You start at a company and you see code that is making things harder than it should be. Do you try to differentiate between the two or do you just treat it as technical debt?
The point I'm making is: a developer writes some code. They learn to make that code better later on, but don't have time to rewrite it. If they went back to that code it would start to look painful because they know how to make it better. By default now they have technical debt because if they left it alone and tried to build on top of it, it would be off of a technical solution they know to be inferior.
Thanks for expending on that.
Typically code reviews eliminate most of these technical debt you described. I tend to think of technical debt as a "team debt" due to specific constraints such as time or resource.
Tech debt avoidance might be worthless at a micro level, but a lot of tech debt can be made cheap to remedy by choosing a adaptable architecture and avoiding framework lock-in. I think the article pigeon-holes the issue and ignores the greater scope.
The counter to that statement is that architects learn new things too. There are always ways to improve on things from the macro level to the micro level. You'll probably find 10x more people talk about micro services than people who have actually implemented micro services at a large scale. That 90%, of which I am a part of, have a lot left to learn. And those in the 10% have probably thought of different ways of how to improve on what they've built.
I've seen many devs who have fallen into a tech debt hole by getting swept up in a language or framework.
Take for example ASP.NET. Came out around 2002. First choice is VB.NET or C#. It didn't take an expert to read the community and choose C#. At the time, it only had the Web Forms front end framework, which is and was terrible. But when you stripped away the abstractions and focused on handlers/modules, you could have had up to 15 years before .NET Core comes along and you need to migrate to Web API. The migration is a trivial replacement of wrapper code.
Something a bit more difficult- 2003. You're presented with YUI, jQuery and MooTools that are each offering overlapping promises. It takes some hands on use of each, but experience would tell you the jQuery is your ticket. Could still be sticking with it today, although it has been less useful since browsers became more standard. Thankfully it isn't entirely monolithic, the UI library is separate and they have slim versions. Should a dev want to remove the dependency it is at least a step-down process.
Another one is javascript templating engines. A Mustache spec engine was/is the correct choice. ORMs another, but that depends on your stack.
Something more recent (I'll probably regret discussing) is the Angular/React/Vue/whatever else argument. Angular is like choosing ASP.NET Web Forms in 2002 and is a rewrite waiting to happen. React has its good and bad parts. The correct choice for cheap tech debt is to not use a framework and instead choose libraries wisely and implement with caution.
Think you hit the nail on the head with that sentence. The more I learn, the more I find that I have to learn even more to improve the code I've previously written.
Here Kevin Scott LinkedIn V.P of Eng. definition of technical debt:
"The reason that we call these compromises and mistakes technical debt is that in a very real sense you are borrowing against your future to get something done in the moment that you will pay for later, one way or the other"
he is taking about companies but it can be applied to individuals also.