261

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

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

帮助我理解的观点。

  • 什么是自记录代码
  • 它真的可以取代注释良好和记录良好的代码吗
  • 是否存在比有据可查和注释的代码更好的情况
  • 有没有代码不可能在没有注释的情况下自我记录的例子

也许这只是我自己的局限性,但我不明白它如何成为一个好的做法。

这并不是要成为一个论点 - 请不要提出为什么注释良好和记录良好的代码是高优先级的原因 - 有很多资源表明这一点,但它们并不能说服我的同行。我相信我需要更充分地理解他的观点才能说服他。如果必须,请提出一个新问题,但不要在这里争论。

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

4

44 回答 44

403

好吧,既然这是关于注释和代码的,让我们看一些实际的代码。比较这个典型的代码:

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.

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

我会说这取决于你正在做的事情的背景。对我来说,在这种情况下,自我记录的代码可能就足够了,但是详细说明背后的方法(在这个例子中,方程)的注释也是有用的。

于 2008-10-16T15:36:02.477 回答
182

在我看来,任何代码都应该是自记录的。在良好的、自记录的代码中,您不必解释每一行,因为每个标识符(变量、方法、类)都有一个清晰的语义名称。有多余的评论实际上会使阅读代码变得更加困难(!),所以如果你的同事

  • 为每个类、成员、类型和方法编写文档注释(Doxygen、JavaDoc、XML 注释等)和
  • 清楚地注释代码中不是自记录的任何部分,并且
  • 为解释意图的每个代码块编写注释,或者代码在更高的抽象级别上做了什么(即查找所有大于 10 MB的文件,而不是循环遍历目录中的所有文件,测试文件大小是否大于 10 MB,如果为真则返回

在我看来,他的代码和文档很好。请注意,自我记录的代码并不意味着不应该有注释,而只是说不应该有不必要的注释。然而,问题是,通过阅读代码(包括注释和文档注释)应该可以立即理解代码的作用和原因。如果“自我记录”代码比注释代码需要更长的时间来理解,那么它并不是真正的自我记录。

于 2008-10-16T15:33:38.690 回答
173

代码本身总是对您的代码所做的最新解释,但在我看来,它很难解释意图,这是注释中最重要的方面。如果编写得当,我们已经知道代码做了什么,我们只需要知道它到底为什么会这样做

于 2008-10-16T15:27:11.620 回答
99

曾经有人说过

1) 只为难以理解的代码写注释。
2)尽量不要编写难以理解的代码。

于 2008-10-16T16:16:44.157 回答
39

“自我记录”代码背后的想法是代码中的实际程序逻辑非常清晰,可以向阅读代码的任何人解释代码在做什么以及为什么要这样做。

在我看来,真正的自我记录代码的想法是一个神话。代码可以告诉您正在发生的事情背后的逻辑,但它无法解释为什么以某种方式完成它,特别是如果有不止一种方法可以解决问题。仅仅因为这个原因,它永远无法取代注释良好的代码。

于 2008-10-16T15:33:28.830 回答
19

我认为这与质疑特定代码行是否是自记录的有关,但最终如果您不了解一段代码的结构和功能,那么大多数时候注释将无济于事。以 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);

以我个人的经验,很少有“正常”的编码情况是绝对需要注释的。例如,您最终多久滚动一次自己的算法?基本上,其他一切都是构建系统的问题,以便编码人员可以理解正在使用的结构以及驱使系统使用这些特定结构的选择。

于 2008-10-16T21:43:07.197 回答
17

我忘记了我从哪里得到的,但是:

程序中的每一条评论都像是对读者的道歉。“很抱歉,我的代码太不透明了,以至于您无法通过查看它来理解它”。我们只需要接受我们并不完美,而是努力做到完美,并在需要时继续道歉。

于 2008-10-16T15:32:22.983 回答
14

首先,很高兴听到您同事的代码实际上比您见过的其他代码更清晰。这意味着他可能不会以“自我记录”为借口,懒得评论他的代码。

