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

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

帮我理解一下他的观点。

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

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

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

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


当前回答

既然这是关于注释和代码的,那么让我们来看一些实际的代码。比较下面的典型代码:

float a, b, c; a=9.81; b=5; c= .5*a*(b^2);

到这个显示正在执行的操作的自文档代码:

const float gravitationalForce = 9.81;
float timeInSeconds = 5;
float displacement = (1 / 2) * gravitationalForce * (timeInSeconds ^ 2);

然后是这个文档代码,它更好地解释了为什么要这样做:

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

最终版本的代码作为文档,不需要注释:

float computeDisplacement(float timeInSeconds) {
    const float gravitationalForce = 9.81;
    float displacement = (1 / 2) * gravitationalForce * (timeInSeconds ^ 2);
    return displacement;
}

下面是一个糟糕评论风格的例子:

const float a = 9.81; //gravitational force
float b = 5; //time in seconds
float c = (1/2)*a*(b^2) //multiply the time and gravity together to get displacement.

在最后一个例子中,当变量应该被描述性地命名时,就会使用注释,当我们可以清楚地看到操作是什么时,就会总结操作的结果。无论如何,我更喜欢自文档化的第二个示例,也许这就是您的朋友所说的自文档化代码。

我会说,这取决于你所做的事情的背景。对我来说,在这种情况下,自编文档的代码可能就足够了,但是详细描述所做事情(在本例中是方程)背后的方法的注释也很有用。

其他回答

我相信您应该始终努力实现自文档化代码,因为它确实使代码阅读变得更容易。然而,你也必须务实。

例如,我通常为每个类成员添加注释(为此我使用文档注释)。这描述了成员应该做什么,而不是如何做。我发现,当我阅读代码,特别是旧代码时,这有助于我快速记住成员是用来做什么的,我也发现这比阅读代码和解决它更容易,特别是当代码流跳跃相当多的时候。

这只是我的个人观点。我知道很多人在工作时根本没有评论,他们认为这没有问题。然而,我曾经问过某人关于他们六个月前写的一个方法,他们不得不思考几分钟来告诉我它到底是做什么的。如果方法是注释的,这不是问题。

最后,您必须记住,注释和代码一样都是系统的一部分。在重构和更改功能时,还必须更新注释。这是反对使用注释的一个论点,因为如果它们不正确,它们比无用更糟糕。

自我记录代码是愚蠢的。任何在几周、几个月或几年之后不得不重新访问代码的人都知道这一点(对我来说是几天)。(也许推广这个想法的人还很幼稚!?! ! !)

使用有意义的、描述性的数据名称,聪明地分解代码,并给自己留下提示,告诉自己为什么要这么做,这样你的生活就会更丰富、更充实。

尽管……我确实读过一句比尔·盖茨说过的话:“代码就是文档。”

图。

好的设计结构有助于指出,有些函数是通用的,有些是随机的业务逻辑,即使你没有评论说“这个函数是通用的”。

We should not forget about design and specification documentation though. Those have or at least should have much of the texts that are not necessarily needed in comments. Software often have also user manuals and other description documents, and those should be in sync with what the program does. The situation is not great if the user has to find out what the software does from the source code instead of a manual. So self documenting code still doesn't mean that the actual software has been documented.

还要考虑功能的可跟踪性。当你有了你的手册,那么你应该能够追踪到源代码的特性,并返回更好的可维护性。手册和规范与编程没有太大关系,但它们与软件工程有关。软件越大,需要的工程设计就越多。

对于许多有效的答案,我想再提供一个观点:

什么是源代码?什么是编程语言?

机器不需要源代码。他们很高兴运行组装。编程语言是为了我们的利益。我们不想写汇编。我们需要理解我们在写什么。编程就是写代码。

你能读懂你写的东西吗?

源代码不是用人类语言编写的。它已经被尝试过(例如FORTRAN),但并不完全成功。

源代码不能有歧义。这就是为什么我们必须在其中加入比文本更多的结构。文本只适用于上下文,当我们使用文本时,我们认为这是理所当然的。源代码中的上下文总是存在的。想想c#中的“使用”。

大多数编程语言都有冗余,这样编译器就能在我们不连贯的时候发现我们。其他语言使用更多的推理,并试图消除冗余。

类型名、方法名和变量名在计算机中是不需要的。它们是供我们参考的。编译器不理解语义,这是我们要用的。

编程语言是人与机器之间的语言桥梁。它必须对我们来说是可写的,对他们来说是可读的。次要要求是它应该对我们来说是可读的。如果我们擅长语义,并且擅长构建代码,那么即使对我们来说,源代码也应该很容易阅读。最好的代码不需要注释。

但是复杂性潜伏在每个项目中,您总是需要决定将复杂性放在哪里,以及吞下哪只骆驼。这些是使用注释的地方。

这里的输入似乎非常复杂:)

我使用伪代码编程过程进行新的开发,这实际上使我的代码自文档化。我只在写新代码时才开始写伪代码,然后在上面扩展。我不是说这是最佳实践或类似的东西,我只是强调一个我认为有用的技巧,如果你知道你的代码需要大量的文档,如果它要交给第三方,审查者等等……它偶尔也会在我还没写一行代码的时候就给我指出一些问题。

' check database is available
  ' if it is then allow the procedure
  ' if it isnt roll back and tidy up 
' move onto something else

变成了;

' check database is available
  if checkDBStateResult(currentDB) = Open then 
     ' if it is then allow the procedure
          proc.Ok = True 
  else
     ' if it isnt roll back
          proc.Ok = False
          CleanUp()
  end if