第 17 章 一致性
Chapter 17 Consistency
Consistency is a powerful tool for reducing the complexity of a system and making its behavior more obvious. If a system is consistent, it means that similar things are done in similar ways, and dissimilar things are done in different ways. Consistency creates cognitive leverage: once you have learned how something is done in one place, you can use that knowledge to immediately understand other places that use the same approach. If a system is not implemented in a consistent fashion, developers must learn about each situation separately. This will take more time.
一致性是一个强大的工具,可以降低系统复杂性并使其行为更明显。如果系统是一致的,则意味着相似的事情以相似的方式完成,而不同的事情则以不同的方式完成。一致性创造了认知杠杆:一旦您了解了某个地方的工作方式,就可以使用该知识立即了解其他使用相同方法的地方。如果一个系统的没有以一致的方式实施,则开发人员必须分别了解每种情况。这将花费更多时间。
Consistency reduces mistakes. If a system is not consistent, two situations may appear the same when in fact they are different. A developer may see a pattern that looks familiar and make incorrect assumptions based on previous encounters with that pattern. On the other hand, if the system is consistent, assumptions made based on familiar-looking situations will be safe. Consistency allows developers to work more quickly with fewer mistakes.
一致性减少了错误。如果系统不一致,两种情况可能看起来是一样的,但实际上它们是不同的。开发人员可能会看到一个看起来很熟悉的模式,并根据以前遇到的模式做出错误的假设。另一方面,如果系统是一致的,则基于看起来很熟悉的情况所做的假设就会很安全。一致性允许开发人员更快速的工作,并减少错误。
17.1 Examples of consistency 一致性示例
Consistency can be applied at many levels in a system; here are a few examples.
一致性可以应用于系统中的许多层面。这里有一些例子。
Names. Chapter 14 has already discussed the benefits of using names in a consistent way.
名字。第 14 章已经讨论了以一致的方式使用名称的好处。
Coding style. It is common nowadays for development organizations to have style guides that restrict program structure beyond the rules enforced by compilers. Modern style guides address a range of issues, such as indentation, curly-brace placement, order of declarations, naming, commenting, and restrictions on language features considered dangerous. Style guidelines make code easier to read and can reduce some kinds of errors.
编码风格。如今,开发组织通常会制定风格指南,将程序结构限制在编译器所强制执行的规则之外。现代风格指南解决了一系列问题,例如缩进,大括号放置,声明顺序,命名,注释以及对认为危险的语言功能的限制。风格指南使代码更易于阅读,并且可以减少某些类型的错误。
Interfaces. An interface with multiple implementations is another example of consistency. Once you understand one implementation of the interface, any other implementation becomes easier to understand because you already know the features it will have to provide.
接口。具有多个实现的接口是一致性的另一个示例。一旦了解了接口的一种实现,其他任何实现都将变得更易于理解,因为您已经知道它将必须提供的功能。
Design patterns. Design patterns are generally-accepted solutions to certain common problems, such as the model-view-controller approach to user interface design. If you can use an existing design pattern to solve the problem, the implementation will proceed more quickly, it is more likely to work, and your code will be more obvious to readers. Design patterns are discussed in more detail in Section 19.5.
设计模式。设计模式是某些常见问题的普遍接受的解决方案,例如用于用户界面设计的模型-视图-控制器方法。如果您可以使用现有的设计模式来解决问题,则实现会更快地进行,更有可能奏效,并且您的代码对读者来说也会更明显。设计模式将在 19.5 节中详细讨论。
Invariants. An invariant is a property of a variable or structure that is always true. For example, a data structure storing lines of text might enforce an invariant that each line is terminated by a newline character. Invariants reduce the number of special cases that must be considered in code and make it easier to reason about the code’s behavior.
不变量。不变量是一个变量或结构的属性,它总是为真的。例如,存储文本行的数据结构可能会强制要求每行以换行符终止。不变量减少了代码中必须考虑的特殊情况的数量,并且更容易推断代码的行为。
17.2 Ensuring consistency 确保一致性
Consistency is hard to maintain, especially when many people work on a project over a long time. People in one group may not know about conventions established in another group. Newcomers don’t know the rules, so they unintentionally violate the conventions and create new conventions that conflict with existing ones. Here are a few tips for establishing and maintaining consistency:
一致性很难保持,尤其是当许多人长时间从事一个项目时。一个小组的人可能不了解另一小组中建立的约定。新来的人不了解约定,因此他们无意间违反了约定,并创建了与现有约定冲突的新约定。以下是建立和保持一致性的一些技巧:
Document. Create a document that lists the most important overall conventions, such as coding style guidelines. Place the document in a spot where developers are likely to see it, such as a conspicuous place on the project Wiki. Encourage new people joining the group to read the document, and encourage existing people to review it every once in a while. Several style guides from various organizations have been published on the Web; consider starting with one of these.
文档。创建一个文档,列出最重要的总体约定,例如编码风格指南。将文档放置在开发人员可能会看到的位置,例如项目 Wiki 上的显眼位置。鼓励新成员加入小组阅读文档,并鼓励现有人员不时的回顾一下。一些来自不同组织的风格指南已经在网上发布;考虑从其中之一开始。
For conventions that are more localized, such as invariants, find an appropriate spot in the code to document them. If you don’t write the conventions down, it’s unlikely that other people will follow them.
对于那些更加本地化的约定,例如不变量,请在代码中找到合适的位置进行记录。如果您不把这些约定写下来,那么其他人不太可能会遵循它们。
Enforce. Even with good documentation, it’s hard for developers to remember all of the conventions. The best way to enforce conventions is to write a tool that checks for violations, and make sure that code cannot be committed to the repository unless it passes the checker. Automated checkers work particularly well for low-level syntactic conventions.
执行。即使有好的文档,开发人员也很难记住所有约定。执行约定的最佳方法是编写一个检查违规的工具,并确保代码在通过检查器之前不能提交到存储库。自动检查器对于低级别的语法约定特别有用。
One of my recent projects had problems with line termination characters. Some developers worked on Unix, where lines are terminated by newlines; others worked on Windows, where lines are normally terminated by a carriage-return followed by a newline. If a developer on one system made a small edit to a file previously edited on the other system, the editor would sometimes replace all of the line terminators with ones appropriate for that system. This gave the appearance that every line of the file had been modified, which made it hard to track the meaningful changes. We established a convention that files should contain newlines only, but it was hard to ensure that every tool used by every developer followed the convention. Every time a new developer joined the project, we would experience a rash of line termination problems while that developer adjusted to the convention.
我最近的一个项目有行终止字符的问题。一些开发人员在 Unix 上工作,行被换行终止;其他的工作在 Windows 上,行通常由一个 carriage-return 后跟一个换行符来结束。如果一个系统上的开发人员对先前在另一个系统上编辑过的文件进行了小的编辑,那么编辑器有时会将所有行终止符替换为适合该系统的行终止符。这给人的感觉是文件的每一行都被修改了,这使人很难追踪有意义的变化。我们建立了一个约定,即文件应该只包含换行,但是很难确保每个开发人员使用的每个工具都遵循这个约定。每当一个新的开发人员加入这个项目,我们就会遇到大量的行终止问题,而该开发者才会适应这个约定。
We eventually solved this problem by writing a short script that was executed automatically before changes are committed to the source code repository. The script checks all of the files that have been modified and aborts the commit if any of them contain carriage returns. The script can also be run manually to repair damaged files by replacing carriage-return/newline sequences with newlines. This instantly eliminated the problems, and it also helped train new developers.
我们最终解决了这个问题,通过编写了一个简短的脚本,该脚本在更改提交到源代码存储库之前自动执行。该脚本检查所有已修改的文件,如果其中任何一个包含回车符,则中止提交。该脚本也可以手动运行,通过用换行符替换回车/换行符序来修复损坏的文件。这一下子就消除了问题,并且还有助于培训新的开发人员。
Code reviews provide another opportunity for enforcing conventions and for educating new developers about the conventions. The more nit-picky that code reviewers are, the more quickly everyone on the team will learn the conventions, and the cleaner the code will be.
代码审查为实施约定和向新开发者提供有关约定的教育提供了另一个机会。代码审阅者越挑剔,团队中的每个人学习约定的速度就越快,并且代码越清晰。
When in Rome ... The most important convention of all is that every developer should follow the old adage “When in Rome, do as the Romans do.” When working in a new file, look around to see how the existing code is structured. Are all public variables and methods declared before private ones? Are the methods in alphabetical order? Do variables use “camel case,” as in firstServerName, or “snake case,” as in first_server_name? When you see anything that looks like it might possibly be a convention, follow it. When making a design decision, ask yourself if it’s likely that a similar decision was made elsewhere in the project; if so, find an existing example and use the same approach in your new code.
在罗马时……最重要的约定是每个开发人员都应遵循古老的格言“在罗马时,就像罗马人一样。” 在处理新文件时,请环顾四周以了解现有代码的结构。是否在私有变量和方法之前声明了所有公共变量和方法?方法是否按字母顺序排列?变量是像 firstServerName 中那样使用“camel case”,还是像 first_server_name 中那样使用“snake case”?当您看到任何看起来可能是约定的内容时,请遵循该约定。在做出设计决策时,请问自己是否有可能在项目的其他地方做出了类似的决策;如果是这样,请找到一个现有示例,并在新代码中使用相同的方法。
Don’t change existing conventions. Resist the urge to “improve” on existing conventions. Having a “better idea” is not a sufficient excuse to introduce inconsistencies. Your new idea may indeed be better, but the value of consistency over inconsistency is almost always greater than the value of one approach over another. Before introducing inconsistent behavior, ask yourself two questions. First, do you have significant new information justifying your approach that wasn’t available when the old convention was established? Second, is the new approach so much better that it is worth taking the time to update all of the old uses? If your organization agrees that the answers to both questions are “yes,” then go ahead and make the upgrade; when you are done, there should be no sign of the old convention. However, you still run the risk that other developers will not know about the new convention, so they may reintroduce the old approach in the future. Overall, reconsidering established conventions is rarely a good use of developer time.
不要改变现有约定。抵制“改善”现有约定的冲动。拥有一个“更好的主意”并不是引入不一致的充分借口。您的新想法可能确实更好,但是一致性胜于不一致的价值几乎总是大于一种方法胜过另一种方法的价值。在引入不一致的行为之前,请问自己两个问题。首先,您是否拥有大量的新信息来证明您的方法在建立旧约定时是不可用的?其次,新方法是否值得花时间更新所有旧用法?如果您的组织同意对两个问题的回答均为“是”,那么就去进行更新;当您完成后,应该没有旧约定的迹象。然而,您仍然面临着其他开发人员不了解新约定的风险,因此他们将来可能会重新引入旧方法。总体而言,重新考虑已建立的约定很少会很好能很好的利用开发人员时间。
17.3 Taking it too far 走得太远
Consistency means not only that similar things should be done in similar ways, but that dissimilar things should be done in different ways. If you become overzealous about consistency and try to force dissimilar things into the same approach, such as by using the same variable name for things that are really different or using an existing design pattern for a task that doesn’t fit the pattern, you’ll create complexity and confusion. Consistency only provides benefits when developers have confidence that “if it looks like an x, it really is an x.”
一致性不仅意味着相似的事情应该以相似的方式完成,而且不同的事情也应该以不同的方式完成。如果您对一致性过于热衷,并试图将不同的事物强制采用相同的方法,例如对确实不同的事物使用相同的变量名,或者对不适合该模式的任务使用现有的设计模式,那么会造成复杂性和混乱。一致性只有在开发人员确信“如果看起来像 x 时,它确实是 x”时才会带来好处。
17.4 Conclusion 结论
Consistency is another example of the investment mindset. It will take a bit of extra work to ensure consistency: work to decide on conventions, work to create automated checkers, work to look for similar situations to mimic in new code, and work in code reviews to educate the team. The return on this investment is that your code will be more obvious. Developers will be able to understand the code’s behavior more quickly and accurately, and this will allow them to work faster, with fewer bugs.
一致性是投资心态的另一个例子。确保一致性的工作将需要一些额外的工作:确定约定,创建自动检查程序,寻找类似情况以在新代码中模仿,并在代码审查中教育团队成员。这项投资的回报是您的代码将更加明显。开发人员将能够更快,更准确地了解代码的行为,这将使他们能够更快地工作,并减少错误。