代码可读性与命名艺术:空格与命名的核心原则

本文深入探讨代码可读性的核心原则,强调空格使用和命名长度对代码清晰度的影响。通过具体代码示例对比,说明如何通过合理空格布局和恰当命名提升代码质量,避免过度注释,实现代码自解释性。

可读性与命名 » 代码简洁性

代码简洁性

可读性与命名

2011年1月25日 by Max Kanat-Alexander

许多人认为代码的可读性取决于使用的字母和符号。他们相信通过添加、删除或更改这些符号可以使代码更易读。在某种意义上是正确的。然而,根本原则是:代码的可读性主要取决于字母和符号如何占据空间

这意味着两件事:

  • 代码周围应有适当的空白。不多也不少。
  • 一行代码内部应有适当的空间来分隔不同部分。不同的操作通常应放在不同的行上。缩进应适当使用以分组代码块。

根据这一原则,实际上是代码的缺失使内容易读。这是生活中的普遍原则——例如,如果书中字母和单词之间完全没有空格,就很难阅读。另一方面,在晴朗的夜空中很容易看到月亮,因为有很多清晰的黑色空间不是月亮。同样,当代码中有适量的空间时,你可以轻松分辨代码的位置和内容。

例如,这段代码难以阅读:

1
x=1+2;y=3+4;z=x+y;print"hello world";print"z is"+z;if(z>y+x){print"error";}

而通过适当的行内、周围和行间间距,它变得易读:

1
2
3
4
5
6
7
8
x = 1 + 2;
y = 3 + 4;
z = x + y;
print "hello world";
print "z is" + z;
if (z > y + x) {
    print "error";
}

然而,也可能有太多或错误的空格。这段代码也难以阅读:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
    x            =          1+        2;
y = 3            +4;


  z = x    +      y;
print    "hello world"         ;
 print "z is " + z;
if (z  >     y+x)
 {        print "error" ;
        }

代码本身占据的空间应与其含义量成正比。

基本上,含义丰富的小符号使代码难以阅读。含义不多的非常长的名称也使代码难以阅读。含义量和所占空间应密切相关。

例如,这段代码由于名称太短而难以阅读:

1
2
q = s(j, f, m);
p(q);

这些名称所占的空间相对于它们的含义来说非常少。然而,使用适当大小的名称,代码块的用途变得更加明显:

1
2
quarterly_total = sum(january, february, march);
print(quarterly_total);

另一方面,如果名称相对于所表示的含义过长,代码再次变得难以阅读:

1
2
quarterly_total_for_company_x_in_2011_as_of_today = add_all_of_these_together_and_return_the_result(january_total_amount, february_total_amount, march_total_amount);
send_to_screen_and_dont_wait_for_user_to_respond(quarterly_total_for_company_x_in_2011_as_of_today);

这一原则同样适用于整个代码块和单个名称。我们可以用单个函数调用替换上面的整个代码块:

1
print_quarterly_total();

这比之前的任何示例都更易读。尽管我们使用的名称print_quarterly_total比其他名称稍长,但这没关系,因为它代表了比其他代码片段更多的含义。事实上,它甚至比我们的代码块本身更易读。为什么?因为代码块占据了大量空间,但实际含义很少,而函数为相同的含义占据了更合理的空间。

如果一个代码块占据大量空间但没有太多实际含义,那么它是重构的好候选。例如,这是一个处理一些用户输入的代码块:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
x_pressed = false;
y_pressed = false;
if (input == "x") {
    print "You pressed x!";
    x_pressed = true;
}
else if (input == "y") {
    if (not y_pressed) {
        print "You pressed y for the first time!";
        y_pressed = true;
        if (x_pressed) {
            print "You pressed x and then y!";
        }
    }
}

如果那是我们的整个程序,可能足够可读。然而,如果这位于大量其他代码中,我们可以这样使其更可读:

1
2
3
4
5
6
7
8
x_pressed = false;
y_pressed = false;
if (input == "x") {
    handle_x(x_pressed);
}
else if (input == "y") {
    handle_y(x_pressed, y_pressed);
}

我们可以通过简化为这样使其更可读:

1
handle_input(input);

在代码中阅读“handle_input”比尝试阅读上面的整个第一个块要容易得多,因为“handle_input”占据了适量的空间,而块占据了太多空间。但请注意,如果我们做了类似h(input)的事情,那将令人困惑且难以阅读,因为“h”太短,无法正确告诉我们代码在做什么。此外,handle_this_input_and_figure_out_if_it_is_x_or_y_and_then_do_the_right_thing(input)不仅会让程序员输入起来烦人,还会导致代码难以阅读。

命名事物

