You take a step across a sidewalk.
Meanwhile, an ant starts across the same sidewalk. It’s a rough sidewalk, the kind with little rocks everywhere. The ant walks around the first bump, then the second. It climbs up a rock and steps across a valley. Then it climbs over a bump, around another — hundreds of bumps. As it crosses the same section of sidewalk, the ant travels a much longer distance than you do.
You went 1 step, say half a meter. Meanwhile the ant travels in millimeters, and it went over and around these bumps for at least a thousand millimeters, a full twisty turny meter, twice as far as you traveled.
Software development feels like this.
“Add a flag for public/private posts,” you say. That’s one step from an external perspective. Then I start implementing it. I decide where to put the flag in the UI. I decide how to represent it in code (as an enumeration), and where and how to store it. Can people update the flag? If the update fails, how do I tell them?
These are some of the bumps provided by the feature. Then there are bumps specific to programming languages and frameworks: how do I get an enumeration (in the code) into the database (as a string)? How do I make a little slider display with a label? How do I set the slider to “on”?
Then there are bumps unique to my particular codebase. How do I make it not display on this other screen that reuses some of the same code? How does this feature interact with the post-deletion feature? Do I need to update reports to reflect the new attribute? How many random test failures and latent bugs am I going to trip over meanwhile?
The distance from here to a new feature gets longer as you get deeper into the details.
This is a coastline problem. How long is a coastline? The answer depends on the size of your ruler. The closer you look, the more details you follow, the more length.
What can we do about this?
There are two ways to decrease the distance we have to travel. One is: take bigger steps. In software, this corresponds to using pieces built by other people. Use software-as-a-service when you can. Use libraries and frameworks maintained by others.
A good abstraction lets you traverse a few well-documented bumps and get somewhere. Like, define your queues and their storage limits and what happens when they overflow. Leave the intricacies of distributed queueing to your kafka-as-a-service provider.
The other one is: smooth the road before you walk on it.
That increase in distance with detail differs among software.
“Nature’s forms or patterns are irregular (or rough) and fragmented.”Michael Turvey, Lectures on Perception
How rough or fragmented is a measurable quantity. The example in Lectures on Perception: for a particular swath of vegetation, a bug that’s 10x smaller travels 2.76x farther from one point to another. That is calculated from a property of the vegetation surfaces called fractal dimension.
(Note: “fractal” here is not only those infinitely repeated patterns that we call fractals. Those are an extreme of roughness. Here, “fractal” applies to everything rough, to varying degrees.)
The rougher and more intricate the leaves and stems, the higher the fractal dimension, and the bigger the disadvantage of the smaller bugs.
Some software is easier than change than others. For instance, if I try to split a sentence into words in straight C, I gotta allocate memory and move pointers around and loop and and and. In Ruby,
sentence.split. At least metaphorically, C has a higher fractal dimension than Ruby. Tasks blow up into more and more tasks, and those tasks are harder to get right.
Even in the same language, some codebases are hairier than others. How well is the code organized for my purposes? That makes a big difference to how many bumps I’ll have to traverse. As features accumulate, so do gotchas. Fractal dimension naturally increases, so doing a thing in a new codebase is far easier than the same thing in an old codebase.
Refactoring smooths the code, like straightening out a kink in the stem. This brings the goal closer to us right now, and it decreases the detailed distance of future travel as well.
If you’re tired of the term “technical debt,” try fractal dimension of the code. Higher fractal dimension means problems look harder the closer we look at them, and travel times are highly uncertain. Lowering the fractal dimension brings every destination nearer to us, in the detailed level where software develops.