自文档代码是不需要自由文本注释的代码,知情的读者可以理解它在做什么。例如,这段代码是自记录的:

print "Hello, World!"

这是这样的:

factorial n = product [1..n]

这是这样的:

from BeautifulSoup import BeautifulSoup, Tag

def replace_a_href_with_span(soup):
    links = soup.findAll("a")
    for link in links:
        tag = Tag(soup, "span", [("class", "looksLikeLink")])
        tag.contents = link.contents
        link.replaceWith(tag)

现在,这种“知情读者”的想法是非常主观和情境化的。如果您或其他任何人在遵循您同事的代码时遇到问题,那么他最好重新评估他对知情读者的看法。为了调用代码自文档化,必须假定对所使用的语言和库有一定程度的熟悉。

我见过的编写“自记录代码”的最佳论据是,它避免了自由文本评论与编写的代码不一致的问题。最好的批评是,虽然代码可以描述它自己在做什么如何做,但它不能解释为什么某事以某种方式完成。

于 2008-10-16T15:51:17.797 回答
14

自记录代码是“DRY”(不要重复自己)的一个很好的例子。不要在代码本身中或可能存在的注释中重复信息。

与其解释变量的用途,不如重命名变量。

与其解释一小段代码的作用,不如将其提取到一个方法中并给它一个描述性的名称(可能是您的注释文本的缩短版本)。

与其解释一个复杂的测试做了什么,不如把它提取到一个方法中并给它一个好名字。

等等。

在此之后,您最终会得到不需要太多解释的代码,它会自行解释,因此您应该删除仅在代码中重复信息的注释。

这并不意味着您根本没有评论,有些信息您不能放入代码中,例如有关意图的信息(“为什么”)。在理想情况下,代码和注释相互补充,每一个都增加了独特的解释价值,而不会在另一个中重复信息。

于 2008-10-16T17:57:22.533 回答
13

自记录代码是一种很好的做法,如果做得好,可以很容易地传达代码的含义,而无需阅读太多注释。特别是在团队中的每个人都很好理解该领域的情况下。

话虽如此,评论对于新手或测试人员或生成文档/帮助文件非常有帮助。

自我记录的代码 + 必要的注释将大大有助于帮助跨团队的人。

于 2008-10-16T15:37:50.100 回答
9

为了:

  • 自文档代码是向读者清楚地表达其意图的代码。
  • 不是完全。评论总是有助于评论为什么选择特定策略。然而,解释一段代码正在做什么的注释表明代码的自我记录不足,可能需要进行一些重构。
  • 评论撒谎并过时。代码总是告诉更有可能说真话。
  • 我从未见过没有注释就无法清楚地说明代码内容的情况但是,就像我之前所说的,有时有必要/有帮助,包括对原因的评论。

然而,重要的是要注意,真正的自我记录代码需要大量的自我和团队纪律。你必须学习更多的声明式编程,你必须非常谦虚,避免“聪明”的代码,而支持那些显而易见的代码,似乎任何人都可以编写它。

于 2008-10-16T15:37:10.007 回答
7

当您阅读“自记录代码”时,您会看到它在做什么,但您不能总是猜到它为什么以这种特定方式做。

有大量的非编程约束,如业务逻辑、安全性、用户需求等。

当您进行维护时,这些背景信息变得非常重要。

只是我的一小撮盐...

于 2008-10-21T22:09:05.330 回答
6

首先,请考虑以下代码段:

/**
 * Sets the value of foobar.
 *
 * @foobar is the new vaue of foobar.
 */
 public void setFoobar(Object foobar) {
     this.foobar = foobar;
 }

在此示例中,每 3 行代码有 5 行注释。更糟糕的是 - 注释不会添加您通过阅读代码看不到的任何内容。如果您有 10 种这样的方法,您可能会得到“评论盲区”,而不会注意到偏离模式的一种方法。

