构建完整的架构边界是一件很耗费成本的事情,在这个过程中,需要为系统设计双向的多态接口
,用于输入和输出的数据结构,以及管理相关依赖,以便于划分组件。这里会有大量的前期工作,和后期维护工作。
所在在很多时候,优秀的架构师,会做一些取舍,但是为未来的可能的需要,通常还是会预留一个边界。
这种预防性设计,在敏捷社区里是被诟病的。因为它违背了YAGNI(You Aren't Going to Need It)
原则。即不要预测未来的需要。
但是架构师的工作本身就是要做这样的预防性设计,所以,我们就要引入不完全边界的概念。
1. 省掉最后一步
构建不完全边界的一种方式,就是在将系统划分为一个个组件后,再把它们构建成一个组件。
换句话说就是,在将系统中所有接口,数据格式等每一件事完成后,仍然将它们统一编译和部署为一个组件。
虽然这种方式,代码量和设计的工作量并没有减少,但它省去了多组件管理这部分的工作(部署和编译)。这就等于省去了版本号管理和发布管理方面的工作。
2. 单向边界
在设计一套完整的架构边界时,通常我们需要利用接口来维护边界的隔离性。而且维护这种隔离性,通常还不是一次性的工作,需要我们长期投入资源维护下去。
下图展示了一个,将来可以被替换成完整架构边界的简单结构。
Client
使用ServiceBoundary
接口,ServiceImpl
实现了这个接口。很明显,上述设计为未来构建完整的架构边界打下了基础。图中的虚线,代表了未来可能还是会出现依赖(Client
直接调用ServiceImpl
),这就要靠程序员和架构师自觉了。因为这并不是双向反向接口。(长什么样?)
3. 门户模式
这是一个更简单的模式。这种模式下,依赖反转的工作都可以省去。这里的边界将只能由Facade
类来定义,Facade
会将Client
需要的Service
返回给Client
。但这也就意味着Client
被Facade
传递性的依赖了所有Service
。这也就意味着Service
的修改,可能会导致Client
重新编译或修改。
本章小结
这里介绍了三种不完全边界的实现方式。还有很多,这三种只是一个示范。每种实现方式都有相应的成本和收益,还有与之对应的场景。架构师的职责之一就是预判哪里可能会需要设置架构边界,并决定使用完全形式,还是不完全形式来实现它们。