一位著名程序员曾说过,命名事物是计算机科学中最难的问题之一。然而,这些可读性原则为我们提供了一些关于如何命名的好线索。基本上,变量、函数等的名称应足够长以完全传达它是什么或做什么,但不应过长以至于难以阅读。

思考函数或变量将如何使用也很重要。一旦我们开始将其放入代码行中,它是否会使这些代码行相对于实际含义过长?例如,如果你有一个函数只被调用一次,单独在一行上,该行没有其他代码,那么它可以有一个相当长的名称。然而,一个你将在复杂表达式中频繁使用的函数可能应该有一个短名称(尽管仍然足够长以完全传达其功能)。

-Max

分享 点击在Facebook上分享(在新窗口中打开) Facebook 点击在LinkedIn上分享(在新窗口中打开) LinkedIn 点击在Hacker News上分享(在新窗口中打开) Hacker News 点击在Reddit上分享(在新窗口中打开) Reddit 点击在Threads上分享(在新窗口中打开) Threads 点击在X上分享(在新窗口中打开) X

29条评论 留下回复

Ahmed 说:2011年1月25日上午11:21 优秀的“空间编码原则”。我认为这是你即将出版的书中的一章。你可能需要更多示例,比如比较两段代码: 是编码 SELECT * FROM table WHERE x = y 更好 还是 SELECT * FROM table WHERE x = y 更好,为什么? 谢谢, Ahmed。 回复 抱歉

Ahmed 说:2011年1月26日下午12:19 你的两个示例看起来一样… 回复

Rob, Robot Vacuum 说:2012年2月13日晚上7:54 我也看不出太大区别。 回复

Max Kanat-Alexander 说:2011年1月26日下午12:23 嘿Ahmed!是的,我目前计划将其纳入书中,当然。 至于SQL间距风格,我们在Bugzilla项目中发现这种方法创建了最清晰的SQL: http://www.bugzilla.org/docs/developer.html#sql-style -Max 回复

Havvy 说:2011年1月25日上午11:51 你用语言表达了我潜意识里认为是真实的东西。为此,谢谢。 回复

Max Kanat-Alexander 说:2011年1月26日下午12:25 谢谢!是的,这是我所有博客的目标之一,就是准确陈述这些我们“只是知道”的事情,并通过这样做帮助我们更准确地理解它们,并能够与每个人交流。 -Max 回复

James Napolitano 说:2011年1月25日晚上11:13 我发现间距对可读性有很大影响的类似例子是对齐相似的代码行: firstX = rect.width + 5; lastX = rect.width + 50; firstY = rect.height + 10; lastY = rect.height + 20; 这在编写几行相关公式时特别有用;它让你几乎一眼就能看出它们之间的相似和不同之处。这样的代码几乎要求以某种表格格式呈现;如果你的IDE、代码编辑器或其他工具能为你做到这一点,那不是很好吗? 回复

ccr 说:2011年1月27日凌晨1:37 有些编辑器这样做。我知道TextMate做(Cmd-Alt-]),除非我的记忆真的很模糊,Emacs也给你这个选项。 回复

James Napolitano 说:2011年1月25日晚上11:34 哎呀,看起来代码标签不像pre那样保留空格,而且pre似乎不允许在评论中使用。(也许你可以在你的css中添加类似“code { white-space: pre }”的东西?也许为你的博客添加一个“预览评论”功能?)。 再次提供我的代码示例,空格转换为下划线: firstX_=rect.width_+_5; lastX=rect.width+50; firstY=rect.height+_10; lastY=rect.height+_20; 回复

Tweets that mention Code Simplicity » Readability and Naming Things – Topsy.com 说:2011年1月26日凌晨1:36 […] 这条推文被Robert Nyman, Frank Kleine提到。Frank Kleine说:代码简洁性:可读性与命名事物 http://bit.ly/hhxPLM […] 回复

Michael Campbell 说:2011年1月26日上午6:58 我从未理解这个“对齐”论点,尽管我一次又一次地看到它。它对我所做的只是让我的眼睛想垂直阅读代码,而其语义意义是水平获得的。我的代码不是列式的,我不明白为什么它应该这样格式化。 回复

Michael Chermside 说:2011年1月26日上午9:59 致Michael Campbell: 实际上,我认为你正好击中了这种垂直布局重要的确切原因——因为它使语义意义是垂直的而不是水平的时候变得清晰。 考虑给出的代码: firstX_=rect.width_+5; lastX=rect.width_+50; firstY=rect.height+10; lastY_=rect.height+_20; 从编译器的角度来看,我们发布了4个赋值语句,它们可能完全无关。但这不是代码的真正语义意义。代码的真正语义意义更接近“用一定的边距设置rect给出的点的所有4个边界”。 在真正表达力强的编程语言中,我们可能能够以不同方式编写这个…像这样: xyBounds = boundsWithMargin(center=rect, leftPad=5, rightPad=50, topPad=10, bottomPad=20); 我想我们都同意这更清晰,也不容易出错,但不幸的是,大多数时候我使用的语言不够强大,无法使用这种清晰的语法。将字段对齐在列中是一种穷人的方式,表示这些行是强相关的…实际上只是同一更大过程的不同部分。 回复