如果当然,更好的版本应该是:

/**
 * The serialization of the foobar object is used to synchronize the qux task.
 * The default value is unique instance, override if needed.
 */
 public void setFoobar(Object foobar) {
     this.foobar = foobar;
 }

不过,对于琐碎的代码,我更喜欢没有评论。在代码之外的单独文档中可以更好地解释意图和整体组织。

于 2008-10-16T15:35:47.030 回答
6

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

  • 您应该记录例程的“功能”。
  • 你不应该记录它是如何做到的,除非有特殊情况(例如参考特定的算法论文)。那应该是自我记录的。
于 2009-08-12T08:23:41.880 回答
5

您可能希望向您的同事指出的一件事是,无论他的代码如何自我记录,如果考虑并丢弃其他替代方法,则除非他使用该信息评论代码,否则该信息将丢失。有时同样重要的是要知道考虑了替代方案以及为什么决定反对它,并且代码注释最有可能随着时间的推移而存在。

于 2008-10-16T15:35:28.170 回答
5

我很惊讶没有人提出“文学编程”,这是一种由 TeX 的 Donald E. Knuth 于 1981 年开发的技术,并以“计算机编程的艺术”而闻名。

前提很简单:既然代码必须被人理解,而注释只是被编译器丢弃,为什么不给每个人他们需要的东西——代码意图的完整文本描述,不受编程语言要求的限制, 对于人类读者和编译器的纯代码。

文学编程工具通过为文档提供特殊标记来做到这一点,该标记告诉工具哪些部分应该是源代码,哪些是文本。该程序稍后会从文档中提取源代码部分并组装一个代码文件。

我在网上找到了一个例子:http: //moonflare.com/code/select/select.nw或 HTML 版本http://moonflare.com/code/select/select.html

如果你能在图书馆找到 Knuth 的书(Donald E. Knuth,Literate Programming,Stanford,California:Center for the Study of Language and Information,1992,CSLI Lecture Notes,第 27 期。)你应该阅读它。

那是自我记录的代码,包含推理和所有内容。甚至制作了一份不错的文档,其他一切都只是写得很好的评论:-)

于 2008-10-16T22:02:33.083 回答
5

在我工作的一家公司中,其中一位程序员的显示器顶部贴有以下内容。

“记录你的代码,就像维护它的人是一个知道你住在哪里的杀人狂一样。”

于 2009-08-12T09:08:37.623 回答
4

自记录代码通常使用与代码所做的完全匹配的变量名,以便于理解正在发生的事情

然而,这样的“自我记录代码”永远不会取代注释。有时代码太复杂,而自记录代码是不够的,尤其是在可维护性方面。

我曾经有一位教授是这个理论的坚定信徒事实上我记得他说过的最好的一句话是“评论是给娘娘腔的”
一开始我们所有人都感到惊讶,但这是有道理的。
但是,情况是,即使您可能能够理解代码中发生的事情,但是经验不足的人可能会落后于您并且不了解发生了什么。这是评论变得重要的时候。我知道很多次我们不认为它们很重要,但很少有不需要评论的情况。

于 2008-10-16T15:30:21.537 回答
4

我想为许多有效的答案提供另一种观点:

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

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

你应该能够阅读你写的东西吗?

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

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

大多数编程语言都有冗余,因此当我们不连贯时编译器可以捕捉到我们。其他语言使用更多的推理并试图消除这种冗余。

计算机不需要类型名称、方法名称和变量名称。它们被我们用作参考。编译器不懂语义,那是给我们用的。

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

但是复杂性潜伏在每个项目中,你总是必须决定把复杂性放在哪里,以及吞下哪些骆驼。这些是使用评论的地方。

于 2008-12-13T23:57:06.840 回答
3

我认为自文档代码是评论的一个很好的替代品。如果您需要注释来解释代码是如何或为什么是这样的,那么您有一个函数或变量名称应该修改为更具解释性。编码员是否会通过注释或重命名一些变量和函数以及重构代码来弥补不足,这可能取决于编码员。

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

