Mindful coding: Purpose and intention

Source: var0.xyz
17 points by var0xyz a day ago on lobsters | 7 comments

Mindful coding: Purpose and intention

"Mindful coding" sounds a bit provocative, maybe even a little clickbaity, I know. I don't mean that you should focus on your breathing while you type, or become acutely aware of every movement of your fingers.

What I mean is simpler: be mindful of the intent of the code.

Programming languages already give us a vocabulary for describing actions. We can iterate over a list, call a function, assign a value, raise an exception. But the interesting question is often not what the code is doing. It's why.

That distinction is easy to miss because the mechanics are right there in front of us. A for loop tells me that we're iterating. It doesn't tell me why those items need to be visited, or what role that iteration plays in the larger operation. Good code fills in that missing context—not by explaining every line, but by making the purpose of the code apparent.

Names are more than labels

One of the simplest ways we communicate intent is by naming things.

A value of 5 tells me almost nothing. A constant called MAX_RETRIES tells me that the number has a particular role: it represents a limit on how many times an operation should be attempted. The name gives the value a reason for existing.

This is one reason naming is so difficult. We often joke that the hardest problems in computer science are 2: naming things, cache invalidation, and off-by-one errors. The joke works because naming is genuinely hard, sometimes we haven't figured out what a piece of code is for well enough to give it a good name.

Recently, I had a discussion with a colleague about extracting some code into a function. We could have done it. The extraction would have made the surrounding code shorter. But then we struggled to come up with a name for the new function.

That made me stop and ask a different question: why are we extracting this in the first place?

The problem wasn't that we hadn't found the right name, it was that there wasn't a meaningful concept to name. We had simply drawn an arbitrary boundary through the code. We weren't separating one concern from another, encapsulating a coherent piece of logic, or creating something reusable. We were just moving some lines somewhere else.

The difficulty of naming was exposing a problem with the design.

When the name exposes the abstraction

This is where naming becomes more interesting than just choosing readable identifiers. A name can tell you that the abstraction itself is wrong.

Imagine a function whose name effectively has to be something like validateAndStore. Maybe that's perfectly reasonable in some context. But if the function validates input, stores it, and also decides how an HTTP error should be returned, we have a stronger signal that several different concerns have been pushed together.

The problem isn't that validateAndStore is a bad name. The problem is that the name is accurately describing an abstraction that is doing too much.

Good abstractions give us meaningful things to name because they correspond to meaningful concepts. When we have to invent a name for an arbitrary slice of implementation, the struggle can be a symptom rather than the disease.

So when you're stuck on a name, sometimes the answer isn't to search for a better word. Take a step back and ask: what concept am I actually trying to name? And if there isn't one, perhaps there shouldn't be a boundary there at all.

Code tells you what. History tells you why.

The same distinction appears outside the code itself.

Consider a commit message. It's common to write messages such as "Add validation module" or "Introduce retry logic." These aren't necessarily wrong, but they're often not very useful. The commit already contains the code. If I want to know what changed, I can inspect the diff.

The more valuable question is why did we make this change?

Maybe we discovered a bug. Maybe users were running into a particular failure. Maybe the old implementation worked under normal circumstances but broke under a condition we hadn't anticipated. Maybe we tried another approach and discovered that it didn't work.

That information isn't necessarily present in the code. It is part of the history of the code.

A useful commit message therefore doesn't merely narrate the diff. It preserves the reasoning that led to it. Years later, when someone asks why this apparently strange piece of code exists, the commit history can provide an answer.

Comments shouldn't repeat the code

Comments have the same problem.

A comment saying:

x = 5  # assign 5 to x

doesn't add anything. The code already tells us that.

A useful comment explains something the code cannot easily express: why that particular value is necessary, why an apparently unnecessary operation must remain, or why a seemingly obvious optimization should not be attempted.

For example, if a piece of code looks strange because of a bug we previously encountered, a comment can preserve that context:

# Do not optimize this away. This looks redundant, but removing it
# reintroduces the race condition described in issue #1234.

The exact wording doesn't matter. The important thing is that the comment tells the reader something they couldn't simply learn by reading the code. The answer isn't necessarily a giant comment explaining the entire system. A reference to the relevant issue, discussion, or piece of documentation may be more useful.

Intent is information

This is what I mean by mindful coding. It isn't about writing more comments, longer names, or more elaborate abstractions. In fact, sometimes the most intentional thing you can do is not add another abstraction, comment, or layer.

It's about being conscious of the information your code communicates. The code itself is usually good at telling us what happens, it's "the support structure" around the logic, such as names, boundaries, comments, and history that can tell us why it happens.

And that "why" is often the part that future readers actually need. It explains why a value exists, why a function is a coherent concept, why an abstraction has a particular boundary, why a strange-looking piece of code must remain, or why a change was made in the first place.

When those things are intentional, the code becomes easier to understand without needing more explanation. When they're arbitrary, we often feel it: the name doesn't fit, the abstraction doesn't quite make sense, and the comments have to explain things that should have been obvious from the design.

So the next time you're writing code and find yourself wondering what to call something, ask yourself a more fundamental question:

Why am I struggling to find a name?

The answer might reveal that this thing should not exist, that's why there's no name for it.


I made a video version of this argument, if you'd rather watch it: Mindful coding: Purpose and intention.

Thanks for reading.