我有一个同事,他坚持认为他的代码不需要注释,这是“自文档”。

我已经审阅了他的代码,虽然它比我看到的其他人编写的代码更清晰,但我仍然不同意自文档化代码与经过注释和文档化的代码一样完整和有用。

帮我理解一下他的观点。

什么是自文档代码 它真的能取代注释良好和文档化的代码吗 在某些情况下,它是否比有良好文档和注释的代码更好 是否存在代码不可能在没有注释的情况下自文档化的例子

也许这只是我自身的局限性,但我看不出这怎么能成为一种好的练习。

这并不是一个争论——请不要提出为什么注释良好并有文档记录的代码是高优先级的原因——有很多资源都表明了这一点,但它们对我的同行来说并没有说服力。我认为我需要更全面地了解他的观点,才能说服他。如果你有必要,可以提出一个新的问题,但不要在这里争论。

另外,那些反对自我记录代码的人——这主要是为了帮助我理解自我记录代码传播者的观点(即积极的方面)。


当前回答

来自非评论阵营的一些观点。

“注释良好”(冗长)的代码更难阅读和理解。首先,有更多的文本需要扫描。它增加了理解CodeBase的认知努力——非功能性文本占用了屏幕上可以用来显示代码的空间。

注释的另一个大问题是它们不可靠——尤其是在旧的代码库中,注释腐烂比位腐烂发生得更快。

当然,还有写评论的工作。除了偶尔的一行注释之外,每次我开始注释代码时,都会有两种负罪感

这个信息需要在整个支持文档中 我需要清理我的代码

其他回答

区别在于“什么”和“如何”。

您应该记录一个例程做了什么。 你不应该记录它是如何做到的,除非特殊情况(例如,参考一篇特定的算法论文)。这应该是自我记录的。

自文档代码是一个很容易解决的问题,随着时间的推移,代码、注释和文档会出现分歧。编写清晰的代码也是一个约束因素(如果你对自己有那么严格的话)。

对我来说,以下是我努力遵循的规则:

Code should be as easy and clear to read as possible. Comments should give reasons for design decisions I took, like: why do I use this algorithm, or limitations the code has, like: does not work when ... (this should be handled in a contract/assertion in the code) (usually within the function/procedure). Documentation should list usage (calling converntions), side effects, possible return values. It can be extracted from code using tools like jDoc or xmlDoc. It therefore usually is outside the function/procedure, but close to the code it describes.

这意味着所有三种记录代码的方法都很接近,因此更有可能在代码更改时被更改,但它们所表达的内容并不重叠。

我认为自记录代码是注释的一个很好的替代品。如果您需要注释来解释代码是如何或为什么是这样的,那么您应该修改函数或变量名以使其更具解释性。这可能取决于编码器是否会用注释或重命名一些变量和函数并重构代码来弥补不足。

但是,它并不能真正取代您的文档,因为文档是您提供给其他人用来解释如何使用您的系统的,而不是它是如何工作的。

编辑:我(可能还有其他所有人)应该有一个数字信号处理(DSP)应用程序应该很好地注释的规定。这主要是因为DSP应用程序本质上是2 for循环,提供了数组的值和添加/乘以/等等所说的值…要更改程序,您需要更改其中一个数组中的值…需要一些评论来说明在这种情况下你在做什么;)

我想他可能想说的是,如果注释解释了代码的功能,那么就应该重写,以明确它的意图。这就是他所说的自文档代码。这通常意味着简单地用描述性函数名将长函数分解成逻辑上的小块。

这并不意味着代码不应该被注释。这意味着注释应该提供代码以这种方式编写的原因。

我认为,质疑某一行代码是否具有自文档性是有意义的,但最终,如果你不理解一段代码的结构和功能,那么大多数时候注释是没有用的。以amdfan的“正确注释”代码片段为例:

/* compute displacement with Newton's equation x = v0t + ½at^2 */
const float gravitationalForce = 9.81;
float timeInSeconds = 5;
float displacement = (1 / 2) * gravitationalForce * (timeInSeconds ^ 2);

这段代码很好,但下面的代码在大多数现代软件系统中同样具有丰富的信息,并且明确认识到使用牛顿计算是一种选择,如果其他一些物理范式更合适,可能会被改变:

const float accelerationDueToGravity = 9.81;
float timeInSeconds = 5;
float displacement = NewtonianPhysics.CalculateDisplacement(accelerationDueToGravity, timeInSeconds);

根据我个人的经验,很少有绝对需要注释的“正常”编码情况。举个例子,你有多频繁地使用自己的算法?基本上,其他一切都是构建系统的问题,以便编码器能够理解正在使用的结构以及驱动系统使用这些特定结构的选择。