导论
软件开发作为一项系统工程,其中最基础而重要的一个环节就是代码编写。然而,在代码编写的顺序上,业内一直存在着"先注释后代码"和"先代码后注释"两种模式,关于哪一种模式更好,争论一直未休。
事实上,这两种模式各有利弊。"先注释后代码"强调整体设计,注重可读性和可维护性;但其操作成本高,效率低下。"先代码后注释"注重快速验证思路,但容易忽略设计细节,给日后维护带来困难。文将从历史演变和软件工程实践两个角度,系统论述这两种模式在不同阶段的优劣势,并给出更深入的分析,得出一个逻辑自洽的理论性编写建议。
本文的观点如下:
- 随着IDE和其他软件工具的发展,两种模式在历史上都有过不同阶段的应用
- 从项目管理和代码质量两个层面,它们各有利弊
- 对注释目的正本清源,才能正确写注释
- 两种模式本质上不是对立的
历史上的演变
早期机器语言阶段,由于编码难度极大,程序开发主要注重设计与文档记录。这一时期,"先注释后代码"成为主流模式。同时,随着软件工程学科的形成和发展,"先注释"模式作为一种系统化的软件开发方法也得到推广和传播,进一步成为主流看法。
随着高级语言的出现,编程难度降低,但项目规模也日益扩大。为了提高开发效率,一些开发团队开始采用"先代码后注释"的方式来进行快速编码与迭代。这种模式强调先按功能模块实现基本功能,后续再梳理注释与设计文档。
90年代,随着互联网的兴起,软件开发项目越来越多采用小型团队的敏捷开发模式。这种模式下,快速交付产品成为首要任务。"先代码"模式因其高效的开发特性而得到广泛采用。
总体来说,随着技术水平和管理模式的变化,"先注释"与"先代码"两种模式在不同历史阶段都发挥过各自的优势。它们也在不断互相影响,共同推动着软件开发范式的演变。
更多的细节
其实争论主要源自于对于项目不同阶段的强调。其实双方都承认整个项目,尤其是大型项目都需要整体的设计,对这一点双方并没有严重分歧。主要的分歧在于对于更小的,函数尤其是小函数级别的范围上,究竟是否需要完备的事先设计并形成文档化,还是快速进入编码并在代码趋于稳定后回头补充相关文档。
在先编码概念下,其中比较有名的一本2015年出版的书:《Code as Design: Three Essays by Jack W. Reeves》。在文章中作者指出:
- 编码并不是机械得实现原始设计。编码过程中程序员必须做出大量设计选择和权衡,这才是设计活动的关键所在;
- 编码阶段的设计决策事实上会深刻影响最终软件的结构。像命名、代码组织、控制流等都包含设计内容。因此不能认为编码只是映射先期设计。
- 依赖设计文档而不看实际代码,无法判断软件品质。因为文档常常会与代码脱节。只有代码才是设计的权威表
而强调先注释的一方则认为即使是最小的函数,也应该先进行基本的设计然后展开编码。
几种函数注释模式
如果注释的内容就是代码是如何实现函数的功能的,那么显然当函数的最终代码在实现过程中会被多次重构的话,那么"先编码"的观点显然是正确的。即使先进行设计,那么99%的设计都是会被推翻的。然而我们不能因此就同意在最终函数级别就应该"先编码"。这里的核心问题是双方对于注释的理解不科学。
我们给出注释可能的几种模式
- 注释所包含的信息量完全和代码所包含的信息量一致
- 注释所包含的信息量是代码所包含的信息量的真子集
- 注释所包含的信息量中包含一个代码所包含的信息量的真子集
如果注释的内容就是代码如何实现,从信息量角度两者如果是等价的,那么这样的注释其实就是信息的冗余。为了维护注释和实际代码的一致性,显然需要更多的工作量。此时我们需要的仅仅是一个自动化工具,能自动将注释映射成代码,或者自动将代码映射成注释就可以了。几十年来这样的工具都没有出现,足以证明第一个模式并不是事实。这个推理对于第二种模式同样适用。注释如果只是代码信息的一个真子集,那么用刚才的工具也基本能解决问题。
函数及函数内注释的定义
从需求到代码,是一个信息量逐渐丢失的过程,也是一个信息量逐渐增加的过程。有些设计意图背后的原因不会在代码中被展示,具体代码的实现方式几乎不可能在业务需求中被指定。注释究竟需要描述什么东西?我们把注释分为两类,一类是偏业务端的信息描述,另一类是偏技术实现端的描述信息。基于现有的讨论分析,我们给出以下的建议
什么时候写注释
- 函数注释必须先于实际代码编写而完成
注释写什么
函数注释
的核心内容是函数的业务目的,不涉及函数的具体实现方式和处理过程函数内注释
的核心是具体业务操作步骤、相关算法或技术实现的信息
遵守以上的建议,那么我们的函数注释将处于一个比实现代码更稳定的状态,不会因为具体功能的实现方式在实际编码过程中的优化和重构而变化。并且提供了实现代码所不能体现的实际业务上的目的和描述信息,使得整个项目从上到下的设计目的的描述得以连续和完整。同时明确了业务描述和技术描述两种不同目的的注释信息的编写位置。
如果我们进一步遵守函数职责单一化的建议,那么实际上函数内注释几乎就不会出现需要描述业务操作信息的情况了,因为每个函数内很可能最多只出现一个条件语句了。
总结
本文分析了编程行业中常见的"先编码"和"先注释"观点的历史成因和理念差异,指出两者其实并非完全对立而是相辅相成。并且给出了更为系统化理论化以及逻辑自洽的关于软件中函数注释信息应该如何编写的指导性意见。