编辑:我(可能还有其他所有人)可能应该规定数字信号处理(DSP)应用程序应该得到很好的评论。这主要是因为 DSP 应用程序本质上是 2 个循环,其中包含值数组并添加/乘法/等表示值...要更改程序,您可以更改其中一个数组中的值...需要一些评论来说明什么在那种情况下你正在做;)

于 2008-10-16T15:31:15.887 回答
3

自我记录代码是解决问题的一个简单方法,随着时间的推移,代码、注释和文档会出现分歧。编写清晰的代码是一个纪律因素(如果你对自己这么严格的话)。

对我来说,这些是我试图遵循的规则:

  • 代码应该尽可能简单明了地阅读。
  • 注释应该说明我做出的设计决策的原因,例如:我为什么要使用此算法,或代码具有的限制,例如:当...时不起作用(这应该在代码中的合同/断言中处理)(通常在函数/过程中)。
  • 文档应列出用法(调用转换)、副作用、可能的返回值。可以使用 jDoc 或 xmlDoc 等工具从代码中提取它。因此它通常在函数/过程之外,但接近它描述的代码。

这意味着所有三种记录代码的方式都紧密结合在一起,因此在代码更改时更有可能被更改,但它们表达的内容不重叠。

于 2008-10-16T15:33:37.143 回答
3

所谓的自记录代码的真正问题在于它传达了它实际所做的事情。虽然一些评论可能有助于某人更好地理解代码(例如,算法步骤等),但它在一定程度上是多余的,我怀疑你会说服你的同行。

然而,文档中真正重要的是那些从代码中不能直接看出的东西:潜在的意图、假设、影响、限制等。

能够通过快速浏览来确定代码执行 X 比能够确定代码不执行 Y 要容易得多。他必须记录 Y...

例如,您可以向他展示一个看起来不错、很明显但实际上并未涵盖输入的所有基础的代码示例,然后看看他是否找到了它。

于 2008-10-16T15:35:00.417 回答
3

在编写数学代码时,我有时会发现写长的、类似文章的注释、解释数学、代码使用的符号约定以及它们如何组合在一起很有用。我们在这里谈论数百行文档。

我尝试让我的代码尽可能地自我记录,但是当我在几个月后回来处理它时,我确实需要阅读解释以避免对其进行散列。

现在,对于大多数情况,当然不需要这种极端措施。我认为这个故事的寓意是:不同的代码需要不同数量的文档。有些代码可以写得很清楚,不需要注释——所以写得清楚,不要在那里使用注释!

但是很多代码确实需要注释才能有意义,所以尽可能清楚地写出来,然后根据需要使用尽可能多的注释......

于 2008-10-16T18:23:41.280 回答
3

我会争辩——正如你们中的许多人所做的那样——要真正实现自我记录,代码需要表现出某种形式的意图。但我很惊讶还没有人提到 BDD -行为驱动开发。部分想法是您有自动化测试(代码)来解释代码的意图,否则很难使之变得明显。

良好的领域建模
+ 好名字(变量、方法、类)
+ 代码示例(来自用例的单元测试)
= 自我记录软件
于 2008-10-17T05:43:10.050 回答
2

除了代码之外的额外注释可能更清晰的几个原因:

  • 您正在查看的代码是自动生成的,因此在下次编译项目时可能会破坏对代码的任何编辑
  • 为了提高性能(展开循环、为昂贵的计算创建查找表等)而牺牲了一个不太简单的实现
于 2008-10-16T18:42:22.460 回答
2

这将是团队在其文档中所重视的全部内容。我建议记录为什么/意图而不是如何重要,这并不总是在自我记录代码中捕获。get/set 不,这些是显而易见的——但计算、检索等应该表达一些原因。

如果您来自不同的国籍,也请注意团队中的差异。措辞上的差异可能会影响方法的命名:

