编写可读代码的艺术:初·代码审美


前言:人生有很多第一次,作为一只不谙世事的小程序媛,第一次踏出校门,开始实习,感触良多,其中,颇为震撼的一点是,原来一直给人印象邋里邋遢的程序猿们,竟然在写代码上有那么多讲究,原来科学看待程序媛的方法真的不是“以貌取人”,而是“以代码取人”。本文为《编写可读代码的艺术》一书的读书笔记,并加上一些个人理解,用于记录,也用于分享共勉。为了编写可读代码,本书主要从四个方面对代码进行提升改进,此文主要记录第一部分,即更多的是对代码表明的一些改进,如名字命名,注释的书写等,并建立代码审美意识。之后还会有同系列的文章用来继续记录后面三部分内容。


编写可读代码何以称作艺术?

相信不少道行尚浅的小程序猿们如我一样,在技术的海洋里混乱遨游之际,只追求写出能够运行的代码,然后窃喜以为已然顿悟,但过一段时间回来再看,即使是自己的亲儿子代码,依旧不知所云。为什么呢?这里就要说到代码对人的友好性和可读性,优秀的代码具备良好的可读性,编写的代码要使其他人(或者一段时间后的自己)能在最短的时间内理解才行。写代码不仅要在乎宏观架构和整体设计,同时也要注重细节,可以说每个程序员每天更多接触的是是代码的细枝末节,有时一个不小心整个工程就会在一个不起眼的小错误中纠结度过。因此,这样看来,编码,不仅仅是一种技术,也是一门艺术

如何编写可读代码

  1. 简化命名、注释和格式的方法,使每行代码都言简意赅。
  2. 梳理程序中的循环、逻辑和变量来减小复杂度并理清思路。
  3. 在函数级别解决问题,例如重新组织代码块,使其一次只做一件事。
  4. 编写有效的测试代码,使其全面简洁,同时可读性更高。

起名字的学问

写代码如同写文章,每个函数每个变量都会有一个名字,以便需要时进行调用,好的名字能够让人一目了然,将信息装到名字里,把名字当做一条小小的注释,能够使得代码更加精简清晰。那么如何起名字,才能携带更多的信息呢?

1.选择专业的词

eg:GetPage(url)函数用于获取页面
Q:从本地缓存获取?从数据库获取?从互联网获取?
---> 从互联网获取:FetchPage()或者 DownloadPage()

2.找到更有表现力的词

可以从同义词中寻找,多思考。

单词 更多选择
send deliver, dispatch, announce, distribute, route
find search, extract, locate, recover
start launch, create, begin, open
make create, set up, build, generate, compose, add, new
3.避免像tmp和retval这样泛泛的名字
  • 好的名字应当描述变量的目的,或者它承载的值。
    eg:sum 变量,代表累加平方值
    Q: 谁的和?累加和?平方和?
    ---> sum_squares
  • 有时泛泛的名字也有意义,只在有特殊意义时使用,如 tmp 名字只应用于短期存在且临时性为其主要存在因素的变量。
  • 循环迭代器的升级
    eg: 像 i、j、k 这样的名字常被用于做索引或循环迭代器
    Q: 很容易在使用时写错,如 i 写成 j
    ---> 变量名_循环迭代器 eg:club_i, member_j, user_k
4.用具体的名字代替抽象的名字

eg:ServerCanStart() 函数,检测服务器是否可以监听某个给定的TCP/IP端口
Q: 名字太抽象,范围大
---> CanListenOnPort() 直接描述方法做的事情

5.为名字附带更多信息
  • 带单位的值
    eg1:包含十六进制的字符串id ---> hex_id
    eg2:如果变量是度量(时间长度或字节数)---> start_ms, delay_secs, size_mb, max_kbps, degrees_cw
  • 附带其他重要属性
情形 变量名 better变量名
一个“纯文本”格式的密码,需要加密后才能进一步使用 password plaintext_password
一条用户提供的注释,需要转义后才能用于显示 comment unescaped_comment
已转换为 UTF-8 格式的 html 字节 html html_utf8
以“uml方式编码”的输入数据 data data_urlenc
6.利用名字的格式来传递含义

对下划线、连字符和大小写的使用方式可以把更多的信息装到名字中。对不同的实体使用不同格式就像语法高亮显示的形式一样,能够帮助更容易阅读代码。例如:

格式 意义
CamelCase 表示类名
lower_separated 表示变量名
kConstantName 表示常量
MACRO_NAME 表示宏
offset_ 表示类成员变量

名字应该有多长

  1. 在小的作用域里可以使用短的名字。
    如果一个标识符有较大的作用域,那么它的名字就要包含足够的信息以便含义更清楚。
  2. 长名字也不用担心------编辑器上自动补全功能。
  3. 首字母缩略词和缩写的使用。
    原则:团队新成员能够理解名字含义。
  4. 丢掉没用的词
    eg: ConvertToString() ---> ToString()

准确命名(没有歧义)

  1. 使用 min 和 max 来表示(包含)极限
    eg:CART_TOO_BIG_LIMIT 是个二义性名字导致“大小差一”问题
    ---> MAX_ITEMS_IN_CART 表示包含极限的最大值

  2. 用 first 和last 来表示包含的范围


  3. 用 begin 和 end 来表示包含/排除范围


