Tech Debt, Leverage, and Grandma’s Envelope

In my previous posts about tech debt, I focused on how we can help organizations remember their debts, and on understanding how tech debts are funded and paid back.

Photo credit: Friends of the Earth International (Flickr)

Photo credit: Friends of the Earth International (Flickr)

These topics hit a raw nerve with coders and testers. Those in the trenches often feel very keenly the cost of doing things in a messy way, and it’s common for them to worry that others don’t “get it.”

They’re not wrong to worry.

However, today I’d like to put on my executive hat and discuss tech debt from a perspective that code jockeys sometimes miss, because blindness is not just an executive disease.

Debt as Leverage

When you hear the word “leverage” in business circles, people are talking about debt: a “highly-leveraged” firm is one financing large portions of its strategy through debt; “leveraged buyouts” are transactions where the buyers borrow vast sums of money from a risk-taking lender to take a company private.

Technogeeks (like me): business people are not dumb. Why did they settle on this metaphor of debt as leverage?

The answer is that debt can allow a company to concentrate enough capital in a short enough timeframe to make high-impact strategic moves that would otherwise be impossible. It’s an enabler and multiplier.

Another take on leverage. Image credit: xkcd.

Debt is a fundamental machine in the business toolkit, just as levers are a fundamental machine for mechanical engineers. Almost all businesses use debt to some extent. If a CEO can borrow capital at 9% and produce 12% ROI with it, and Continue reading

How to turn coding standards into epic fails — or not

Yes, a restaurant really displayed this sign. I doubt it influenced anybody’s behavior…

Some attempts to influence the behavior of other people succeed; others are doomed from the get-go.

Coding standards are usually written because we want to influence the structure or style of code produced by engineering teams. Sometimes they’re helpful; more often they’re ignored and forgotten; occasionally they provoke fireworks or bitter resentment.

I’m not sure there’s a guaranteed formula for success, but there’s a guaranteed formula for failure; let’s cover that first, and then see what helpful suggestions we can derive.

How to turn coding standards into epic fails

1. Micromanage.

Leave no room for personal style and creativity. Make no attempt to distinguish between meaty issues and utter trivialities. State all rules in absolutes; allow no exceptions. Announce enforcement in code reviews. Bonus points if you actually follow through on the threat, and double bonus points if you display some other developer’s code in front of the team as an example of egregious violations.

“Always put a space between an identifier and a curly brace, except in nested struct initializers where the first member is a string literal (other than NULL) or a #define’ed constant.”

“Begin every function with a comment that specifies the name of the coder, the date the function was last modified, the purpose of the function, an annotated history of how the function has evolved over time, a list of functions called by your function, your zodiac sign, and the names of all parameters. Make sure that parameters are listed alphabetically (case-insensitive), with a blank line between each, and the explanatory text after the param name indented 8 – (len(param name) mod 4) spaces.”

Continue reading

A Quibble With Martin’s “Optimize Later” Notion

In Refactoring, Martin Fowler (a brilliant engineer whom I greatly admire) articulates an idea that I have heard from smart engineers for a long time: first make it work, then make it fast. He puts it this way:

“Until I profile I cannot tell how much time is needed for the loop to calculate or whether the loop is called often enough for it to affect the overall performance of the system. Don’t worry about this while refactoring. When you optimize you will have to worry about it, but you will then be in a much better position to do something about it, and you will have more options to optimize effectively.”

I mostly agree. Certainly, premature optimization can cause lots of problems (pollute an otherwise clean design, overvalue corner cases, dilute conceptual integrity), and profiler-driven optimization (science, not black magic!) is the way to get the best results. Donald Knuth famously observed that “premature optimization is the root of all evil” — a bit over the top, maybe, yet true often enough to give me fits.

But implicit in Fowler’s advice are the following problematic notions:

  • Optimization is a discrete activity from ordinary coding. Especially, it is discrete from refactoring.
  • Between the time that you code an original or refactored version, and the time you optimize, the existence of unoptimized code will have negligible effect on how the rest of the code’s ecosystem evolves.

The flaws in the first notion should be obvious; optimization often requires concommitant refactoring. I won’t beat that dead horse here. The second idea, however, deserves further comment.

Sometimes the only time to optimize is before decisions get made :-). Image credit: xkcd

Before you get around to optimizing, what happens if programmers go looking for an API that does X, find your works-correctly-but-suboptimally function, and wrinkle their nose. “Code smell!” they cry. And they write their own function that does a binary rather than linear search, etc. They don’t have time to investigate whether the original version was coded that way for a reason (and thus should simply be refactored); they just need something that works AND that is fast, and your function doesn’t cut it.

I have seen this happen over and over and over again. Late optimization, while smart in many cases, must be managed (communicated, commented, evangelized, trained, reinforced, audited, planned for) carefully or else it will provoke a lot of NIH and contempt from (ironically) less savvy programmers. Result: more guck that needs refactoring.

Action Item

Find a notoriously sub-optimized function in your code. Study how its existence in non-optimal form has influenced how other code has evolved.