
Technical Debt 101 - rograndom
https://medium.com/@joaomilho/festina-lente-e29070811b84
======
Joeri
I've had occasion to think a lot about the relationship of quality to long
term productivity. The remarkable thing about building software quickly is
that if you focus on speed, cutting quality where needed to "move forward",
you end up slowing down after a while, due to the build-up of technical debt.
A continued focus on speed will typically result in slower development, and a
low-quality product, a sort of worst of both worlds scenario.

On the other hand, if you focus on quality, you end up making choices that
enable fast development. You make sure you have high-quality requirements and
a deep business domain insight in the whole team, which means you end up
writing only that code which you truly need, and write it in the right order
(most important features first). You make sure you have code that is well-
covered by tests, which as a happy side-effect makes it easy to adapt to new
requirements. You focus on having a high-quality deployment process, so the
amount of customer issues that result from a broken deployment go down
reducing the load on your dev and support teams.

Focusing on quality first is not about gold-plating code, it's about making
conscious decisions to have a high-quality process from front to back, and
those decisions typically result in a highly efficient organization. It's no
accident that those teams which manage to ship releases every few weeks (e.g.
firefox, chrome, facebook) have world-class products. You have to focus on
quality to go fast.

This isn't just theory. Capers Jones actually measured this. The fastest
delivery schedules were produced by teams with the highest quality product.
[http://www.parasoft.com/products/article.jsp?articleId=2769](http://www.parasoft.com/products/article.jsp?articleId=2769)

~~~
opendais
As someone who works at a place that has tons of technical debt yet is able to
release daily, I have to disagree.

We have things that are 6+ months old without any of the normal best practices
and are able to continue to ship w/o delay.

 _Hell, for a new project /service two of my coworkers completely bypassed
version control and unit tests_.

You can achieve high velocity without high quality. The cost to do that is
sometimes you have an expensive production bug to fix.

Please note, I'm not endorsing the way my coworkers do things but I've given
up fighting any of it outside of my narrow slice of turf. ;)

~~~
sheepmullet
It sounds like releasing daily is part of your testing strategy in that you
simply let your customers do the testing for you.

Making small incremental changes with extensive manual testing can work. It
just looks like you don't have to pay for the test effort.

I've seen it a fair bit with internal projects at larger companies but most
external customers I have met in my career would quickly switch products.

Edit: It also sounds like you are confusing best practices with good code.
I've met teams, usually without a formal cs education, who haven't used
version control and didn't have any unit tests, but still had a well designed
codebase. Of course best practices are best practices for a reason....

~~~
opendais
> Edit: It also sounds like you are confusing best practices with good code.
> I've met teams, usually without a formal cs education, who haven't used
> version control and didn't have any unit tests, but still had a well
> designed codebase. Of course best practices are best practices for a
> reason....

1) They both have degrees in comp sci.

2) For very narrow definitions of the word "good" you would be correct. Its
technically functional and reliable. However, it regularly has problems with
security and/or changes to the common library breaking other people's
services.

------
jackgavigan
It's possible to minimise the technical debt you take on (without spending the
full amount up front) by being smart about your application's
design/architecture.

Using the user roles example given in the article, it's not beyond the wit of
man to foresee that you're going to need user roles at some point in the
future, so you can make provisions for adding it in later. Done right, the
extra effort is minimal but means that you'll be able to plug in the new
functionality at a later date without needing to refactor the entire codebase.

It might be as simple as figuring out where the permissions/role check will go
and including a "# Future permissions check will go here" comment. Or you
might actually include a check that calls a dummy service/function which
always responds to a "Can this $user do $action to $resource?" query with
"Yes". Then, in a few months, you can simply replace the dummy
service/function with a real one.

You don't even have to design/architect the whole thing up front. You just
need to avoid painting yourself into a corner. Ask yourself "What am I likely
to need in the future and can I do something cheap now that will save me a lot
of time/effort further down the line?"

