Mindful coding: Purpose and intention
Mindful coding: Purpose and intention
正念编程:目的与意图
2026-08-09
“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. “正念编程”(Mindful coding)听起来有点挑衅,甚至可能有点标题党,我明白。我并不是说你在打字时应该专注于呼吸,或者敏锐地意识到手指的每一个动作。我的意思更简单:要留意代码的意图。
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.
编程语言已经为我们提供了描述动作的词汇。我们可以遍历列表、调用函数、赋值、抛出异常。但有趣的问题往往不是代码在做什么,而是为什么这样做。这种区别很容易被忽略,因为代码的运行机制就摆在我们面前。一个 for 循环告诉我我们在进行迭代,但它并没有告诉我为什么要访问这些项目,或者这次迭代在整个操作中扮演了什么角色。优秀的代码填补了这些缺失的上下文——不是通过解释每一行,而是通过让代码的目的变得显而易见。
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.
我们传达意图最简单的方法之一就是命名。数值 5 几乎什么也告诉不了我,但一个名为 MAX_RETRIES 的常量则告诉我这个数字有一个特定的作用:它代表了操作应尝试次数的上限。名称赋予了数值存在的理由。这也是命名如此困难的原因之一。我们常开玩笑说计算机科学中最难的两个问题是:命名、缓存失效和“差一错误”(off-by-one errors)。这个笑话之所以成立,是因为命名确实很难;有时我们还没完全搞清楚一段代码的用途,自然也就无法给它起一个好名字。
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.
这就是命名变得比仅仅选择可读标识符更有趣的地方。一个名称可以告诉你抽象本身是错误的。想象一个函数,其名称实际上必须是类似 validateAndStore 这样的词。在某些上下文中,这可能是完全合理的。但如果该函数既验证输入、存储数据,又决定如何返回 HTTP 错误,那么我们就有了一个强烈的信号:几个不同的关注点被强行挤在了一起。问题不在于 validateAndStore 是个坏名字,而在于这个名字准确地描述了一个承担了过多职责的抽象。好的抽象为我们提供了有意义的命名对象,因为它们对应着有意义的概念。当我们不得不为一段随意的实现片段编造名称时,这种挣扎可能只是症状而非病灶。所以,当你卡在命名上时,答案有时不是去寻找一个更好的词,而是退后一步问自己:我到底想命名什么概念?如果没有,也许根本就不应该在那里划定界限。
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. 同样的区别也存在于代码之外。以提交信息(commit message)为例。人们常写诸如“添加验证模块”或“引入重试逻辑”之类的信息。这些不一定错,但往往没什么用。提交本身已经包含了代码,如果我想知道改了什么,我可以查看 diff。更有价值的问题是:我们为什么要进行这次修改?也许我们发现了一个 bug;也许用户遇到了特定的故障;也许旧的实现在正常情况下运行良好,但在我们未预料到的条件下崩溃了;也许我们尝试了另一种方法却发现行不通。这些信息不一定存在于代码中,它们是代码历史的一部分。因此,一条有用的提交信息不仅仅是描述 diff,它还保留了导致修改的逻辑推理。多年后,当有人问为什么这段看起来很奇怪的代码存在时,提交历史就能提供答案。
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:
注释也有同样的问题。像 x = 5 # 将 5 赋值给 x 这样的注释毫无意义,代码已经告诉我们了。有用的注释解释了代码难以表达的内容:为什么那个特定的值是必要的,为什么一个看起来多余的操作必须保留,或者为什么一个看似明显的优化不应该尝试。例如,如果一段代码因为我们之前遇到的 bug 而看起来很奇怪,注释可以保留该上下文:
# Do not optimize this away. This looks redundant, but removing it
# reintroduces the race condition described in issue #1234.
# 不要优化掉这段代码。它看起来多余,但删除它会重新引入 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. 措辞并不重要,重要的是注释告诉了读者他们无法通过阅读代码直接获知的信息。答案不一定是一段解释整个系统的长篇大论,引用相关的 issue、讨论或文档往往更有用。
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. 这就是我所说的“正念编程”。它不是关于写更多的注释、更长的名称或更复杂的抽象。事实上,有时你所能做的最有意识的事情,就是不去增加额外的抽象、注释或层级。它是关于意识到你的代码所传达的信息。代码本身通常很擅长告诉我们发生了什么,而围绕逻辑的“支撑结构”(如名称、边界、注释和历史)则能告诉我们为什么会发生。而那个“为什么”,往往才是未来读者真正需要的部分。