第 15 章 先写注释
(把注释变成设计过程的一部分)
许多开发人员把编写文档推迟到开发的最后阶段,等编码和单元测试完成后再写。这是最容易产生低质量文档的做法之一。编写注释的最佳时机是开发之初,就在编写代码的时候。先写注释,就能让文档成为设计过程的一部分。这不仅能带来更好的文档和设计,也能让编写文档的过程更愉快。
本章概览注释应该在什么时候写?
15.1 迟到的注释不是好注释
我见过的开发人员几乎都会推迟写注释。问起为什么不早点写文档,他们会说代码还在变:如果现在就写,代码变更时还得重写,不如等代码稳定下来再说。但我怀疑还有另一个原因:他们把写文档当作苦差事,所以能拖就拖。
这种做法有几个不良后果。首先,推迟写文档往往意味着最后根本不会写。一旦开始拖延,就很容易再拖一阵,毕竟过几周代码还会更稳定。等代码真正稳定下来,已经积累了大量代码,补写文档的任务也变得更庞大、更让人不愿着手。似乎总找不到合适的时间停下几天,把缺失的注释补齐。人们也很容易为拖延找到理由:对项目来说,继续迭代、修复缺陷或开发下一个功能才更重要。结果,没有注释的代码越来越多。
即使你有足够的自制力回头补注释(别自欺欺人,你很可能并没有),也很难写好。此时,你的心思已经不在这里:你觉得代码已经完成,急着开始下一个项目。你知道应该写注释,却觉得毫无乐趣,只想尽快了事。于是,你匆匆浏览代码,补上一些注释,看起来差不多就行。距离设计这段代码已经过去一段时间,设计过程的记忆也模糊了。对着代码补注释,很容易只是在重复代码。即使努力回想那些无法直接从代码看出的设计思路,也难免有所遗忘,结果遗漏了注释本该说明的一些最重要的信息。
译者图解推迟注释,为什么可能越积越难补?
15.2 先写注释
我的做法不同:从一开始就写注释。
- 对于新类,我首先编写类接口注释。
- 接下来,我为最重要的公有方法编写接口注释和签名,但将方法主体保留为空。
- 我反复修改这些注释,直到觉得基本结构合理为止。
- 然后,为类中最重要的实例变量编写声明和注释。
- 最后,编写方法体,并根据需要添加实现注释。
- 编写方法体时,通常会发现还需要更多方法和实例变量。对于每个新方法,我都先写接口注释,再写方法体;对于每个实例变量,则在写声明时一并写好注释。
这样,代码完成时,注释也已经完成,不会积压待补写的注释。
先写注释有三个好处。首先,注释的质量更好。设计类时,关键设计问题正清楚地留在脑中,很容易记录下来。最好在编写每个方法体之前先写接口注释,这样就能专注于方法的抽象和接口,不被实现细节分散注意力。在后续编码和测试中,还会发现并修正注释中的问题,使注释随着开发持续改进。
译者图解先写注释不是写完就冻结
15.3 注释是一种设计工具
先写注释的第二个、也是最重要的好处,是改善系统设计。注释是完整描述抽象的唯一方式,而好的抽象是良好系统设计的基础。如果一开始就写好描述抽象的注释,就能在编写实现代码之前检查和调整抽象。要写好注释,必须认清变量或代码的本质:其中最重要的是什么?在设计早期想清楚这一点很重要,否则就只是埋头写代码。
注释就像煤矿中的金丝雀,可以预警复杂性。如果方法或变量需要很长的注释,这就是一个危险信号,表明抽象不够好。请记住第 4 章的原则,类应该是深的:最好的类接口非常简单,却能提供强大的功能。判断接口复杂性的最佳方法,是查看描述接口的注释。如果接口注释简短、简单,又包含使用该方法所需的全部信息,就说明接口很简单。反之,如果必须用冗长、复杂的注释才能完整描述一个方法,就说明接口很复杂。将方法的接口注释与实现相比较,还能判断方法有多深:如果接口注释必须描述实现的所有主要特性,这个方法就是浅的。变量也是如此:如果必须用很长的注释才能完整描述变量,就是一个危险信号,表明变量可能没有得到合理拆分。总之,写注释能让你及早评估设计决策,发现并解决问题。
危险信号:难以描述
描述方法或变量的注释应该简单而完整。如果你发现很难写这样的注释,则表明你对所描述事物的设计可能存在问题。
当然,只有完整、清晰的注释,才能有效反映复杂性。如果方法的接口注释遗漏了调用所需的信息,或者本身就晦涩难懂,也就无法据此准确判断方法的深度。
译者图解删掉调用条件,不会删掉调用义务
15.4 先写注释很有趣
尽早写注释的第三个、也是最后一个好处,是让这项工作更有趣。对我来说,编程最有趣的部分之一就是新类的早期设计,在这个阶段逐步完善类的抽象和结构。我的大部分注释都写于此时,用来记录设计决策,并检验其质量。我会寻找能用尽量少的文字完整、清晰地表达的设计。注释越简单,我对设计就越满意,写出简明的注释也会带来成就感。如果你采用战略式编程,把出色的设计而不只是能工作的代码作为主要目标,那么写注释应该是有趣的,因为它能帮助你找到最佳设计。
15.5 先写注释是否很昂贵?
现在,重新审视推迟写注释的理由:可以省去代码演变时修改注释的成本。粗略估算就能看出,这样节省不了多少时间。先估算实际键入代码和注释所占的开发时间比例,包括修改代码和注释的时间;它不太可能超过全部开发时间的约 10%。即使全部代码行中有一半是注释,写注释占用的时间也很可能不超过开发总时间的约 5%。把注释拖到最后,只能节省其中很小的一部分。
先写注释则意味着,在动手写代码之前,抽象已经更加稳定,这很可能节省编码时间。反过来,如果先写代码,抽象很可能随编码过程而变化,需要的代码修改也会比先写注释时更多。综合这些因素,先写注释可能反而更省时间。
15.6 结论
如果你从未试过先写注释,不妨试一试,并坚持到习惯这种做法。然后想一想,它对注释质量、设计质量以及软件开发的整体乐趣有什么影响。尝试一段时间后,请告诉我你的体验是否与我的一致,以及其中的原因。