top | item 12291707

Technical debt as an opportunity to accumulate technical wealth

253 points| prostoalex | 9 years ago |firstround.com | reply

202 comments

order
[+] itchyouch|9 years ago|reply
Or we can not look at tech debt as debt but as a unhedged call option:

http://higherorderlogic.com/2010/07/bad-code-isnt-technical-...

From the article:

Call options are a better model than debt for cruddy code (without tests) because they capture the unpredictability of what we do. If I slap in an a feature without cleaning up then I get the benefit immediately, I collect the premium. If I never see that code again, then I’m ahead and, in retrospect, it would have been foolish to have spent time cleaning it up.

On the other hand, if a radical new feature comes in that I have to do, all those quick fixes suddenly become very expensive to work with. Examples I’ve seen are a big new client that requires a port to a different platform, or a new regulatory requirement that needs a new report. I get equivalent problems if there’s a failure I have to interpret and fix just before a deadline, or the team members turn over completely and no-one remembers the tacit knowledge that helps the code make sense. The market has moved away from where I thought it was going to be and my option has been called.

[+] crdb|9 years ago|reply
More like selling a put: you're hoping it expires out of the money, but if volatility goes up, it will be expensive. Upside is limited and short term, downside potentially unlimited and in the long term, so if your discount rate is high (due, perhaps, to low cash reserves) then the NPV of the trade still makes sense.

People who sell a few puts get away with it for a while, but make it your business and you better be too big to fail.

If everybody is selling puts and levering up, you better do it too or you'll find yourself out of a job. And if volatility increases, everybody is exposed at the same time so you won't get personally blamed anyway, and your career will be just fine.

[+] yelnatz|9 years ago|reply
I agree with this. Tech debt really is very similar to how selling call options work.

Unfortunately, not a lot of people know how options work, so now you have another problem of explaining how that works.

[+] dwaltrip|9 years ago|reply
Totally agree. Unfortunately, it's a market with low liquidity and opaque fundamentals, so black magic reigns supreme.

The greatest difficulty is trying to predict how the product will evolve, and thus how the software must also evolve. We should always be thinking about how the relevancy and requirements of each component of source code may change in the future: next month, in 6 months, 2 year from now, etc.

To better evaluate the risk of each call option, there needs to be a strong, coherent, and tangible vision of what the product should be. This vision should be internalized by the entire team. There also needs to be a healthy, forward thinking dialogue between designers, product owners, and engineers.

[+] ptype|9 years ago|reply
Honestly, this seems like a stretched comparison to me. How many managers understand options? And what is even the underlying for your call option? Why would it be a call option and not a put option?
[+] mscottford|9 years ago|reply
There are many different ways to describe this problem, and it's very possible that using a call option as a metaphor is a better fit. Unfortunately, "technical debt" is the term that's currently in fashion, so you at least have to mention it when you're suggesting an alternative approach.

Incidentally, we're big fans of Martin Cronje's article[1] which suggests that "technical debt" is a broken metaphor, and he suggests using "depreciating assets" as an alternative.

[1]: http://www.martincronje.com/technical-debt-is-broken/

[+] mathattack|9 years ago|reply
I think you're right - it is very much like writing call options. It is still a liability, but of an unknown quantity.
[+] mikekchar|9 years ago|reply
There is a problem with these metaphors: activities that work against technical debt are often dependent on the skill and experience of the programmers involved. You often get no long term benefit from doing them.

I write code in a specific fashion, which involves a lot of TDD and a lot of refactoring. I've been doing it a long time and have refined it to the point where I expect to get payback in less than 1 week. But it is naive to expect that someone else will use the same techniques and achieve the same benefits right away (I have been, very, very naive in this respect at times :-( ).

For example, non-mocking TDD forces a particular set of design decision to be made up front. It also forces the creation of specific API entry points. Mocking TDD allows you to defer design decisions and makes it cheap to explore large design spaces. It forces you concentrate on your interfaces. The choice of which to use in various situations dramatically affects how well you can refactor. With non-mocking unit tests, you can get buried in the details of setting up contexts. With mocking unit tests, you tests can become very brittle. It also allows/encourages you to make some pretty horrifying design choices.

