您需要文档(以某种形式;并不总是注释)以在本地理解代码。如果您阅读了所有代码并牢记在心,代码本身就会告诉您它的作用。(更多内容见下文。)评论最适合非正式或半正式文档。
许多人说注释是一种代码味道,可以通过重构、更好的命名和测试来替代。虽然糟糕的评论(很多)都是如此,但很容易得出结论总是如此,哈利路亚,没有更多的评论。这将本地文档的所有负担——我认为太多了——放在了命名和测试上。
记录每个函数的契约,以及对于每种类型的对象,它表示什么以及对有效表示的任何约束(技术上,抽象函数和表示不变)。在可行的情况下使用可执行的、可测试的文档(文档测试、单元测试、断言),但也要写简短的注释,在有帮助的地方给出要点。(如果测试采用示例的形式,它们是不完整的;如果它们是完整的、精确的契约,它们可能与代码本身一样需要深入研究。)为每个模块和每个项目编写顶级注释;这些可以解释使您所有其他评论(和代码)保持简短的约定。(这支持命名为文档:建立了约定,并且我们可以期望在其中发现细微之处,我们可以更有信心地相信名称说明了我们需要知道的一切。)更长的、程式化的、令人恼火的冗余 Javadocs 有它们的用途,但是帮助产生了反弹。
(例如,这个:
执行 n 次 fobulation。
@param n 移动的次数
@param x 移动中心的 x 坐标
@param y 移动中心的 y 坐标
@param z 移动中心的 z 坐标
可能就像“围绕中心 (x,y,z) 摇晃 n 次”。评论不一定是阅读和写作的苦差事。)
我并不总是按照我在这里说的去做;这取决于我对代码的重视程度以及我希望谁阅读它。但是学习如何编写这种方式让我成为了一个更好的程序员,即使是在偷工减料的时候。
回到我们为了本地理解而记录的声明:这个函数有什么作用?
def is_even(n): return is_odd(n-1)
测试整数是否为偶数?如果is_odd()
测试一个整数是否为奇数,那么是的,这有效。假设我们有这个:
def is_odd(n): return is_even(n-1)
同样的推理表明,这is_odd()
会测试整数是否为奇数。当然,将它们放在一起,两者都不起作用,即使每个都起作用,如果另一个起作用。稍微改变一下,我们就会得到可以工作的代码,但只适用于自然数,而在本地看起来它仍然适用于整数。在微观世界中,这就是理解代码库的样子:循环追踪依赖关系,以尝试对作者可能已经解释过一两行的假设进行逆向工程。我讨厌在过去的几十年里,精神上粗心的编码人员的代价让我走上了这条路:哦,这种方法看起来有与扭曲核心远距离的副作用......总是?好吧,如果奇怪的crobuncles去饱和,至少;他们吗?最好检查所有 crobuncle 处理代码......这将对理解提出挑战。好的文档将这个 O(n) 指针追踪减少到 O(1):例如,知道一个函数的契约和它明确使用的事物的契约,函数的代码应该在不进一步了解系统的情况下有意义。(在这里,合同说is_even()
和is_odd()
工作自然数会告诉我们两个函数都需要测试n==0
。)