-- Walter W. "Red" SmithWriting is easy. All you do is sit in front of a typewriter keyboard until little drops of blood appear on your forehead.
I cut my thumb open the other day while making dinner. My wife was sitting on our blue fabric couch when she heard me yelp with pain and drop the knife. She turned just in time to see me rush to get my hand under the water from the sink. The water stung and cooled the cut while she reached for the bandaids and I watched more and more of my blood go down the drain.
It took a long time to heal. The cut extended, on the outside edge of my thumb, from fingertip to the first knuckle and for a while there was a great piece of dead skin wanting to fall off. But I was too afraid to pull on it because I felt like it may restart the bleeding. So, I kept it under bandaids for a few days until it began to heal of its own accord.
The cut is healed now, but I remember the sting of it. I can remember the very moment it was opened up and blood poured out bright red onto my thumb and then into the kitchen sink. I remember the low throbbing after wrapping it in bandages and the occasional jerk of pain when I hit the wrong place on my pockets or the book I was reading.
The point is, bleeding hurts.
At the risk of sounding over-dramatic, I'm pretty sure the first word of Walter Smith's quote could be substituted with "software development". I've bled over difficult bugs. I've bled over scaling problems. I've bled over cloud architectures, function names, and interface designs.
But alas, the world does not respect the bleeding software artist despite the evidence that it should. The world respects quick lead times, useful products, and skyrocketing ARR. And these things are clearly not the result of those who dawdle on making code into works of art, but instead these achievements belong to those who crank out features and ship product. But people in the know know that this is a false dichotomy - those who bleed over code ship faster and better than those who don't.
Spend any time in the software industry and you will learn that money and code are bound by the nuclear force. It takes enormous sums of money to create software systems, and when those systems provide some value to some customer somewhere, those very systems can generate ten or one-hundred-fold the money spent to create them. You have to spend money to make money, as the saying goes.
The big names in software money-making have changed our lives on a minute-by-minute basis for better or worse and so the impact of software, along with knowledge of how much money it can generate, has slipped into our milieux. As a result, most any software engineer can recall stories of people who only seem to be interested in money when speaking with them.
The software engineers who truly love their craft, those who bleed over it, are more likely to have these conversations since software engineering composes a greater portion of their thoughts and dialogue; therefore, people are more likely to know that they can code; and therefore more people are likely to ask them about it. But the great irony is that many of these same developers couldn't care less about money; after all, they make enough of it. They want to make art. They understand that it's the quality of software that counts. They are great developers, and they bleed over their code.
What It Means to Bleed
I recently began a new project, separate from my work, and purely as a test of endurance. It's a simple terminal-based game. It hardly has a UI and it hardly has any features in its current state. The goal of the project is simple, I want to find out how much code I alone can stuff into a single project before it becomes unbearable.
I still haven't found the limit. The current count is 3,664 lines of TypeScript. Bear in mind, that's how many lines are
in the src
folder. Including the node_modules
folder in that count would be cheating.
Periodically, I tinker with the project after work hours. I'll think of the next feature I want to add and begin writing tests. And evening after evening come and go, and test after test pass until the feature is complete. For a while, I sit back and appreciate my work. Then, I put the project aside for a few days to think about the next feature I would like. And so the cycle begins anew.
But the other day I had a burst of energy and instead of implementing the next feature I went to work refactoring a bit of code I knew needed to be improved. I'm embarrassed to say it, but on my personal projects refactoring is not the typical activity. During the refactoring I realized I cared about the quality of the code. Code that no one would likely ever see. Code that would make me zero dollars. Code that was not a requirement, but simply an exercise. Yet, I found myself obsessing over it. I cared about code for the code's sake. I was starting to bleed over it.
That evening I found myself clumsily groping for the ethereal; and coming up short with a pile of improved, but not yet beautiful, code.
Here's what I started out with:
export async function interactWithDoor(
gameState: GameState,
uiController: UiController,
objectCoords: Coords
): Promise<GameState> {
const theDoorInQuestion = findDoorByCoordinates(gameState, objectCoords)
if (!theDoorInQuestion) return gameState
if (theDoorInQuestion.open) {
return assocPath(
['currentScene', 'doors', 0],
{ ...theDoorInQuestion, open: false },
gameState
)
}
const playerKeys = filter(
(inventoryItem: InventoryItem) => inventoryItem.type === 'key',
gameState.player.inventory
)
const playerHasKeyForDoor =
filter(
(key: Key) => key.id === theDoorInQuestion.keyId,
playerKeys as Key[]
).length > 0
if (
!playerHasKeyForDoor &&
!theDoorInQuestion.open &&
theDoorInQuestion.locked
) {
theDoorInQuestion.open = false
theDoorInQuestion.locked = true
return gameState
}
// TODO: even though collidable gets set to false here I still can't walk through it.
theDoorInQuestion.open = true
theDoorInQuestion.locked = false
theDoorInQuestion.symbol = '0'
theDoorInQuestion.collidable = false
return gameState
}
And here's how it ended:
export async function interactWithDoor(
gameState: GameState,
uiController: UiController,
objectCoords: Coords
): Promise<GameState> {
const theDoorInQuestion = findDoorByCoordinates(gameState, objectCoords)
if (!theDoorInQuestion) return gameState
if (theDoorInQuestion.open) {
closeDoor(theDoorInQuestion)
return gameState
}
if (playerCanOpenDoor(theDoorInQuestion, gameState)) {
openDoor(theDoorInQuestion)
return gameState
}
return gameState
}
The satisfaction of simplifying such a mess into, well, less of a mess, has not been lost on me. In fact, I consider this renewed function an achievement in clarity for me. Yet there is still something missing; and an ever-longing goal in the distance calls me. I want to achieve beauty and I'm not sure I have.
But, you see, at some point, code is good enough. There is a plateau where further improvement is no longer necessary; a point where the next developer will surely be able to understand the intentions of the writer. Unfortunately, too many developers neglect to even come this far and leave code simply as they wrote it the first time. Sometimes, I am one of those developers. And perhaps the reason we do this is because we don't know where that plateau lives. And the thought of hiking aimlessly towards improvement with no end in sight breeds in us guilt and shame for wasting time. The only reason I didn't feel guilt and shame during the time I took with my example is because it didn't matter - it was my code. I was making it for code's sake. At work, it's a different story.
But all that guilt and shame for wasting time improving the business's code is nonsense. Quality is an achievement - even when it's business time.
I can hear managers groaning.
Bleeding Accelerates the Business
If you don't believe me, don't worry - I have an objective source to back up this claim. But if you're a developer, perhaps it would be best for you to make an attempt at achieving high quality in some small bit of code first. Try it on a side project away from work and see if you don't relish the experience. You may disagree, but I think finding the right names, the right flow, and the right shape of some function is extremely satisfying.
But back to the objective source - Accelerate. Accelerate by Nicole Forsgren, PhD, Jez Humble, and Gene Kim is now a staple piece of literature in the software industry. Thanks to this book, we have data to back up claims about which practices lead to higher business success in software. This data is remarkably difficult to come by, and so this book is a rare treasure and, as far as I know, the only of its kind.
Chapter 4 of Accelerate discusses technical practices which increase organizational performance. Among those practices mentioned in the chapter are loosely coupled architectures, automated tests, and test-driven development.
Accelerate didn't directly say that spotless code leads to higher business performance. However, loosely coupled architecture, automated tests, and TDD all make it clear - the code matters. Each of those practices is about the code itself, the very nuts and bolts. These practices rely on having clear, maintainable code. Therefore, clear, maintainable code, increases business performance.
If you had any other doubts, take this quote from the book into consideration:
-- Accelerate, Chapter 2: Measuring Performance, Page 20These results demonstrate that there is no trade-off between improving performance and achieving higher levels of stability and quality. ... much dogma in our industry still rests on the false assumption that moving faster means trading off against other performance goals, rather than enabling and reinforcing them.
Experience Agrees
Numbers and evidence aside, think of your own experiences as a developer. That project that nobody wanted to touch, why was it so bad?
Every time I've seen a project in this sorry state, it's because of a few simple flaws. First, there were no tests. And second, the code was never refactored, only added upon. And it continued to get added on without any refactoring for so long that in a few years time it turned into a junk-yard where the slightest misstep is likely to put a shard of glass through your foot. Nobody wants to walk there.
But, I believe this can be prevented. Perhaps if we had more developers willing to bleed over the code we could avoid these situations more often. Bleeding developers will write tests, they'll think about names and structure, and they'll worry about the readability. A bleeding developer does as Arthur Miller said a writer must do:
The writer must be in it; he can't be to one side of it, ever. He has to be endangered by it. His own attitudes have to be tested in it. The best work that anybody ever writes is the work that is on the verge of embarrassing him, always.
So, bleed. Be in your code and endangered by it. Be so confident in it that if it didn't work you'd be embarrassed. Work on the edge of your ability and test your mettle in it. Bleed. For the sake of code, for the sake of the company, for the sake of your career.