第 4 章. 关注点分离
本作品已使用人工智能进行翻译。欢迎您提供反馈和意见:translation-feedback@oreilly.com
"关注点分离"......就是我所说的 "将注意力集中在某个方面":这并不意味着忽略其他方面,而只是公正地对待这样一个事实,即从这个方面来看,其他方面是无关紧要的。这就是同时具有单轨和多轨思维。
埃德斯格-戴克斯特拉,"论科学思想的作用"。
我们的源代码越来越多。 根据语言的不同,一个源代码文件有 50-75 行。这在许多显示器上都超过了一屏,当然也超过了本书的印刷页。
在进入下一个功能之前,我们要花一些时间重构代码。这是本章和接下来三章的主题。
测试和生产代码
到目前为止,我们已经编写了两种不同类型的代码。
-
解决 Money 问题的代码。这包括
Money和Portfolio以及其中的所有行为。我们称之为生产代码。 -
验证问题是否正确解决的代码。这包括所有测试和支持这些测试所需的代码。我们称之为测试代码。
这两类代码之间有相似之处:它们使用相同的语言,我们连续快速地编写它们(通过现在已经耳熟能详的红-绿-重构循环),并将两者都提交到代码库中。不过,这两种代码之间也有一些关键的不同之处。
单向依赖性
测试代码必须依赖于生产代码,至少依赖于生产代码中需要测试的部分。 但是,不应该有其他方向的依赖。
目前,我们每种语言的所有代码都在一个文件中,如图 4-1 所示。因此,要确保从生产代码到测试代码之间没有意外的依赖关系并不容易。从测试代码到生产代码之间存在隐含的依赖关系。这会产生一些影响:
-
在编写代码时,我们必须小心谨慎,避免在生产代码中意外使用任何测试代码。
-
在阅读代码时,我们必须识别代码的使用模式,同时注意缺少的模式,即生产代码不能调用任何测试代码。
图 4-1. 当测试代码和生产代码位于同一模块时,前者对后者的依赖是隐含的
重要
测试代码依赖于生产代码,但不应存在反向依赖。
如果生产代码依赖于测试代码,可能会产生什么不良后果? 在特别糟糕的情况下,它可能会误导我们走上这样一条道路:经过测试的代码路径是 "纯净的",而没有经过测试的路径则充满了错误。图 4-2显示了汽车发动机控制单元的部分伪代码。如果发动机正在接受排放合规性测试,那么代码的工作方式与发动机在 "真实世界 "中的使用方式是不同的。
图 4-2. 生产代码对测试代码的意外依赖会导致生产代码路径以未经测试的方式出现异常行为
如果你对这种 "在测试中表现最佳 "的公然情况在现实中是否会发生持怀疑态度,我们建议你阅读大众汽车的排放丑闻,图 4-2中的伪代码就来自于该丑闻。1
拥有单向依赖关系,即生产代码不以任何方式依赖测试代码,因此在测试时不会出现不同的行为,这对于确保不会出现这种性质的缺陷(无论是意外还是恶意的)至关重要。
依赖注入
依赖注入是一种将对象的创建与使用分离开来的做法。 它增强了代码的内聚力,降低了代码的耦合度。2依赖注入要求不同的代码单元(类和方法)相互独立。将测试代码和生产代码分开是促进依赖注入的重要前提。 ...