如何使大型代码库更容易理解


104

假设我正在开发一个相对较大的项目。我已经用Doxygen记录了我的所有类和函数,但是,我有个主意,在每个源代码文件上都写上“程序员笔记”。

这背后的想法是用通俗的术语解释一个特定的类是如何工作的(不仅是为什么大多数评论如此)。换句话说,让其他程序员对类的工作方式有另一种看法。

例如:

/*
 * PROGRAMMER'S NOTES:
 *
 * As stated in the documentation, the GamepadManager class 
 * reads joystick joystick input using SDL and 'parses' SDL events to
 * Qt signals.
 *
 * Most of the code here is about goofing around the joystick mappings.
 * We want to avoid having different joystick behaviours between
 * operating systems to have a more integrated user experience, since
 * we don't want team members to have a bad surprise while
 * driving their robots with different laptops.
 *
 * Unfortunately, we cannot use SDL's GamepadAPI because the robots
 * are interested in getting the button/axes numbers, not the "A" or
 * "X" button.
 *
 * To get around this issue, we created a INI file for the most common 
 * controllers that maps each joystick button/axis to the "standard" 
 * buttons and axes used by most teams. 
 *
 * We choose to use INI files because we can safely use QSettings
 * to read its values and we don't have to worry about having to use
 * third-party tools to read other formats.
 */

这是使大型项目更容易让新的程序员/贡献者理解其工作方式的好方法吗?除了保持一致的编码风格和“标准”目录组织外,针对这些情况是否还有“标准”或建议?


32
一定不行。如果您的代码不可读,文档将无济于事。
Telastyn

35
@jeffo-问题在于花时间去做一次可能会发生一次。保持代码可读性的时间是随着时间的流逝。我去过这类文档的地方,这些文档是在项目年轻时或完美主义者Joe仍在团队中时完成的。然后它被放弃了,评论流连忘返,不再准确。
Telastyn

25
至少在更高层次上,对项目的功能,其工作方式以及在体系结构中进行了哪些折衷的代码外散文描述是无价的。对于新手来说阅读文档之前必须阅读此类文档。有很多的我,方法论,是太激进换文档,花花公子周围的净胡说,虽然它真实的初始拱doc和一个不断发展的拱文档将不对齐,一个文字描述是必要的任何人都可以快速掌握庞大而重要的代码库。这是一个(较差的)示例:zxq9.com/erlmud/html/001-002_architecture.html
zxq9

11
@Telastyn:这与代码是否可读无关(我希望是这样)。记录设计依据是绝对重要的。
Lightness Races in Orbit

7
@Telastyn:是的,也许。我个人会用独立文档编写它。但是源文件顶部的注释块还不错。
Lightness Races in Orbit

Answers:


139

这太棒了。我希望更多的软件开发人员花时间和精力来做到这一点。它:

  • 用简单的英语陈述班级的工作(即责任),
  • 提供有关代码的有用的补充信息,而无需重复逐字逐句地说明代码,
  • 概述了一些设计决策以及做出这些决策的原因,以及
  • 突出显示下一个阅读您的代码的人可能会遇到的陷阱。

las,许多程序员陷入了“如果代码编写正确,就不必记录文档”的阵营。不对。在代码类,方法,模块和其他工件之间存在许多隐含的关系,这些关系从仅阅读代码本身来看并不明显。

有经验的编码人员可以精心设计出具有清晰,易于理解的体系结构的设计,而无需文档即可显而易见。但是您实际上看到过多少个这样的程序?


15
以及为什么“神话人月”成为一种自我实现的预言,没有人花时间为新开发人员写出所有这些内容,因为他们对新开发人员的想法是新鲜的,并且该项目没有落伍。
JeffO

3
我同意您在这里提出的所有观点。我不喜欢他的职位中使用的OP一词how a class works。这随着时间和维护而改变。尽管我的团队没有在源代码中提及以上内容。我们维护一个包含决策的Wiki,并将有关设计决策的闲置渠道讨论复制到文档中(我们提供了从决策摘要和结论到原始注释的链接,因此我们不必重新哈希旧的决策)。一切都在github中完成(所以都放在一个地方)。
马丁·约克

1
我唯一的问题是在全球范围内应用。此类足够复杂,并且具有某些陷阱,显然它确实很有用(尽管您最终还是要处理Comment Rot)。当一个班级更加明显时,评论可能会变得多余。
deworde 2015年