James Napolitano 说:2011年1月26日下午1:07 我同意,但即使有表达力强的语言语法,仍然会有一些情况你有几行强相关的代码,例如在你的boundsWithMargin函数的实现中,或在这种情况下: xyBounds1 = boundsWithMargin(center=rect1, leftPad=5, rightPad=50, topPad=10, bottomPad=20); xyBounds2 = boundsWithMargin(center=rect2, leftPad=0, rightPad=15, topPad=20, bottomPad=10); 我习惯编写很多数学公式;这是一个你经常有相似代码行的情况,看到它们之间的对称性很重要。 回复

Code Simplicity » Readability and Naming Things « Interesting Tech 说:2011年1月26日上午7:51 […] 在这里阅读更多 发布在未分类, 有趣, 科学, 科技 | 无评论 » […] 回复

Loup Vaillant 说:2011年1月26日上午8:51 我同意关于空白管理,但大多数时候我们不会偏离漂亮打印机的输出太多。 然而,我不同意你关于名称长度的标准。我的规则是将名称的长度与其使用频率和命名事物的范围相关联。 使用越频繁,名称越短。范围越短,名称越短。例如,循环索引可以很容易地是一个字母,因为它是一个常见的习惯用法,而且范围非常短(循环内部)。 有些东西含义丰富,但名称很短。map和fold是一个很好的例子,相当有意义,范围广(它们通常是标准库中的全局名称),但使用非常频繁。 现在是吹毛求疵:名称背后的复杂性和其使用频率之间存在非常强的负相关。所以你的规则大多会奏效。 回复

Max Kanat-Alexander 说:2011年1月26日下午12:30 嘿Loup。如果你看博客的结尾,我确实谈到了名称的使用频率。 我不同意“范围越短,名称越短”作为一般原则——有时甚至循环变量也需要更长的名称来消除歧义(尽管我同意这是一个不寻常的情况)。 “map”和“fold”实际上含义相对较少。为它们取一个短名称是可以的。 -Max 回复

