关于我的一点背景:我是一名自学成才的程序员,6 年前加入 MegaCorp(TM) 时,他开始使用 Python 并学习了 Java。拥有数学学位,我在算法和批判性思维方面相当扎实(不是双关语),但我经常发现自己在数据结构、设计或其他 CompSci 基础知识方面存在差距,而我的同行在他们的计算机科学中学到了这些基础知识培训班。
为此,我向团队中的一位高级工程师请教了一本书,以帮助填补我的空白,他建议使用Clean Architecture。
我大约完成了三分之一,并且对这些建议的主要激励因素之一感到非常困惑。鲍勃叔叔提出了许多想法和原则(包括我以前听说过的SOLID原则,尽管我仍在掌握 Liskov 替换原则)旨在“保护”系统的某些部分免受要求改变。有几个例子,但最清楚的是第 73 页:
如果组件 A 应该被保护免受组件 B 的更改,那么组件 B 应该依赖于组件 A。
(我应该注意到,在没有任何我能看到的实际定义的情况下,我认为“组件”等同于 Java 包,尽管我认为如果“组件”可以应用相同的思维过程" 是一个单独的服务 - 两者都应该为用户提供稳定可用的接口,无论是本地调用还是通过网络调用)
这种说法没有提供任何证据,对我来说也不是不言而喻的。考虑ClassA
组件(包)中的类在组件中ComponentA
调用DoStuffReturn doStuff(DoStuffInput input, String someOtherArg)
的情况- 并且其中调用是通过直接依赖关系或通过对接口的依赖关系(不是in,正如 Clean Architecture 所建议的那样)ClassB
ComponentB
ComponentB
ComponentA
- 如果 B 中的更改是功能更改,而不是签名更改(即 - 对于相同的
DoStuffInput
输入String
,DoStuffReturn
返回不同的),则 A 中不需要更改:ClassA
的调用ClassB.doStuff
保持有效(相同的参数和返回类型)ClassA
的单元测试(应该使用 mockedClassB
s)应该仍然通过- 任何测试如何
ClassA
和ClassB
协作的功能/集成测试都需要更新他们的期望,但这不是改变ComponentA
(除非这些测试在ComponentA
- 我通常看到它们在一个ComponentAIntegrationTests
包中外部化,但我想它们也可以放在一起. 但这似乎不是本书所暗示的 - 它似乎是在谈论对代码的更改,而不是对测试的更改)
- 如果 B 中的更改是对 以外的方法的签名更改
doStuff
,则 A 不需要任何更改 - 如果 B 中的更改是对 的签名更改
doStuff
,则 A将需要更改 - 但如果接口也在 A 中,情况就是如此。
(请注意,在清洁架构提倡的设置下,其中提供类的接口在消费组件(A)中,只有第一种情况会构成 B 的变化 - 所以这是我们真正需要关注的唯一一个和)
我错过了什么?如果 ComponentA 依赖于 ComponentB,那么在什么情况下 ComponentB 中的类的更改需要 ComponentA 的更改?
(请注意,我并不是反对使用接口——它们还有许多其他好处,尤其是允许在合同的“双方”同时开发,并允许交换接口的各种实现)