Even when people do TDD and have lots of tests, they often make poor choices and end up with code that they can't (or don't want to) refactor. The thing that people often do not understand is that unit tests and/or TDD will usually not provide much of a payback (in terms of productivity) alone. It is the refactoring that leads to simple design, reduces complexity, reduces code duplication, makes it easy to reason about changes, etc. Unit tests (and TDD in general) simply give you a framework for making refactoring easier.

The problem, from my perspective, is not about judging risk of upfront payback versus long term payback. When done well, the activities around reducing technical debt pay off so quickly and so dramatically that there are almost no cases where they are inappropriate. The problem is that using the techniques poorly often leads to no payback at all! In fact, sometimes you inherit a project with a rat's nest of crazy tests and the first thing you do to improve your productivity is delete the tests -- on the principle that less code means less complexity that you need to deal with.

Although my own personal style involves TDD and refactoring, I believe that the same can be said for other styles of development that are geared toward reducing technical debt. In my career I've done BDUP (1000 page requirement and design docs FTW!), I've done rapid prototyping (build 20 to throw away!), and a few other techniques. They can all work, but IMHO require even more skill to do well.

This is one of the things I wish someone told me at the beginning of my career. At the moment my current feeling is that there are virtually no cases where tolerating/embracing technical debt will lead to even short term gains. However, the alternative is not straight forward. Young teams must expend considerable effort finding expertise to help guide them forward. More importantly, everybody on the team needs to be aligned to the style that will be used. How you achieve that alignment is yet another can of worms.

[+] shoo|9 years ago|reply
maybe "unhedged" here is the important bit.

accumulated technical debt makes the software project less robust / less able to respond effectively to future events.

there are many examples in life where failing to do maintenance / prepare for contingencies is a clear short/med-term win, provided something unexpected does not occur.

[+] rhizome|9 years ago|reply
Is there a concept like YAGNI at all in stocks/finance?
[+] kristianc|9 years ago|reply
Here's a question: if you have a team and an internal culture that managed to create a legacy code mess in as little as six months in their existing app, how is giving them a microservices architecture and Docker to play with going to help?

If you give that team that structure, it seems to me you're highly unlikely to end up with beautifully bounded context and highly likely to end up with even more of a mess than you started with.

[+] hinkley|9 years ago|reply
That's a very excellent question, to which I have most of an answer, if not 'the' answer.

Daylight is the best antiseptic.

It's not giving them a microservices architecture and Docker that solves problems. It's expecting them to use it that causes problems to be solved, or at least formally identified.

I do a lot of root cause analysis whether my boss asks for it or not. Human factors are almost always in play. A significant source of bugs that make it into late QA or even production are caused by wishful thinking about the scope and impact of code changes. Things that should have been red flags are brushed off because you can't prove that their code caused the problem, and as long as there is reasonable doubt about the source, some people won't look at code they already declared done.

When the code is developed and tested in an isolated system then the only source of state changes on that system were caused by the new code. It takes a real set of brass ones or an extremely dense skull to deflect concerns about problems seen on a system that only contains your code changes. People either shape up or get labeled as untrustworthy. The former result is preferable, but at least with the latter you get predictability out of the system.

[+] gvb|9 years ago|reply
"Corgibytes often introduces new clients to Docker, making it much easier and faster to set up new developer environments." (emphasis mine)

She isn't advocating using Docker for the target environment, she is advocating using Docker to set up a standard development environment that allows the developers to be productive[1] in 10 minutes rather than 10 hours.

I've been in the situation where the development environment is a poorly documented, massively multi-step steaming pile. The result is I spent a lot of time chasing down those responsible for the steaming pile (the "rockstar" in the department) asking them how to get the development environment working. Typically they pull the keyboard away from me, type a bunch, and then say "there, it works." Which it does. For a while.