1
“经验丰富的编码人员可以精心设计出具有清晰,易于理解的体系结构的设计,而无需编写文档就很明显。但是实际上您看到了多少个这样的程序。”确实如此,文档的质量永远不会比编码。架构良好的代码往往具有良好的文档,即使毫无意义。架构欠佳的代码具有“ x递增1”这样的注释
deworde

3
我完全同意这个答案,如果我在代码中找到类似OP的示例,我将非常高兴。只需添加一个即可:考虑在评论中添加一个日期,以向最终读者提示描述的新鲜度,并在每次更新文本时对其进行更新。
Svalorzen

36

使用大型代码库的关键是不必阅读整个代码库即可进行更改。为了使程序员能够快速找到他要查找的代码,应该对代码进行组织,并使组织清晰可见。也就是说,代码中的每个逻辑单元,从可执行文件,库,命名空间,到单个类,都应有明显的责任。因此,我不仅要记录源文件,还要记录它们所在的目录。

程序员的注释也为设计决策提供了背景知识。尽管这可能是有价值的信息,但我会将其与责任说明分开(以使读者可以选择是否要阅读类的责任或它的设计原理),并将其移至与它描述的来源接近的地方。尽可能地提高代码在更新时文档更新的机会(仅当我们可以相信文档的准确性时文档才有用-过时的文档可能比没有文档更糟糕!)。

就是说,文档应该保持DRY,即不要重复可能已经用代码表达或已经在其他地方描述的信息(诸如“由于文档状态”之类的警告标志)。特别是,将来的维护人员将精通项目的编程语言,就像他们使用的是英语一样。用注释对实现进行释义(当人们为自己的文档感到骄傲时,我经常会看到它)没有任何好处,并且可能与实现有所不同,特别是如果文档与它描述的代码不符时。

最后,应在整个项目中对文档结构进行标准化,以便每个人都能找到它(这是错误跟踪中Peter文档的一团糟,在Wiki中是Sue,在自述文件中是Alan,在源代码中是John……) 。


您的第一句话就是我对此的看法。大型代码库应由许多较小的组件组​​成,在这些组件中,新程序员可以可靠地更改一个程序,而不会危及其他程序。
乔恩·切斯特菲尔德

1
将其尽可能靠近其描述的源代码移动,以最大程度地在代码为时更新文档。这是宝贵的经验。
laike9m 2015年

将DRY作为文档指南非常重要!这将自动设置聚焦权,并禁止著名的令人讨厌的“ // x递增1”注释。
汉斯·彼得·斯特尔

13

我不同意这是一个很好的方法,主要是因为

  1. 当您重构项目时,四处移动方法,文档就会中断。

  2. 如果文档没有正确更新,将导致混乱,而不是帮助理解代码。

如果您具有针对每个方法的单元测试/针对每个模块的集成测试,则与代码注释相比,这将是一个更易于维护且更易于理解的自我文档。

是的,拥有适当的目录结构肯定会有所帮助。


测试+1是理解代码库的最佳方法。单元测试,集成测试,验收测试都讲述了有关应用程序应该如何工作以及如何使用的故事。
BZink

7

我个人是高级设计文档的爱好者-最好在编写任何代码之前编写这些文档-该文档概述了设计,并提供了类和资源的列表。自上而下的设计大大简化了工作-您的操作可能是“游戏引擎->硬件->控制器->游戏杆”;因此,一个新的程序员告诉“修复'xyz控制器上的'a'按钮”至少会知道从哪里开始寻找。

太多的现代语言倾向于将代码分解为数百个小文件,因此,即使是中等规模的项目,要找到正确的文件也可能是一个挑战。


16
20年前,我所有的代码都保存在一个巨大的文件中。现在有成千上万的小文件和测试文件。这是有充分的理由的,它反映了20多年的软件开发(一般的生态系统,而不是我的知识)。Waaay太久了,无法发表评论。
Michael Durrant

4
啊,古老的瀑布方法在编码开始之前就编写了一个单一的,所有包含的,不可变的真相,这甚至使它在实现上不可能偏离所说的真相。
jwenting

2
@jwenting:您不必走那么远。但是,对您正在构建的东西有所了解仍然是一件好事。
罗伯特·哈维

1
当然,没有对如何正确地分解规则以及在何处违反规则的警告,您很快就会拥有一个过时或磨石的文档。“我需要增加一门新课;吃时间的巨兽Documanto!”
deworde

