第 1 章:整洁的代码
-
杂乱的总量随着时间的推移而增加。
-
从头开始恢复过时的系统非常困难。重构和增量改进将是最好的选择。
-
在混乱的代码库中,原本只需要几个小时的任务可能需要几天或几周才能完成。
-
花时间快速行动。
-
干净的代码可以很好地完成一件事。糟糕的代码试图做太多事情。
-
干净的代码经过了良好的测试。
-
当阅读编写良好的代码时,每个函数都大致符合您的预期。
-
如果您不同意具有多年经验的人教授的原则,您至少应该在忽略之前考虑他们的观点。
-
代码的读取次数远多于编写次数。
-
更容易阅读的代码也更容易更改。
-
让代码库比你发现它时更好(童子军规则)。
第 2 章:名字的含义
-
仔细选择变量名称。
-
选择好名字是很困难的。
-
变量或函数的名称应表明它是什么以及如何使用它。
-
避免使用单字符变量名称,常用名称除外,例如循环中的计数器变量 i。
-
避免在变量名中使用缩写。
-
变量名称应该是可发音的,以便您可以谈论它们并大声说出来。
-
使用易于查找的变量名称。
-
类和对象必须具有名词形式的名称。
-
方法和函数名称必须是动词或动名词对。
第 3 章:函数
-
函数应该很小。
-
该函数必须执行一项操作。
-
函数必须有描述性名称。
-
提取 if/else 主体中的代码或将语句转换为明确命名的函数。
-
限制函数接受的参数数量。
-
如果函数需要许多配置参数,请考虑将它们组合成单个配置选项变量。
-
函数必须是纯函数,这意味着它们没有副作用,并且不会修改其输入参数。
-
该函数必须是命令或查询,但不能同时是命令或查询(命令查询分离)。
-
从代码中删除错误和异常比在代码中保留错误更好。
-
将重复的代码提取到明确命名的函数中(不要重复自己)。
-
单元测试使重构变得更加容易。
第 4 章:评论
-
评论可能不正确。它们可能一开始就是错误的,或者它们最初可能是准确的,但随着代码的变化,它们会随着时间的推移而变得过时。
-
使用注释来描述为什么要这样写,而不是解释正在发生的事情。
-
通过使用明确命名的变量并将代码段提取到明确命名的函数中,通常可以避免注释。
-
使用一致的前缀为 TODO 注释添加前缀,以便更容易查找。定期查看并清理您的 TODO 评论。
-
不要仅仅为了使用 Javadoc 而使用它们。描述一个方法的作用、它接受什么参数以及它返回什么的注释往好了说是多余的,往坏了说是误导性的。
-
评论应包括读者需要的所有相关信息和上下文。写评论的时候不要偷懒。
-
由于版本控制和 gitblame,不需要日志注释和文件作者注释。
-
不要注释掉死代码。删除它即可。如果您认为将来需要代码,这就是版本控制的用途。
第 5 章:格式化
-
作为一个团队,选择一组用于格式化代码的规则,然后一致地应用这些规则。无论您同意什么规则,都需要达成协议。
-
使用自动代码格式化和代码分析器。不要依赖人们手动查找并修复每个格式错误。在审查代码时,这是低效、低效且浪费时间的。
-
在代码行之间添加垂直空格,以在视觉上分隔相关的代码块。您所需要的只是在组之间创建一条新线。
-
小文件比大文件更容易阅读、理解和移动。
-
变量应该在使用它们的地方附近声明。对于小型函数,这通常位于函数的顶部。
-
即使对于简短的函数或 if 语句,仍然要正确格式化它们,而不是将它们写在一行上。
第 6 章:对象和数据结构
-
对象中的实现细节必须隐藏在对象的接口后面。通过提供一个供对象的使用者使用的接口,您可以更轻松地在以后重构实现细节,而不会造成重大更改。抽象使重构变得更加容易。
-
任何给定的代码片段都不应该了解它所操作的对象的内部结构。
-
使用对象时,您应该要求它执行命令或查询,而不是询问它的内部结构。
第 7 章:纠正错误
-
错误处理不应干扰模块中的其余代码。
-
从代码中删除错误和异常比在代码中保留错误更好。
-
编写带有错误的测试,以确保您的代码能够识别它们并且不会错过它们。
-
错误消息应该提供信息,包含有效排除故障可能需要的所有必要上下文。
-
将第三方 API 包装在薄薄的抽象层中,使得将来更容易用一个库替换另一个库。
-
将第三方 API 包装在薄薄的抽象层中可以更轻松地在测试期间模拟库。
-
使用特殊情况模式或空对象模式来处理异常行为,例如当某些数据不存在时。
第 8 章:边界
-
第三方库允许您外包各种任务,从而帮助加快产品交付速度。
-
编写测试以确保您正确使用第三方库。
-
使用适配器模式来弥合第三方库的 API 和您想要的 API 之间的差距。
-
将第三方 API 包装在薄薄的抽象层中,使得将来更容易用一个库替换另一个库。(重复第 7 章)
-
将第三方 API 包装在薄薄的抽象层中可以更轻松地在测试期间模拟库。(重复第 7 章)
-
尽量不要告诉您的应用程序太多有关任何第三方库的详细信息。
-
依赖于你能控制的东西比依赖于你无法控制的东西更好。
第 9 章:单元测试
-
测试代码应该与生产代码一样干净(有一些例外,通常与内存或效率有关)。
-
当生产代码发生变化时,测试代码也会发生变化。
-
测试有助于保持生产代码的灵活性和可维护性。
-
测试允许您进行更改,让您可以自信地进行重构,而不必担心自己没有注意到。
-
使用排列-执行-断言(也称为构建-操作-检查、设置-练习-验证或给定-何时-然后)模式构建测试。
-
使用特定于域的函数使测试更易于编写和阅读。
-
每次测试给一个概念评分。
-
测试必须快。
-
测试必须是独立的。
-
测试必须是可重复的。
-
测试不应需要确认。
-
测试应该及时编写,在编写生产代码之前或之后不久,而不是几个月后。
-
如果您的测试很糟糕,那么您的代码中可能会存在错误。
第10章:课程
-
班级规模应该很小。
-
类应该只负责一件事,并且应该只有一个改变的原因(单一责任原则)。
-
如果您无法为类起一个清晰的名称,那么它可能太大了。
-
当你让一段代码可以工作时,你的工作并没有结束。下一步将是重构和清理代码。
-
在应用程序中使用许多小类而不是几个大类可以减少开发人员在处理任何给定任务时必须理解的信息量。
-
拥有一个好的测试套件可以让您在将大类分解为更小的类时充满信心地进行重构。
-
类应该对扩展开放,但对修改封闭(开闭原则)。
-
接口和抽象类创建了接缝,使测试变得更加容易。
第11章:系统
-
使用依赖注入使开发人员能够灵活地将具有适当接口的任何对象传递给另一个类。
-
使用依赖项注入在应用程序中的对象之间创建接口,以使测试更容易。
-
软件系统不像建筑物,需要提前设计。它们更像是随着时间的推移而发展和扩张的城市,以适应当前的需求。
-
推迟到最后关键时刻才做出决定。
-
使用特定于领域的语言,以便领域专家和开发人员使用相同的术语。
-
不要使您的系统过于复杂。使用最简单有效的方法。
第12章:部署
-
无法测试的系统无法验证,无法验证的系统永远不应该部署。
-
编写测试可以带来更好的设计,因为易于测试的代码通常使用依赖项注入、接口和抽象。
-
一组好的测试将消除重构时破坏应用程序的恐惧。
-
重复代码会带来更多风险,因为代码中有更多地方可以更改,甚至更多地方可以隐藏错误。
-
你现在编写的代码更容易理解,因为你深入地理解它。其他人想要快速达到同样的理解水平并不容易。
-
软件项目的大部分成本与长期维护有关。
-
测试充当应用程序应该(以及确实)如何表现的活生生的文档。
-
一旦您的代码有效,就不要再进行任何操作。花点时间让它变得更清晰、更容易理解。
-
在不久的将来,下一个阅读您代码的人很可能就是您。通过编写易于理解的代码来善待未来的自己。
-
抵制教条。拥抱实用主义。
-
成为一名真正优秀的软件工程师需要几十年的时间。您可以通过向周围的专家学习并学习常用的设计模式来加快学习速度。
第13章:并行性
-
编写并行代码很困难。
-
偶尔出现的难以重现的错误和问题通常是并发问题。
-
测试并不能保证您的应用程序没有错误,但可以最大限度地降低风险。
-
了解常见的并发问题及其可能的解决方案。
第14章:顺序细化
-
干净的代码通常不是从一张白纸开始的。您首先编写一个粗略的解决方案,然后重构它以使其更清晰。
-
一旦代码开始工作就停止工作是错误的。在它已经发挥作用后,花点时间让它变得更好。
-
骚乱正在逐渐加剧。
-
如果您发现自己陷入添加功能太困难或花费太长时间的困境,请停止编写功能并开始重构。
-
增量变化通常比从头开始重建更好。
-
使用测试驱动开发 (TDD) 进行大量非常小的更改。
-
好的软件设计包括分离代码中的关注点并将代码分成更小的模块、类和文件。
-
弄乱后立即清理比稍后清理更容易。
第 15 章:JUnit 内部结构
-
负变量名称或条件表达式比正变量名称或条件表达式更难理解。
-
重构是一个充满尝试和错误的迭代过程。
-
让代码库比你发现它时更好(童子军规则)。(从第 1 章重复)
第 16 章:重构 SerialDate
-
代码审查和对代码的批评使我们变得更好,我们应该对此表示欢迎。
-
首先让代码工作,然后修复它。
-
并非每一行代码都需要测试。
第17章:气味和启发法
-
干净的代码不是一套规则,而是决定你工作质量的价值观体系。
GO TO FULL VERSION