4、给布尔值命名
(1)通常来讲,加上像 is、has、can 或 should 这样的词,可以把布尔值变得更加明确
eg:bool read_password = ture;
Q: 需要读取密码?已经读取了密码?
---> need_password 或者 user_is_authenticated
(2)避免使用反义名字
eg:bool disable_ssl = false;
---> bool use_ssl = true;

代码审美-组织代码

三条原则:
(1)使用一致的布局,让读者很快就习惯这种风格;
(2)让相似的代码看上去相似;
(3)把相关的代码行分组,形成代码块;

整洁的代码能够提升浏览速度,和使用程度,相反如果代码结构凌乱,很影响代码的阅读和进一步重构。根据三条原则,可以总结出以下几条提高代码审美的Tips:

  1. 重新安排换行来保持一致和紧凑。
  2. 用方法来整理不规则的东西。如果多个代码块做相似的事情,尝试让他们有同样的剪影。
  3. 需要时使用列对齐。按列对齐可以让代码更加容易阅读。
  4. 选一个有意义的顺序,始终一直使用它。如:变量定义的顺序,如果一段代码中提到 A、B、C,那么另一段中使用同样的顺序。
  5. 把声明按块组织起来。不要把所有的方法都放到一个巨大的代码块中,应当用空行按逻辑把他们分组。
  6. 个人风格与一致性:一致的风格比“正确”的风格更重要。

注释的使用

什么地方需要注释?

注释的目的是尽量帮助读者了解的和作者一样多。当程序员写代码时,脑海中会有很多有价值的信息;当其他人阅读代码时,这些信息已经丢失,所见到的只是眼前的代码。

什么地方不需要注释?

(1)能从代码本身中迅速推断的事实。
(2)不要给不好的名字加注释-----应该把名字改好:一个好的名字比一个好的注释更重要,因为在任何用到这个函数的地方都能看到它。也就是好代码>坏代码+好注释

注释作用:记录你的思想

记录写代码时有过的重要想法。以下几种情况建议写注释:

  1. 对于为什么代码写成这样而不是那样的内在理由。
    eg:防止做无谓的优化而浪费时间; 解释为什么代码不那么整洁;
  2. 给常量加注释。是什么?为什么是这个值?通过阅读注释,有了调整这个值的指南。但有些常量不需要注释,名字本身已经很清楚了(eg: SECONDS_PER_DAY)
  3. 为代码中的瑕疵写注释。即代码需要改进时,或代码没有完成时。
标记 通常的作用
TODO 还没有处理的事情
MAYBE_LATER 方法有次要的缺陷
FIXME 已知的无法运行的代码
HACK 对一个问题不得不采用的比较粗糙的解决方案
XXX 危险!这里有重要的问题
加注释:站在读者的角度

想象代码对于外人来讲看起来是什么样子的,这个人并不熟悉项目,这对于发现什么地方需要注释尤其有用。

  1. 用注释总结代码块,不致迷失在细节中 ---> 在包含大块的长函数中使用。
  2. 在文件/类的级别上使用“全局观”注释 ---> 熟悉代码库。解释所有的部分是如何一起工作的,迅速了解代码,比自己读源代码快很多。
//这个文件包含一些辅助函数,为我们文件系统提供了更便利的接口
//它处理了文件权限及其他基本的细节。

写注释的学问

  1. 注释保持紧凑
  2. 避免使用不明确的代词,如 it,this
  3. 润色粗糙的句子
  4. 精确地描述函数的行为
    eg:统计行数 ----> 统计换行符(/n)
  5. 用输入/输出例子来说明特别的情况
  6. 声明代码的意图:表达写代码时的想法,不是描述字面上的意思
  7. 使用嵌入的注释:大多数函数不需要,这样可以方便紧凑地解释看上去难以理解的参数
    eg:Connect(10, false); --->
    Connect(/*timeout_ms = */ 10, /*use_encryption = */ false);
  8. 用含义丰富的词来使注释简洁:如果感觉一段注释太长了,可以使用一个典型的编程场景来描述。
    eg1:
// This class contains a number of members that store the same information as in the 
// database, but are stored here for speed. When this class is read from later, those
// members are checked first to see if they exist, and if so are returned; otherwise the 
// database is read from and that data stored in these field for next time.

可以简单的说:

This class acts as a caching layer to the database.

eg2:

// Remove excess whitespace from the street address, and do lots of other cleanup
// like turn "Avenue" into "Ave." This way, if there are two different street addresses
// that are typed in slightly differently, they will have the same cleaned-up version and 
// we can detect that these are equal.

可以简单的说:

Canonicalize the street address (remove extra spaces, "Avenue" -> "Ave.", etc.)
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 158,233评论 4 360
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 67,013评论 1 291
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 108,030评论 0 241
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 43,827评论 0 204
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 52,221评论 3 286
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 40,542评论 1 216
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 31,814评论 2 312
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 30,513评论 0 198
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 34,225评论 1 241
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 30,497评论 2 244
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 31,998评论 1 258
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 28,342评论 2 253
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 32,986评论 3 235
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 26,055评论 0 8
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 26,812评论 0 194
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 35,560评论 2 271
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 35,461评论 2 266

推荐阅读更多精彩内容