2
@deworde:我读这句话是“太懒于维护文档”。
罗伯特·哈维

6

如果代码库很大,我将尝试提供一个设计文档,其中列出了其设计和实现的关键要素。这里的目的不是要详细说明所使用的任何类,而是要提供编码的关键和进入设计的思想。它为系统,其组件及其应用提供了一个总体上下文。

设计文件中应包括的内容是:

  • 应用架构
  • 逻辑代码结构
  • 数据流
  • 使用的关键模式及其使用的动机
  • 代码源结构
  • 如何构建它(这提供了对隐式依赖关系和物理代码源结构的深入了解)

之后,应该适当地完成有关类和函数/方法的文档。特别是公共API;应该清楚在每种情况下以下所有内容;

  • 前提条件
  • 特效
  • 不变量
  • 异常条件(抛出)

+1比描述每个类要好,因为它会比整体设计更快地过时。
Lode

4

我发现使新开发者更容易理解代码库的最重要规则是完美的协议,代价很高。

如果新开发人员必须完全了解他们正在使用的系统,那么它将阻止所有机会在职学习。我认为程序员的笔记是一个很好的开始,但是我会走得更远。尝试编写新的代码,如果重新使用它们,它们将使开发人员能够实时确定自己在做什么,而不是要求他们先学习再做。对于您所知的情况,断言之类的小事情永远都不会发生,而解释断言为何有效的注释则大有帮助。如果您做错了任何事情,编写代码也会正常失败,而不是进行段错误。


我的原则是,意见应约WHY,而不是如何。该代码描述了HOW。
2015年

3

我看到了带有文档的大型类,并且在阅读了文档之后,我不知道该类应该做什么,以及为什么有人会使用它!同时,我需要一些功能,并且我绝对确定必须有一个类来处理它,并且在任何地方都找不到它-因为没有文档将我从我需要的知识引导到该类。正在做。

因此,我在文档中想要的第一件事就是一句话,一个类做什么,以及为什么要使用它。原始问题中的评论在这方面做得很好。阅读这些注释后,如果我有一个由于无法解释其提供的值而无法正常工作的操纵杆,我将知道要检查的代码。


0

类似于@meriton所说的,将代码分解为单独的组件。更好的是,将代码库分解为单独的程序包(JAR,Gem,Eggs等),以使组件的分离更加清晰。如果存在错误,则开发人员仅需要找到该错误所在的,并且(希望)仅将其修复。更不用说,单元测试更容易,并且您可以利用依赖管理。

另一个解决方案:缩小代码库。代码越少,越容易理解。重构出未使用或重复的代码。使用声明式编程技术。当然,这很费力,而且通常是不可能或不实际的。但这是一个值得的目标。正如杰夫·阿特伍德(Jeff Atwood)所写:最好的代码根本没有代码


-1

对于复杂的系统,不仅要记录每个文件,还要记录它们的交互作用和层次结构,以及程序的结构和原因,这是值得的。

例如,游戏引擎通常非常复杂,在经过数百层抽象之后,很难确定什么叫什么。可能需要创建一个类似“ Architecture.txt”的文件来解释代码的结构以及为什么如此,以及为什么那里没有毫无意义的抽象层。


-7

这可能部分是因为单个程序员很难编写它,因为每个人都只能理解他们的项目部分。

有时您可以从项目经理的注释中获取此信息,但这仅是您将获得的,因为他们很少会用这种格式重写其注释。


7
如果您查看github,则会在README.md文件中找到很多具有此类注释的项目。一般而言,它已成为git文化的一部分,尤其是对于javascript项目,对于大多数人而言,它们将不使用没有此类高级文档的库。因此,“没有程序员会写”是不正确的,因为您只需要查看jQuery或socket.io之类的东西,然后找到编写此类内容的程序员即可。README文件不准确也会生成错误报告,这也已成为一种文化。
slebetman

1
这似乎并不能回答这个问题,该问题是在寻找为什么建议的文档样式行不通的原因,以及文档标准。
user52889

5
如果您有一个由一组产品开发人员组成的程序员,并且每个程序员都只了解他们所使用的特定代码,那么不仅您的团队由于荒唐的总线因素而无法正常工作,而且对代码的质量提出了质疑。如何在不了解同一系统中其余代码的情况下将代码集成到产品中?
Lightness Races in Orbit
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.