二分搜索

二进制搜索

BinaryChop

这三种方法由在 3 个不同大洲受过培训的开发人员提供,它们做同样的事情。只有通过阅读描述算法的评论,我们才能识别我们库中的重复。

于 2008-10-16T18:55:42.400 回答
2

对我来说,阅读需要注释的代码就像阅读我不懂的语言的文本。我看到声明,但我不明白它的作用或原因 - 我必须查看评论。我读了一个短语,我需要查字典才能理解它的意思。

通常很容易编写代码来自我记录它所做的事情。告诉你为什么这样做,注释更合适,但即使是这里的代码也可以更好。如果您在每个抽象级别上都了解您的系统,您应该尝试像这样组织您的代码

public Result whatYouWantToDo(){
  howYouDoItStep1();
  howYouDoItStep2();
  return resultOfWhatYouHavDone;
}

方法名称反映了您的意图,方法主体说明了您如何实现目标。无论如何,您无法在书名中说出整本书,因此仍然必须记录系统的主要抽象,以及复杂的算法、非平凡的方法契约和工件。

如果您的同事生产的代码确实是自我记录的 - 幸运的是您和他。如果您认为您的同事代码需要注释 - 它需要。只需打开其中最不平凡的地方,阅读一遍,看看你是否理解了所有内容。如果代码是自我记录的——那么你应该这样做。如果不是 - 向您的同事询问有关它的问题,在他给您答案之后询问为什么该答案没有事先记录在评论或代码中。他可以声称代码对于像他这样聪明的人来说是自文档,但无论如何他必须尊重其他团队成员——如果你的任务需要理解他的代码,而他的代码没有向你解释你需要理解的一切——它需要评论。

于 2008-10-17T02:14:53.373 回答
2

大多数文档/评论有助于帮助未来的代码增强者/开发人员,从而使代码可维护。通常情况下,我们最终会在稍后返回我们的模块以添加新功能或优化。那时,通过阅读注释比单步执行大量断点更容易理解代码。此外,我宁愿花时间思考新逻辑,也不愿破译现有逻辑。

于 2008-10-20T05:06:59.967 回答
1

我认为他可能会说,如果注释解释了代码在做什么,那么应该重写它以明确它的意图是什么。这就是他所说的自我记录代码的意思。通常这可能意味着简单地将长函数分解为具有描述性函数名称的逻辑小块。

这并不意味着不应评论代码。这意味着注释应该提供代码按原样编写的原因。

于 2008-10-16T15:31:08.227 回答
1

我相信您应该始终努力实现自文档化代码,因为它确实使代码更容易阅读。但是,你也必须对事情务实。

例如,我通常为每个班级成员添加注释(为此我使用文档注释)。这描述了成员应该做什么,但不描述它是如何做的。我发现当我阅读代码时,尤其是旧代码时,这有助于我快速记住该成员的用途,而且我还发现它比阅读代码并解决它更容易,特别是如果代码流跳动很多.

这只是我的看法。我知道很多人在工作时完全没有评论,并说他们觉得这没问题。然而,我曾向某人询问他们六个月前编写的一种方法,他们不得不考虑几分钟才能确切地告诉我它做了什么。如果方法被注释,这不是问题。

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

于 2008-10-16T15:33:11.327 回答
1

我认为这是一个正确数量的文档问题,而不是全部或没有。如果函数的参数命名良好,您通常不必准确说出它们是什么,例如 char *CustomerName 非常明显。如果您对参数使用断言值范围,则不必同时记录这些范围。IMO,文档应该涵盖所有不太明显的内容,因此需要一些解释,并且大多数代码都需要一些文档。就个人而言,在大多数情况下,我宁愿看一个给定函数如何工作的说明性示例,而不是描述性文档。

为了文档而编写文档可能会浪费时间,因为文档需要维护才能与代码库保持同步。如果没有人会从阅读中受益,请不要制作它。