Rinse and repeat for every developer. Regularly.

[1] Well, at least building the system rather than staring at mysterious very broken error messages.

[+] biocomputation|9 years ago|reply
Depending on what you're doing, the right decisions might only be visible in hindsight.

To this point, you might scaffold out a system to get something running and then incrementally / organically improve the system. I regard this as 'getting the system to the point where it can be dogfooded and/or criticized in a helpful way'.

At this point, despite what you might have running, it may be exceedingly clear that you should have used a different strategy. Maybe you like the overall results, but you need things to be implemented in a different way.

For example, I'm a C++ programmer. It's not always obvious at first that you need a specific set of virtual functions to make something work really nicely.

It's impossible to always know these sorts of things in advance.

[+] maxxxxx|9 years ago|reply
Yeah, that's the 'shiny new toy' fallacy. In every project there are points when it's clear that something wasn't designed right. Some people decide to get deeper into their mess and some people decide to refactor. It's a judgement call and not an easy one.

I don't think I'd want to work with microservices and Docker containers designed by the same people who messed up another codebase.

[+] beat|9 years ago|reply
Doesn't need to be an "and". Just getting the development/ops environments into a virtualized architecture like Docker can make a tremendous difference in a monolithic app. Quite often, the technical debt is due to configuration differences in manually managed environments - development, QA, and production can differ in small or large ways. I don't know how many times I've seen things like developing on Windows and deploying on Unix, or testing on a single server but deploying into a cluster. Docker (or Vagrant, or others) can fully automate provisioning and configuration, simplifying and enforcing consistency between environments.

Likewise, microservices from monoliths can be done without containers. Just pick a chunk of the monolith that can be pried loose, and start with that. This can solve all sorts of problems.

[+] lostInTheWoods3|9 years ago|reply
Agreed. Cleaning and correcting a code base is only part of the solution. Putting in place the policies and culture to make sure the code stays clean is the other part.
[+] mscottford|9 years ago|reply
You're right to say that a microservices architecture and Docker won't solve the problem. That's not an accurate view of what Corgibytes advocates for. Microservices and Docker are tactical tools that can help many teams, but they don't work everywhere.

What does work is assisting that team to slowly clean up the mess that they've built[1] by focusing on incremental improvements.

[1]: And we find that almost all messes were created for very understandable reasons.

[+] benologist|9 years ago|reply
It's not even "technical debt" until someone thinks "technically ... we could have done this more easily in X".

Now it's a question of developer comfort and huge investment will be made to make sure everyone building the product are having the best experience doing so.

All the old code and knowledge is now debt because it can't come with us on this wonderful journey.

[+] jdavis703|9 years ago|reply
It's easier to just start over again with one small part. I've worked at two places with massive monolithic tech debt ridden codebases. It was nearly impossible to rewrite anything because everything touched everything. Now the place I currently work has micro services. Some are legacy tech debt that no one wants to touch. But if needed they could probably be rewritten in a couple of months. It's the difference between selling AAA bonds and junk bonds. You're probably far more likely to pay off those low interest AAA ones than the junk bonds.
[+] matwood|9 years ago|reply
One of the main causes of technical debt and bad code overall is breaking out of the conventions of the code base. Good code reviews can help this, and solid leads of course, but things can still slip through.

Like or hate microservices, one thing they do is maintain a clear, hard boundary on the interfaces. There is no let me just reach into this class here, or call that there. It does work to keep people honest when the pressure is on.

Will it turn bad programmers into good ones? No, but I think the base assumption is that you're not necessarily dealing with bad programmers.

[+] tunesmith|9 years ago|reply
In my experience, diagnosing the tech-debt problem, prescribing the solution, and implementing the solution are not really the hard parts of this - the hard part is battling the culture that led to the problem, and wrangling that huge gulf between "seeming consensus" and "actual consensus" that the group is actually going to change direction by accepting the diagnosis, adopting the solution, and starting work.

Maybe an outside consultancy makes this easier since they are sort of imbued with a moral authority when coming in, but it could also mean that all the hard political work has been done beforehand in agreeing to hire them.