If you ever need to explain this concept to a non-technical manager, tell them
that it's like applying a kind of net present value calculation to development
time/resources: Spending a little extra now means you can potentially save a
lot further down the line.

~~~
rdtsc
> It might be as simple as figuring out where the permissions/role check will
> go and including a "# Future permissions check will go here" comment.

Very good point. I was thinking about this issue not too long ago. And the
ability to do that, comes with experience and often separates normal
programmers from much better programmers.

It also takes a while to detect this, because there needs to be enough
"Futures" that become present to tell if the original architect predicted or
foresaw or did they just over-abstract or and overloaded the code with
potential apis or features.

More often than not I see the later. "This code never runs","why is this
here","we have 4 levels of abstraction for this, why?". "Oh because I thought
we'd have this and that in the future so I added in".

Quite rarely I see the former. When a developer is asked "can we add this?"
they come back and say "yes easily, I knew you'd come and ask for this so I
added the abstraction to handle it or add stuff to it later". The one thing I
noticed is that this becomes a pattern for people. Some people create the
former type software some the later.

------
dllthomas
I don't understand why bad code is "not technical debt". It seems to me
technical debt, _poorly spent_. Someone who takes a payday loan to buy beer is
still incurring a debt.

If there is some more meaningful distinction here that I'm missing, can
someone clarify?

~~~
michaelfeathers
'Technical Debt' is a case where a specific thing was named before the general
concept. Another case is the phrase 'mock object'. In the early 2000s, the
original mock objects paper coined the term and defined them as testing stubs
with builtin expectations. For years, people used the term "mock object" for
any sort of stub.

Technical Debt is a very specific metaphor that Ward Cunningham framed as a
strategy. Ever since, though, people have used the phrase for all sorts of
entropy in software. If you look around the literature, you'll see people
talking about type 1 and type 2 technical debt.

In my experience (and I'm the guy who wrote the Legacy Code book mentioned in
the article), the typical entropy thing that we see in software has more to do
with just taking the easy way and avoiding refactoring - different from Ward's
concept.

------
joseph4521
To me, all code is debt so long as it requires maintenance. It will be read
and modified hundred of times after being initially written hence why you want
to have as few as possible. Code also need to be hosted on servers somewhere
and that's a sort of debt too since you now are forced to maintain the
infrastructure, keep the software updated, ensure it's always running.
However, you have to accept a certain amount of debt otherwise you will never
be able to launch anything. Everytime you can invest some time to reduce
maintenance later down the road, it's like getting a lower rate on your debt.
However no matter how hard you'll try, if the project is used it'll require
love, time and hard work to keep it going. Then comes a time where either the
project fails and you take it down (and stop paying any debt) or, if you're
lucky, the balance between ongoing cost and benefits start to even out and
you're finally out of the woods.

------
rhspeer
While a good post, the real issue is that non technical managers of technical
projects is quickly becoming more of a risk than many projects can prudently
accept.

The old, and unfair, characterization of programmers as smelly trolls that
can't handle client interactions is more of a crutch for fools than a reality.

The truth is my clients complain bitterly about how they'd prefer to just talk
directly to the dev's and not be bothered by the various hand waivers trying
to justify their line item on an invoice. Often this is a great way to annoy
the dev team, but it's a good expression of the perceived value of a non
technical intermediary.

In the end the old truism of "You can't manage what you don't understand"
still applies to this new fangled industry of software development.

That being said, ramping dev's up on management techniques is another
challenge, for another internet rant.

------
leoc
I don't see why the analogy to debt is necessary when the direct analogy is to
capital underinvestment: in fact what we're talking about _is_ or very nearly
is just that, capital underinvestment, not simply something analogous to it.
And the hypothetical businessy, non-technical types whom the debt analogy is
intended to enlighten understand very clearly what deferring capital
investment is and what the likely consequences are, at least if they actually
know anything much about business.