于 2008-10-16T15:34:40.327 回答
1

我会扭转这种局面。

问问自己你在他的代码中有什么不明白的地方,然后让他把这些记录下来。也许你也可以告诉我们一些。

于 2008-10-16T15:35:03.927 回答
1

这是我对您的问题的最佳回答。

自我记录代码是用类、方法、函数和变量名清楚地编写的代码,使其意图和功能易于理解。如果做得好,它就是文档。

可以替换注释和记录良好的代码,但我很少看到它。很多时候,程序员都认为自己足够优秀,可以做到这一点,但打倒他们的最好方法是开始提问。如果他们必须开始解释太多,那么他们的代码不够清晰。您不必阅读代码即可知道它的作用。

在某些情况下可能会更好。如果代码小而简单,那么您可能会通过添加文档来使​​事情变得混乱。

包含算法的代码应该包含注释。大多数时候,即使是最初的程序员也记不起几个月前他们在写一个长函数时到底在想什么。

于 2008-10-16T15:37:15.763 回答
1

这是一个很好的问题。我敢肯定,它可以追溯到第一种允许注释的编程语言。代码当然应该尽可能地自我记录。指出显而易见的评论应该被删除。让我们更容易理解给定方法或代码部分的意图、目的和使用的注释对于我们这些可能不太熟悉所讨论的语言或代码的傻瓜来说是非常宝贵的。允许生成 API 文档的结构化注释就是一个很好的例子。只是不要评论检查复选框是否已选中的 IF 语句,并告诉我您正在检查复选框是否已选中。在评论中重申显而易见的是我们宇宙中最糟糕的浪费击键。

//For example, the above text deals with what is a useful comment
于 2008-10-16T15:38:44.560 回答
1

自我记录的代码是非常容易理解的代码。变量命名在使代码自我记录方面大有帮助,但我发现最好的策略是将任何复杂的逻辑分解成很小的小块,并将这些信息重构为具有详细信息和信息名称的单独方法。然后,您的复杂方法就变成了要执行的步骤列表。然后,微小的私有辅助方法通过它们自己的方法名称进行充分记录,并将复杂的方法记录为要执行的一系列抽象步骤。在实践中,这种策略不能总是完美地应用,所以评论仍然非常有用。另外,您永远不应该完全放弃任何可以帮助您编写更易于理解的代码的工具。

于 2008-10-16T15:51:51.990 回答
1

如果您的代码在没有注释的情况下不完全清晰,那么您的代码还有改进的空间。

我不是说“不要评论不清楚的代码”。我说的是“让你的代码清晰”。

如果您最终以某种方式使您的代码不清楚,请使用注释来弥补。

于 2008-10-16T20:38:02.757 回答
1

自我记录的代码是愚蠢的。任何不得不在数周、数月或喘息年后重新访问他们的代码的人都知道这一点(或数天,在我的情况下)。(也许宣传这个想法的那个人还在耳后!?!?!)

使用有意义的、描述性的数据名称,智能地考虑你的代码,并给自己留下一些提示,告诉你为什么你做了你所做的事情,你会过上更丰富、更充实的生活。

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

去搞清楚。

于 2008-10-16T21:38:02.650 回答
1

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

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

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

当然,还有写评论的努力。除了偶尔的一行澄清,每次我开始评论代码时,我都会有两种内疚感之一

  1. 此信息需要包含在整体支持文档中
  2. 我需要清理我的代码
于 2008-10-17T00:46:19.680 回答
1

不管纯粹的自我记录代码是可以实现的,还是有一些事情浮现在脑海中应该做的:

  • 永远不要有“令人惊讶”的代码。IE。不要使用愚蠢的宏来重新定义事物等。不要滥用运算符重载,不要试图在这方面变得聪明。
  • 在正确的位置拆分代码。使用适当的抽象。与其内联滚动缓冲区(具有固定长度的缓冲区,具有两个指针,这些指针在一端添加项目并在另一端删除项目),而是使用具有正确名称的抽象。
  • 保持低功能复杂度。如果它变得太长或太复杂,请尝试将其拆分为其他其他功能。

