隐式依赖也是依赖
Implicit Dependencies Are also Dependencies
Once upon a time a project was developed in two countries. It was a large project with functionality spread across different computers. Each development site became responsible for the software running on one computer, had to fulfill its share of requirements and do its share of testing. The specification of the communication protocol became an early architectural cornerstone.
从前,有一个在2个国家开发的项目,它的功能分散在不同的电脑上。
每个开发站负责这个软件在一台电脑上运行,并且必须完成被分配的需求及测试。
这个交流协议的规定,变成了项目最早的架构基础。
A few months later, each site declared victory: The software was finished! The integration team took over and plugged everything together. It seemed to work. A bit. Not much though: As soon as the most common scenarios were covered and the more interesting scenarios were tested, the interaction between the computers became unreliable.
几个月之后,各个站点都宣布胜利:这个软件完成了!
集成团队接管了工程,并将一切组合在一起。好像可以了。
等等,现在有个小问题:虽然大部分的模块都覆盖了测试,但电脑之间的相互作用却十分不可靠。
Confronted with this finding, both teams held up the interface specification and claimed their software conformed to it. This was found to be true. Both sides declared victory, again. No code was changed, and they developed happily ever after.
面对这个发现,各个团队都举起了接口规范书,表示自己的软件完全符合规范。
这确实是真的。然后双方又宣布了成功。他们没有修改任何代码,从此还是高高兴兴地开发。
The moral is that you have more dependencies than all your attempts for decoupling will let you assume you have.
这个故事的寓意是,经过各种解耦的努力,你比你自以为的解耦具有更多的依赖。
Software components have dependencies, more so in large projects, even more when you strive to increase your code reuse. But that doesn’t mean you have to like them: Dependencies make it hard to change code. Whenever you want to change code others depend on, you will encounter discussion and extra work, and resistance from other developers who would have to invest their time. The counterforces can become especially strong in environments with a lengthy development micro cycle, such as C++ projects or in embedded systems.
软件组件之间相互依赖,在大项目中依赖更多,当你努力提高代码重用性时,依赖甚至更多。
但是那并不意味着你必须喜欢依赖:依赖让修改代码十分困难。
每当你想修改他人依赖的代码时,你就会遇到讨论以及他们额外的工作,以及来自其他必须要投入自己时间的开发者的阻力。
在经过长期开发的C++项目或者嵌入式系统的环境中,这个阻力会变得特别大。
Many technical approaches have been adopted to reduce suffering from dependencies. On a detailed level, parameters are passed in a string format, keeping the interface technically unchanged, even though the interpretation of the string’s contents changes. Some shift in meaning could be expressed in documentation only; technically the client’s software update could happen asynchronously. At a larger scale, component communication replaces direct interface calls by a more anonymous bus where you do not need to contact your service yourself. It just needs to be out there somewhere.
人们采用了很多技术手段来减轻依赖带来的痛苦。
比如在细节层面,用字符串传递参数,来保证即使这个字符串内容的解释发生了变化,但接口形式技术上保持不变。
一些意义的改变只能用文档材料来表达;技术上来说,客户端软件可以异步更新。
比如说更高的层面,使用匿名事件总线代替直接的接口调用来完成组件之间的交流通信,这样你都不用自己去联系你的服务,它只需要在某个地方是存在的就好了。
These techniques actually make it harder to spot the underlying implicit dependencies. Let’s rephrase the moral a bit: Obfuscated dependencies are still dependencies.
实际上,这些技术使潜在的隐形依赖更加难以辨认。让我们稍微改一下寓言的表述:模糊的依赖也是依赖。
Source-level or binary independence does not relieve you or your team from dependency management. Changing an interface parameter’s meaning is the same as changing the interface. You may have removed a technical step such as compilation, but you have not removed the need for redeployment. Plus, you’ve added opportunities for confusion that will boomerang during development, test, integration, and in the field — returning when you least expect it.
代码或二进制层面的解耦,并不会把你或你的团队从依赖管理中解脱出来。
改变接口参数的意义与改变接口是一样的。
也许你去掉了比如编译期的技术改动,但是你根本没有改变需要改动的事实。
并且,你还增加了在开发、测试、集成、回归过程中产生混淆的机会,而这,是你最不想要的。
Looking at sound advice from software experts, you hear Fred Brooks talking you into conceptual integrity, Kent Beck urging once and only once, and the Pragmatic Programmers advising you to keep it DRY (Don’t Repeat Yourself). While these concepts increase the clarity of your code and work against obfuscation, they also increase your technical dependencies — those that you want to keep low.
听听软件专家们的忠告,Fred Brooks告诫你概念完整性,Kent Beck 敦促你程序员要保持DRY(Don’t Repeat Yourself)。
当这些理念在提高你代码的清晰度、与混淆与困惑对抗时,他们也在增加你想保持在低水平的表面的技术依赖。
The moral is really about: Application dependencies are the dependencies that matter.
这个寓言其实是说:应用的依赖,就是与之相关的依赖的总和。(垃圾翻译,请看原文)
Regardless of all technical approaches, consider all parts of your software as dependent that you need to touch synchronously, in order to make the system run correctly. Architectural techniques to separate your concerns, all technical dependency management will not give you the whole picture. The implicit application dependencies are what you need to get right to make your software work.
不管所有技术上的手段,为了确保整个系统能正确地运行,必须把软件当做需要同时去考虑的独立部分。
作为分割你关注点的架构技巧,所有的依赖管理技术都不能给你一个完整的图景。
为了保证你系统最终能够工作,你需要清晰地了解应用的隐形依赖。