~~~
msandford
Most of the people who are pushing for "features now, someone else's problem
later" are probably not upper management but rather middle management. Upper
management might understand capital underinvestment. Capital underinvestment
is very nearly the sole job middle management is there for. And berating
people for not being done yet. At least at a couple of the places I've worked.

------
the_watcher
I like the concept of Minimum Lovable Product, although MLP isn't as catchy as
MVP (thanks to sports). It's probably good to think of an MVP as a step on the
way to an MLP - the MVP is the one you release to specific audiences of likely
users or show to angels or seed investors to show that it can work, and be
very explicit about it not even being a beta version - more like a version
0.1.

------
jasode
>Thousands of startups have launched and failed precisely for the lack of
quality.

That was an emphatic statement in the article and I feel the discussion would
really be constructive if the author (or posters in this thread) listed
concrete examples of startups that failed _primarily_ because of software
quality.

If success has many fathers, failures are not orphans and also have many
fathers as well. Perhaps software quality was not the 1st but actually the 2nd
or 3rd reason why the company failed. I'm not saying such examples of software
execution killing the company don't exist. I just can't think of any prominent
examples at the moment.

I'm leaving out poor software examples such as the Atari 2600 E.T Extra
Terrestrial game cartridge because that was not a startup situation.[1]

[1][http://en.wikipedia.org/wiki/E.T._the_Extra-
Terrestrial_(vid...](http://en.wikipedia.org/wiki/E.T._the_Extra-
Terrestrial_\(video_game\)#Critical_response)

On the other hand, an internet company like Friendster looks like an
interesting case study. Their infrastructure software was not efficiently
traversing their social graph. It was something Facebook programmers conquered
but Friendster did not. But was software quality the #1 reason behind
Friendster's demise? Apparently, the board-of-directors didn't prioritize and
throw money at the engineering challenges that Friendster was facing.[2] So
the their failure can be reinterpreted as a combination of management of
priorities and software execution. Maybe if they did throw money at the issue,
it wouldn't have mattered because their programming staff didn't have the
unique competencies to tackle at-scale social graph problems. In that case,
it's not a "technical debt" issue but a "hiring talent" issue.

[2][http://highscalability.com/friendster-lost-lead-because-
fail...](http://highscalability.com/friendster-lost-lead-because-failure-
scale)

Another case study might be the Chandler software (chronicled in the book
"Dreaming in Code"). However, it appears that the product got bogged down by
architecture astronauts unable to make decisions and not "technical debt".

If there are thousands of companies that failed on software quality, it'd be
interesting to see which ones can be disentangled from non-software issues and
we can confidently say, " _yep, that technical debt is what killed them._ "

(My curiosity for real examples does not mean I'm endorsing technical debt.
I'd just like to get some real-world perspective on this topic.)

------
swalsh
Here's the analogy I made up a bit ago trying to explain the concept.

As programmers We build code paths. Design mazes. In the beginning the maze is
simple, there's only a few paths. To make things simple we separate our ideas
into many small mazes. Since they're small, it takes a short amount of time
and concentration to predict the different possible paths in our heads.

Technical debt is when, due to to time constraints the decision is made that
it is quicker to draw one more line on an existing maze, rather than create a
whole new small maze. In the beginning it seems not so bad, you can still take
in the whole maze at once. But as time goes on, that one maze gets larger and
larger, and finding a successful path through it takes longer, and longer.
Eventually you get to the point where you can't separate the maze because too
many of the paths are built on top of each other, but you also can't manage
the maze because its to large itself. That's the default. That's the rewrite.

------
jameshart
This isn't a 'primer' about Technical debt - it's an opinionated piece about
the value of the concept of technical debt, which I think is at least a 102 or
possibly 201 level course on the subject, and needs to be taken in the context
of other material. I suspect it hasn't been tested out on many nontechnical
managers, either - using the concept of electron spin (for a nontechnical
audience, remember) as an analogy for the concept of analogies is the kind of
meta-analysis that I think will lose them pretty early on.

I think the real problem of this piece is that it flatters nontechnical
managers, as businesspeople, by describing technical debt as a sensible
business decision they can get into consciously through clearheaded
negotiation with their technical team; then characterizes 'bad code' as
something different, that happens when the technical team just don't do their
job. This alleviates the nontechnical manager of any responsibility for bad
code. The fact is that knowing about technical debt is not necessary to find
yourself up to your neck in it. A team which goes for years taking shortcuts,
being forced to hit unrealistic deadlines, or which lacks the skills to really
build a good, robust system, is like a kid with a credit card who doesn't get
that just paying the minimum payment each month isn't going to work forever.
Every shortcut they get asked to take, they swipe the card, and they get to
walk out of the store with the goods, and it seems to just keep on working;
thousands of dollars worth of stuff, and they just have to pay a few hundred
each month. It's magic!

But the consequences will show up in the end, either in the form of a long
period of hard graft to pay it down, or declaring bankruptcy and abandoning
the codebase.

That's why I love the technical debt analogy - different people manage
financial debt differently, and most businesspeople understand the concept
that planned debt is necessary and beneficial for growth; arguing that Ward
Cunningham and the author don't think you should call other technical debt by
that name seems petty, and not particularly useful, when extending the analogy
to runaway debts works so well.

Overall the problem I really have with this piece is that if I tell a manager
"This project is carrying a bunch of technical debt," now they'll google it,
find this, and come back to me with "You mean it's a pile of bad code." Which
is true, but how does that help us? When I make the argument that a troubled
project needs to pay down some technical debt, I'm trying to make clear that
we need to start paying off more than just the minimum payment every month. If
the technical debt analogy is removed from the table, I'm left with just
saying the team needs to replace the bad code with good code. And then they'll
tell me that this piece also told them that the 'big rewrite' was a bad idea
too... So how has this helped?

~~~
chris_mahan
That's when you tell them to go read Big Ball of Mud.
[http://www.laputan.org/mud/](http://www.laputan.org/mud/)

Then they start to understand.

------
slightlycuban
I'm not really a fan of the story-point example. The article begins with:

> it’s something that you get when you delay design decisions for later

But then presents us with a problem where we can "spend" 21 story points now,
knowing we won't have to do much refactoring later. How do we know this? I
thought the whole point was we couldn't see enough of the picture to make a
stable design.

Instead of talking about how patches, hacks, and workarounds impact code, I'd
like to see discussion on how you move forward when you know the requirements
are going to change, but don't know how.

~~~
msandford
If you implement a robust permissioning system that has permissions related to
group membership and one-off permissions related to a single user then MOST of
your problems are solved. Nearly all new permission requirements can then be
made without touching the code at all, or in more than a couple of places.

The idea is to choose a new design that scales better. If you have M
permissions and N permission checks then each new requirement might cause M *
N changes to the codebase.

If you have a reasonable permission system you might end up having to make N
changes to the codebase (worst-case) or perhaps only M modifications to
permissions or perhaps both. But in that case it's M + N changes, rather than
M * N. For any values of M and N greater than 2 (and very nearly all of them
will be) M + N is smaller than M * N.

~~~
slightlycuban
The issue I deal with isn't in choosing a design that scales better, it is
uncertainty in how things will scale. Say I need to handle group permissions
depending on the context. I could hard-code the permissions changes for the
one group that needs it now, or I could abstract and generalize context-
switching behavior into its own component, ensuring changes to future groups
will be easy and low-cost.

But, what if I _never_ get a second group that needs this? While hard-coding
values was an ugly shortcut, I may never have a need to revisit the code. If I
had gone with a generalized solution, I'd still have to contend with
maintaining all that code.

~~~
msandford
That's an interesting point. Here's my take:

If you ask someone who knows about the business rules if something could EVER
happen and they say "no" they're probably wrong, but not maliciously so. Be
cautious when taking their word for something. Even if the CEO signs off on
the idea of "such and such never needs to be able to do x, y or z" the second
a big contract does need it, it all goes out the window.

As a result whenever possible choose solutions that give you SOME flexibility
without necessarily creating a supremely robust, exhaustive module.

In this particular case, once you realize that you're going to have more in
the way of permissions other than global can/can't do, it's time to be smart.
Being smart might only mean creating a function which takes some context like
userid and "permissions token" and/or the URL that the person is visiting and
then doing a hardcoded permissions check for say one of a dozen userids who
are basically root versus everyone else who isn't.

Yes you didn't make a giant scalable system of awesomeness including a web-
based permission editor. But you did make a function you can insert every time
a new permission item gets created and eventually a system could be created
for storing those in the database such that users can eventually be mapped to
permissions also in the database.

So if you want to hard-code those values into a single page, which then grows
into two pages, which then grows into four pages which then grows into 29
pages that's the wrong solution. But if you want to hardcode those into a
function which you then call, that's a good enough solution for now that
doesn't hobble you later. Putting the function call in adds very minimal
overhead in terms of execution and ranges from slightly negative to moderately
positive on maintainability.

Parts of software development are similar to being a speculator in a financial
market. You need to have a fairly intuitive grasp of what's going to be a
"good bet" for spending a little more time now which has the potential to pay
off big in the future.

------
adamconroy
I think analogies generally suck. Better to analyze things for what they are.
Analogies are good for explaining difficult to understand concepts, but all to
often people say, x is analogous with y, y has something good/bad about it,
therefore x has something good/bad about it.

Technical debt is a good example of a bad analogy :

1\. Assume some piece of code works, technical debt is only an issue if that
code ever needs to be modified. Financial debt is always an issue regardless
of what happens, even if you die.

2\. Writing some code that generates the so called technical debt will often
have an upfront cost saving, so whilst it might incur some extra work down the
track, the extra work isn't a straight cost. The cost = (extra work - time
saved up front).

3\. Attempting to avoid technical debt often ends up with over-engineered
code.

4\. Being dogmatic and avoiding technical debt in all projects is often not
good for the project / business / investors. Being early to market at the cost
of code quality is often very important.

I think point 3 is the worst scourge of all. It is quite common amongst mid-
range developers. After working for a while they start to get good development
skills and start to think too much, looking for ways to express their skills.

In summary, it is like most things in life, there is a balance to be found.

~~~
adamconroy
Something that gives a counter opinion to group think is never appreciated.
Better we all sit around and stroke our egos, with every statement implying
how magnificent we are and at the same time implying how everyone else is
churning out debt filled shit.

------
vpeters25
I am not sure "delaying business decisions for when you have better
information" causes technical debt. Under this premise, pretty much every
agile development project would be technically bankrupt.

------
craigyk
I like its target audience, but am I supposed to just forward this to my
superiors? Can't imagine they won't feel at least a little insulted, even if
it's a concept they need to understand.

------
patja
Always an interesting subject. I can't help but feel it would reach a much
wider audience and achieve a greater impact if it was subjected to an
automated grammar check, or edited by a native English speaker. I could not
get through all of the distracting grammar errors, and I suspect most non-
technical English speaking managers (who seem to be the intended audience?)
would have the same reaction.

~~~
LyndsySimon
Could you provide some examples?

As a native English speaker and someone who prides themselves on their ability
to clearly convey complex ideas through prose, I don't recall a point where a
grammatical error detracted from my understanding.

------
personZ
"Bad code" is a completely subjective measure which everyone is sure they will
know when they see it, but few agree on the actual definition.

Extreme examples will be floated, but in practice what people consider "bad
code" are things that made decisions that aren't sustainable. For instance a
complete lack of permissions. A lack of logging. A lack of multithreading if
it's a CPU bound process. Locks. Dependencies. Etc.

Each person and team really does define bad code differently, and often in
complete contrast with each other. There are people who considered DI heavy
code bad code. Heavily abstracted and layered Java code is considered great
code by some, horrendous code by others. And on and on.

------
alphanumeric0
Can I upvote this like a million times?

