When good code is important and when it’s not

by Jason Swett,

Tollways

All code has a maintenance cost. Some code of course is an absolute nightmare to maintain. We would say its maintenance cost is high. Other code is easier to maintain. We would say its maintenance cost is low, or at least relatively low compared to worse code.

When thinking about good code and bad code, it’s worth considering when exactly code’s maintenance cost is incurred. We might refer to these events as “tollways”. We can’t travel these roads without paying a toll.

Tollway 1: when the code is changed

For any particular piece of code, a toll is incurred every time that code needs to be changed. The size of the toll depends on how easy the code is to understand and change.

Tollway 2: when the code needs to be understood in order to support a change in a different area

Even if a piece of code doesn’t need to be changed, the code incurs a toll whenever someone it needs to be understood in order to make a different change. This dependency of understanding happens when pieces of code are coupled via inheritance, passing values in methods, global variables, or any of the other ways that code can be coupled.

We could put code into two categories: “leaf code”, which depends on other code but has no dependencies itself, and “branch code”, which does have dependencies, and may or may not depend on other code. Branch code incurs tolls and leaf code doesn’t.

Good code matters in proportion to future tollway traffic

When any new piece of code is added to a codebase, it may be possible to predict the future “tollway traffic” of that code.

Every codebase has some areas that change more frequently than others. If the code you’re adding lies in a high-change area, then it’s probably safe to predict that that code will have high future tollway traffic. On average it’s a good investment to spend time making this code especially good because the upfront effort will get paid back a little bit every time the code gets touched in the future.

Conversely, if there’s a piece of code that you have good reason to believe will change infrequently, it’s less important to make this code good, because the return on investment won’t be as great. (If you find out that your original prediction was wrong, it may be wise to refactor the code so you don’t end up paying more in toll fees than you have to.)

If there’s a piece of code that’s very clearly “branch code” (other code depends on it) then it’s usually a good idea to spend extra time to make sure this code is easily understandable. Most codebases have a small handful of key models which are touched by a large amount of code in the codebase. If the branch code is sound, it’s a great benefit. If the branch code has problems (e.g. some fundamental concept was poorly-named early on) then those problems will stretch their tentacles throughout the codebase and cause very expensive problems.

On the other hand, if a piece of code can be safely identified as leaf code, then it’s not so important to worry about making that code super high-quality.

But in general, it’s hard to predict whether a piece of code will have high or low future tollway traffic, so it’s good to err on the side of assuming high future tollway traffic. Rarely do codebases suffer from the problem that the code is too good.

Bad reasons to write bad code

It’s commonly believed that it’s wise to take on “strategic technical debt” in order to meet deadlines. In theory this is a smart way to go, but in practice it’s always a farce. The debt gets incurred but then never paid back.

It’s also a mistake to write crappy code because “users don’t care about code”. Users obviously don’t literally care about code, but users do experience the symptoms of bad code when the product is full of bugs and the development team’s productivity slows to a crawl.

Takeaways

  • A piece of code incurs a “toll” when it gets changed or when it needs to be understood in order to support a change in a different piece of code.
  • The return on investment of making a piece of code good is proportionate to the future tollway traffic that code will receive.
  • Predicting future tollway traffic is not always easy or possible, but it’s not always impossible either. Being judicious about when to spend extra effort on code quality or to skip effort is more economical than indiscriminately writing “medium-quality” code throughout the entire codebase.

3 thoughts on “When good code is important and when it’s not

  1. Jonathan Rochkind

    I like the idea of “tollways” and that good code matters in proportion to future traffic.

    > Rarely do codebases suffer from the problem that the code is too good.

    Right, the problem is not that the *codebase* suffers from “too good” code — that’s a contradiction, the better the code the better.

    The risk is that *the project* suffers from spending too much time on trying to make your code as good as possible, at the cost of slower advancement of the project; or going back and forth on what would make the code better (becuase sometimes you are wrong, and spending time to make the code better that doesn’t actually).

    If we acknowledge that no code is perfect, then that necessarily means there is such a thing as code that is “good enough” — because you could otherwise spend an unlimited amount of time refactoring any existing code better and better, leaving no time to make actual changes to the behavior of the code (adding features, or writing a different project).

    So the question is just when “good enough” is.

    While it might be rare (I’m not sure), I have *definitely* experienced projects that suffer from perfectionism and unbounded time trying to make the code better and better (and not necessarily succeeding — just as no code is perfect, no developer is either), there is a pitfall in that direction too. So rather than the encouragement to perfectionism in the second half of your post, I like returning to the guidance in the first half — knowing you have a limited budget for code perfection, focus the most on the code that has the most “traffic”.

    Reply
  2. Brad

    There is a high risk of low ROI on delivered code when code quality standards are ambiguous.

    There exists a certain breed of developer that will cut every corner, ignore all best practices, and drop duce after stinky duce commit into the companies repos for the sake of looking good for business on delivery times.

    They are usually not going to have to fix the problems they create, and if asked to do so will argue that it’s someone else’s problem.

    Just one of these turd burglars in your organization can cost you hundreds of thousands of dollars down the road.

    Setting global code quality standards for a repository using code quality analysis tools provides a bare minimum of protection from those who would run up technical debt on someone else’s charge card.

    The problem with attempting to foresee “Toolways” is that it requires precognition. It also provides lazy people that are rewarded for work avoidance the opportunity to argue their position.

    Just like refactoring and unit testing, quality code should be built into the estimate. S.O.L.I.D. and D.R.Y.

    Reply
    1. Jason Swett Post author

      I agree with basically all this. I would add that in addition to protecting against these problems with code analysis etc., which I think are good but limited in their helpful power, I would also use, when possible, the all-healing technique of employment termination.

      Reply

Leave a Reply

Your email address will not be published. Required fields are marked *