[+] Ericson2314|9 years ago|reply
I can't agree with this enough idea enough. Also I just love refactoring.

Most of my side work is contributing to existing projects, but here's the stats for 3 school projects: 20,896 lines deleted for 30,342 written. 2 of the projects had fixed requirements from the beginning though one was a more free-form independent study. Additionally all 3 had only one additional author and I did a majority of the line additions and deletions.

I'm pretty sure these numbers are way untypical for this sort of work---with fix goals and deadlines with no more than a few months per project I assume most people delete pretty little, and basically only during debugging.

Certainly this refactor-happy approach did cause some missed deadlines early on, and getting all the abstractions correct still means basic functionality often doesn't come together until the last minute. But I still that the immense technical wealth does pay off as I get more productive the longer I maintain the project---the abstractions anticipate the sort of extensions I may later wish to add by laying a firm foundation. And the fact that the functionality does appear last second speaks testifies to the increasing productivity---longer hours or last minute panic doesn't explain it.

I think most managers would be horrified this approach, but if you're a real company planning on being around indefinitely and not some startup just hanging together or student, this method should be all the more fitting.

[+] mscottford|9 years ago|reply
One of the things that I like to anecdotally measure is how long a similarly complex change takes. Over time, if it takes longer, then you're likely suffering from tech debt issues. If you're able to turn things around so that it starts getting done faster, then it sounds like you're starting to turn things around.

On the missed deadlines issue, that reminds me of a blog we posted a while ago about why we stopped estimating ongoing development on these types of code bases[1].

I also like to use the metaphor of a car that's stuck in the mud (or snow). The wheels Are spinning really fast and the engine is working really hard, but the car isn't going anywhere. It's only when you start trying to dig it out that you start to see forward progress, and even then, the progress is slow at first.

[1]: http://corgibytes.com/blog/no-estimates/productivity/custome...

[+] biocomputation|9 years ago|reply
This is exactly how I work!

>> did cause some missed deadlines early on, and getting all the abstractions correct still means basic functionality often doesn't come together until the last minute.

Yes, yes, yes.

>> I think most managers would be horrified this approach

Yes, been there, done that too!

[+] hinkley|9 years ago|reply
I find it amusing they got their inspiration from This Old House.

Between TOH and the head mechanic (also named Bob) at the bike shop I worked at in college, I get most of my work ethic from outside of software, and it shows. I had high hopes for the 'craft' movement in software but haven't seen much of it materialize.

I spent a lot of my formative years watching TOH, including the 'Pay the Piper' episode where two very nauseous homeowners found out their remodel went 2x the original budget. Part of it was scope creep, but there was always a hefty repair because the foundation was being destroyed by a tree or erosion, and a couple times the entire corner of the house (including corner beams) was rotting away from water damage caused by shoddy work on an earlier repair ten years prior.

I am forever looking for badly-sited trees and water infiltration in my code base, and I'm always agitating to throw out bad tools, get better ones, and learn to use them properly. Just like Bob and Bob taught me.

[+] biztos|9 years ago|reply
I think the "craft of software" is alive and well, it's just weirdly distributed: a few shops doing it throughout, lots of shops (and pretty much all big companies) doing it here or there: an individual coder, a small team, etc.

There are lots of other things like that. Take writing. We all write a bunch of emails (etc.) every day, but how many people try, out of a sense of craft and respect for the language, to write them well?