在实现特定的复杂算法时,添加描述算法的文档(或链接)。但在这种情况下,要格外努力地消除不必要的复杂性并增加易读性,因为太容易出错了。

于 2008-10-17T08:07:35.733 回答
1

这里的输入似乎很混杂:)

我使用伪代码编程过程进行新的开发,这实际上使我的代码自我记录。我仅在编写新代码然后对其进行扩展时才开始编写伪代码。我不是说这是最佳实践或类似的东西,我只是强调一种我认为有用的技术,如果你知道你想要大量的代码文档,如果它去第三方,审阅者等......它也在我写一行代码之前,偶尔会为我突出问题。

' 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
于 2008-10-17T08:39:04.767 回答
1

我曾经和一个准备把一套金融套件卖给一家大公司的人一起工作。他们坚持要他记录源代码,他为此制作了一个 30 多页的汇编程序例程并说“它已记录在案,看”——然后他翻到第 13 页,并有一条评论“反击计数器”。伟大的产品,伟大的实施者,但是......

无论如何,在我看来,上面的重要评论是为了设置上下文。该片段被声明为自记录:

> from BeautifulSoup import
> BeautifulSoup, Tag def
> replace_a_href_with_span(soup):
>     links = soup.findAll("a")
>     for link in links:
>         tag = Tag(soup, "span", [("class", "looksLikeLink")])
>         tag.contents = link.contents
>         link.replaceWith(tag)

但是,我需要一个上下文来完全理解它。

于 2008-11-20T21:14:32.570 回答
1

有人指出,评论应该抓住意图,但我会更进一步。

我认为对于任何一类问题,都有一个理想的(或几乎如此)的词汇和句法来描述它,如果你让有此类问题的人描述它们,你就可以看到它(假设这个人可以清楚地思考) .

如果这些词汇和语法很容易(通过定义类、方法等)映射到计算机语言的代码上,那么该代码可以是自记录的。此外,还创建了 IMO,一种特定于领域的语言。(这是我对“声明性”的粗略定义。)

如果这个理想失败了,如果问题没有直接映射到计算机代码上,那么你需要一些东西将两者联系在一起。IMO,这就是评论的目的。

这样,当问题发生变化时,您可以找到代码的相应部分进行更改。

编辑:顺便说一句,我不赞成 OOP 方法,其中每个名词都成为一个类,每个动词都是一个方法。我已经看到足够多的英国媒体报道软件以这种方式构建。

于 2008-12-11T03:10:12.173 回答
1

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

不过,我们不应该忘记设计和规范文档。那些有或至少应该有很多在评论中不一定需要的文本。软件通常还有用户手册和其他描述文件,这些文件应该与程序的功能同步。如果用户必须从源代码而不是手册中找出软件的功能,情况就不太好了。所以自我记录的代码仍然不意味着实际的软件已经记录在案。

还要考虑功能的可追溯性。当您拥有手册时,您应该能够将功能追溯到源代码并返回以获得更好的可维护性。手册和规范不是关于编程的,而是关于软件工程的。软件越大,需要的工程就越多。

于 2009-08-12T08:18:57.100 回答
0

自我记录的代码是非常清晰以至于不需要注释的代码。我举一个小例子:

//iterate from 0 to 100
for(int i=0; i < 100; i++) {
   println i
}

注释没什么用,因为代码很清楚。文档是一种很好的做法,但是额外的文档会给代码添加不必要的噪音。您的同事需要知道的是,并非每个人都能阅读他人的代码并承认其所有细节。

int calc(int a, int b) {
   return sqrt(a*a + b*b); //pythagoras theorem
}

如果没有注释,最后一个片段将很难破译。你可以想象其他更人为的例子。

于 2008-10-16T15:35:56.267 回答