Curt Sampson 说:2012年3月28日晚上11:49 我在“较小范围让你使用较短名称”这件事上与Loup一致;当你能在满屏文本中看到变量的每一次使用时,名称长于一两个字母有什么优势?那只是 clutter。我们为范围较大的变量使用较长的变量名,因为我们使用的变量上下文较少。 我也相当惊讶你会说“map”和“fold”含义很少;这在我看来就像说“加法”和“乘法”这些词含义很少。Map和fold是操作值集合的基本构建块。(诚然,许多程序员似乎不知道这一点,更喜欢像“for”循环这样的东西,这些循环产生更长、更复杂、更难以理解的代码。 cjs@cynic.net 回复

Readability and Naming Things « Interesting Tech 说:2011年1月26日下午1:03 […] 在这里阅读更多 发布在未分类, 有趣, 科学, 科技 | 无评论 » […] 回复

Michael Powell 说:2011年1月26日下午3:01 另一个常见的误解是可读性完全来自注释。 注释通常可能有用,但像标识符一样,它们应刚好足够长以传达重要含义。此外,它们应仅在确实需要澄清语句时使用。好的代码应 largely speak for itself。 当我看到代码中每个函数名上方有一个10行注释块,并且每隔一行有一个注释描述它在做什么时,我内心有点崩溃。那不是可读的代码。那只是冗长。实际结构在注释中丢失。 回复

Max Kanat-Alexander 说:2011年1月26日下午3:05 是的,有趣的是你提到那个。在我的书中,这整篇文章最初是一个段落,谈论空间如何重要。该段下面还有另一个段落,谈论注释通常只应解释为什么你做了某事,而不是什么它正在做。 我认为人们添加这么多无用的注释是 oversimplification 实际上导致复杂性的一个很好的例子,我在一段时间前的一篇博客中作为一个段落中的单个句子写过,但自那以后没有真正扩展过。 -Max 回复

Michael Powell 说:2011年1月26日晚上7:32 我 mostly 同意,但有时解释你在做什么是有用的。主要是在处理非常性能关键的代码片段时,你被迫以怪异和非直观的方式构建它以获得最大速度。此外,当你正在做特别复杂的事情时。在这些情况下,代码的实际功能——它做什么——可能不会立即明显,无论你的标识符名称和空白有多好。在这些情况下,解释你在做什么的注释,而不仅仅是你正在做什么,可能非常有价值。 我还发现注释有时对于分解有些笨拙的代码块很方便。当你有一个200行长的函数(有时不可避免)时,将其分解成几个块并在每个块前放置一个短注释,给出其基本目的,可以对可读性创造奇迹。在这种情况下,注释既是为了视觉上 spacing things out 和 breaking them up,也是为了实际内容。 但注释,像任何东西一样,可以很容易被过度使用,而且很多对良好实践大声疾呼的人似乎支持对我来说似乎疯狂的注释策略。他们让代码如此杂乱注释,以至于实际结构丢失。 作为旁注,我目前正在实现Perlin噪声函数(并在其工作后继续Perlin simplex噪声)。阅读Ken Perlin的参考实现是痛苦的。他会从这篇文章中受益匪浅。(参见这里:http://www.flipcode.com/archives/Perlin_Noise_Class.shtml) 回复

Max Kanat-Alexander 说:2011年1月26日晚上8:31 哦是的,我完全同意你的观点,解释经常是必需的。例如,在Perl中我们使用很多正则表达式,那些通常需要注释才能容易理解。 我也同意分解长函数。我肯定有过一些那样的函数。(尽管我通常至少能分解它们一点,但并不总是,这是真的。) 哈哈哈,Perlin算法太糟糕了。🙂 -Max 回复

Max Kanat-Alexander 说:2011年1月26日晚上8:32 好吧,哇,是的,我刚读了参考实现,那太糟糕了。 -Max 回复

Florian Over 说:2011年7月26日晚上11:42 也许你可以重新思考一下。我很确定这个话题有一些文化方面。在其他时代(例如中世纪,单词之间没有空格)和其他文化(日语任何人?)中,间距有不同的“默认值”。 这也取决于上下文。如果你作为计算机科学家编码(并理解自己),你有像数学一样的间距上下文。如果你作为程序员编码,你有不同的上下文。 参见(例如LISP类)语言中的编码约定,其中函数看起来像是直接从科学论文中取出的。 将其与Java代码约定进行比较。方式更多空白。 回复

Ricky 说:2011年11月17日上午7:18 对我来说,代码的可读性全在于命名事物。 这很烂: gU(2); 这规则: getUserById(2) 回复

Mike 说:2011年11月29日凌晨3:52 我同意!! 代码在这方面就像诗歌。 它在页面上的布局是美丽、艺术的一部分! 回复

O’Boise 说:2012年3月29日凌晨5:14 关于注释,我 sadly 处于群体中间。我倾向于在代码顶部解释基础知识,我写它的时间,以及我做了哪些更改,以防我需要稍后恢复。然后,通过尝试用十个词或更少注释代码块来说 next block of lines 将要做什么。我认为这很标准。 然而,在外包世界中经常溜走的一件事是用客户的语言命名你的变量。如果支持它的个人不理解你的语言,你的名称有多清晰都无关紧要。我有幸接管了一个xBase程序的支持,其中一名合同员工为一些严重的数据建模编写了几千行代码,但所有代码都用了匈牙利 notation,混合了英语和斯洛伐克语。绝对 brilliant 代码,但不得不用斯洛伐克-英语词典调试非常耗时。 回复

How do you Approach your Code? | Armedia Blog 说:2012年9月20日上午5:50 […] 另一方面,打开读起来像散文的软件是一种真正的乐趣。即使我不理解每个方法的细微差别或逻辑,我通过简单阅读变量、对象和方法名称就能得到要点。风格和缩进的一致应用使其在页面上看起来漂亮,也使逻辑结构明显。我钦佩这样的代码,因为其作者赋予它的关怀和工艺。可读性当然是进入高度 crafted、艺术代码的一个因素。这里是一篇关于代码可读性的很棒博客,有一些好和坏的例子:http://www.codesimplicity.com/post/readability-and-naming-things/。 […] 回复

Anubhav 说:2013年3月18日下午5:30 《Clean Code》书中关于命名约定的所有建议都很好。我最初对长但描述性的名称感到困惑,但它有它的优点,只有当你选择真正好的长名称形成句子时。 回复 留下回复取消回复

联系 关于 书:理解软件 书:代码简洁性 输入你的邮箱… 订阅 © 2025 版权所有。由The Fox提供支持。 管理同意 为了提供最佳体验,我们使用像cookies这样的技术来存储和/或访问设备信息。同意这些技术将允许我们处理数据,如浏览行为或本网站上的唯一ID。不同意或撤回同意,可能会 adversely 影响某些特性和功能。

功能 功能 始终活跃 技术存储或访问对于启用订阅者或用

comments powered by Disqus
使用 Hugo 构建
主题 StackJimmy 设计