(Oh and I'm currently having a flat from 1914 renovated, which had additional work done in 1938 and 1958, so I definitely appreciate your analogy.)

[+] mscottford|9 years ago|reply
Another thing I really like about the work on This Old House is that they give a lot of care making sure that the new things are added blend in with the structures that were there to begin with.
[+] edw519|9 years ago|reply
I really wanted to like this post. It's well written. With passion. Using a common metaphor (a house). And about the biggest elephant in the I.T. room today.

But I couldn't. Because it just skated on the surface of the iceberg.

OP is right. Technical debt is a huge problem that requires significant mind shift to address. And I can't find a single thing here that I'd disagree with.

There's a lot of academic theory and cheer leading here. And true, it's requisite to any further discussion. But what I would love to see are specific prescriptions:

  How do you train to avoid the sins of the past?
  How do you enhance process (peer review, QA)?
  How do you conduct post-mortems to organize the attack?
  How do you decide what to black box and what to rewrite?
  How do you prioritize shoring up the foundation and keeping the lights on?
  How do you find tools to automate the process?
  How do you make technology decisions to set the new path?
And probably most of all:

  How do you fix the broken data supporting all this bad code?
Because any treatment of code without diving deeply into the underlying data structure is too myoptic to be of much value.

I've estimated that half of the bad legacy code I've ever encountered would never have even been written if the data were properly structured in the first place. This isn't a discussion of DBMS technology, but a comprehensive treatment of how the business operates and how it's supporting data must be structured, regardless of technology. Fix the data and the code becomes a much more manageable problem to attack.

Of course, maybe OP just didn't get that far.

Nice article. I'd love to read the sequel, about 5 levels deeper.

[+] unabst|9 years ago|reply
Sounds like the word "debt" is being used to make their clients feel guilty, and the word "remodeling" is being introduced to make it sound as if they're doing something novel.

Doesn't technical debt just reflect operational priority? How is having old code a problem if it all works? Debating priority is not the same as automatically asserting it as a problem.

And isn't technical wealth building always an opportunity? Why must one be in debt? But every business has a laundry list of opportunities. Technical wealth doesn't need to be at the top always.

If the axiom is that being cutting edge is sacrosanct, then technical wealth would always be top priority, and technical debt would be an operational problem. But technical debt is just a function of the technical advancement in the field. No matter what you do, you'll always end up in debt if you sit around long enough, and decide to call what you have "debt".

If you can make what you have better with technology available today, do it. If not, leave it. And ignore whether a technology is new or old. Just confirm if it is proven and tested.

[+] tboyd47|9 years ago|reply
The thing is that most projects fail for reasons other than technical debt. Not having clear requirements to begin with is one, and running out of money along the way is another big one. There's not much programmers can do about those, and burning time working on tech debt may actually hurt you on the second one.

Rather than thinking of it like a house you have to live in, I think of a healthy codebase more like a busy police precinct. It may be a bit messy, but that's just because there's always something more important to do than tidy up.

[+] ensignavenger|9 years ago|reply
What you say is correct, but to add to the analogy- if the precinct is such a mess that the officers are constantly tripping over stuff, and criminals are going free because they are misplacing evidence, it is probably time to do some cleaning and organizing!
[+] humanrebar|9 years ago|reply
Projects don't fail because of technical debt, but organizations do.
[+] biocomputation|9 years ago|reply
Interesting perspective.

With respect to technical debt reflecting organizational problems:

I've always been surprised at how much internal resistance (management and other programmers) I've faced when trying to pay down or eliminate technical debt, regardless of whether it was my code or other people's code. ( For the record, I've written plenty of bad code in my day. )

In the past when I was foolish enough to try and be deferential, I was given excuses like 'yeah, we don't want that kind of churn in version control' and 'we have to maintain compatibility' even when compatibility isn't an issue at all. This, more than anything taught me that it's better to seek forgiveness than permission.

Love the concept of building technical wealth. That's a great way to put it.

[+] beat|9 years ago|reply
I just saw a great term on a friend's Facebook today... "refracturing". That's when you fix bugs by introducing new bugs.
[+] organsnyder|9 years ago|reply
Not appropriate for every environment, but I've heard "refucktering" used to describe this.
[+] programminggeek|9 years ago|reply
There will always be technical debt because of Software Gravity(http://brianknapp.me/software-gravity/) and the Katamari Damacy Effect(http://brianknapp.me/katamari-damacy-effect/). Both drive the natural Evolution of Software(http://devblog.procore.com/dev/evolution-of-software-applica...)
[+] biocomputation|9 years ago|reply
Yes, and systems that one might refer to as 'disruptive' often get traction because they don't have the same gravitational pull as the incumbent. Maybe magnetism is a better term because feature richness often correlates with complexity, and that can attract and repel people.
[+] rhizome|9 years ago|reply
The Katamari Damacy Effect is the same as Creeping Featurism.
[+] mooreds|9 years ago|reply
It was interesting. Too bad the company profiled doesn't really value the developers--if you look at their careers page, they pay 110k for lead devs, and 90k for senior devs: http://corgibytes.com/careers/ . I respect them for stating it up front and I know they are 100% remote, but those salaries seem a bit low to me.

But that's just ad hominem. I think working code is almost never worth a rewrite. See "Things you should never do, part 1" for an old chestnut on the same topic: http://www.joelonsoftware.com/articles/fog0000000069.html

[+] 20years|9 years ago|reply
I looked at the careers page on Corgibytes out of curiosity. Their hiring approach is very refreshing.
[+] morgante|9 years ago|reply
I really take issue with this chart: http://s3.amazonaws.com/marquee-test-akiaisur2rgicbmpehea/H4...

In what world are old text messages or Twitter posts better technical artifacts than commit messages or tests? The latter are directly tied to the code expression, include a clear history, and are easily discoverable when looking for the source of an issue or the explanation.

This is so wrong that I'm wondering if I'm reading the chart incorrectly.

[+] chetanahuja|9 years ago|reply
"Break monolithic apps into micro-services that are lighter weight and more easily maintained."

Does anyone has any actual evidence to support this blanket claim, especially the "more easily maintained" part of the claim? My experience is quite the opposite. More separate processes communicating over unreliable network links there are, higher the likelihood of failures and mysterious performance issues. More succinctly, complexity of system goes as N^2 where N is the number of processes communicating over unreliable links (note, my use of the word "unreliable" is very intentional here).

[+] partycoder|9 years ago|reply
Code is not an asset, is a liability. Code that you own you need to maintain.

There's only so much code that you can realistically own and maintain. If you are smart, you will seek ways of owning strictly what you need, which is the code closer to the core of your business.

If there is code that you need and is not close to the core of your business and does not provide a competitive advantage, open source it.

The worse code always comes from lack of visibility and accountability. Open source promotes visibility and accountability and keeps things working and clean.

A culture of accountability and strong technical skills attracts talent and keeps the company competitive.

[+] perseusprime11|9 years ago|reply
All these articles are fine and dandy but I would like to see more pragmatic articles on how to reduce technical debt. A lot of books have been written aroumd software patterns, service orientation, micro services, etc but none of them really address how to minimize technical debt over the life of software. Also not covered properly is what accounts for texhnical debt? For example, I have fee classes that have good unit tests, interfaces, proper seperation of concerns but performs really bad with 1000 concurrent users. So this goes back to how do we accurately define technical debt?
[+] kelvin0|9 years ago|reply
This is a very good article, and I can certainly relate to the points made about legacy code. The problem I had was to be able to quantify the fact that productivity of the programming team was going downhill (legacy code, little to no tests) and be able to make a case to management. I felt like the canari in the coal mine.

Another key revelation from this article was that there are 'Makers' and 'Menders' ... At heart I think I am a maker, but sometimes need to be a mender by necessity and this has a huge impact on my 'happiness' levels.

[+] am8|9 years ago|reply
"No thanks I don't want to learn more" on the spam pop-up to close it.

Of course I want to learn more. Not on this site though. Using a guilt trip way to close a pop-up made me exit the site immediately.

[+] stcredzero|9 years ago|reply
This analogy works quite well. Basically, you have to look at all of the costs of the current edifice. Maybe it costs nothing on paper to keep the ramshackle old house the way it is, but the impression it gives to visitors is a cost. Likewise, if you think of new hires as "visitors" was well. On the other hand, a building that's well designed can have a positive effect on the public perception of an organization and the mental state of the people working within it. The same thing goes for code.