中国人讲究 “中庸”,“过犹不及”,凡事都要把握一个 “度”。而软件工程正是一个没有银弹,处处要把握度的地方。
比如微服务,使用得当能够解耦应用,提升研发效率,使用不得当则是将一个“大泥球”,变成一个“分布式大泥球”;将单点故障,变成“分布式故障”。
在比如设计模式,有人认为设计模式能够改善系统质量,而有人认为只是编码 “炫技”。这本质上都是 “适度” 的问题。
“度” 在哪里:不在技术,而在业务
一段代码或者微服务的拆分是否得当?很多人会有不同的观点。
比如按照设计模式 DRY 原则(Don't Repeat Yourself),相同的代码就应该被抽成一个方法,这样修改时方便统一修改。
但是在复杂工程中导致的问题就是,DRY 的函数会被大量的地方引用,导致其内部逻辑需要考虑各种情况,逻辑及其复杂,修改风险也极高。
这么看来,DRY 也没有那么好,复制代码反而可以降低后续的修改风险,日后可以根据业务需要再进行整合,“拖延决策” 也优秀设计的特点之一。“复制代码” 貌似也没有很多人所鄙夷的那样不堪
DRY原则优点 | 缺点 | |
---|---|---|
重复代码 | 修改风险小;日后可以根据业务需要再做整合 | 逻辑分散,难以统一修改和收口 |
DRY | 方便统一修改 | 修改风险高,逻辑复杂,需要考虑所有入口 |
从上表可以看出,重复代码和 DRY 很难说孰优孰劣,有时候费了半天劲抽取代码,反而系统复杂性更高了。符合设计原则的代码不一定是好代码,不符合设计原则的代码不一定是坏代码。
通过这个例子就是想说明,通过纯粹技术的角度是看不出来软件设计决策是否正确的,必须从更高的业务视角出发才行。
代码本质上是业务的反映,它只有在最符合业务的地方,才能降低系统复杂度。
方法/函数的存在不是单纯为复用,方便统一修改等技术原因,而是因为它本来就“应该”在那里。
不同模块有不同的“度”
橘生于南则为橘 橘生于北则为枳
“度” 也是不能一概而论的,不同模块有它不同的 “度”,比如对于阿里巴巴的双十一交易系统,钉钉 IM 这样的核心系统,做多少设计都不过“度”,而对于运营管理后台,可能稍微设计一下可能就 “过度” 了。有时候觉得自己手里的系统很“烂”可能并不是因为公司技术不行,而是自己负责的业务不够核心。
DDD 中的子域概念就是用来描述这个的,在 DDD 中存在三种子域:
- 核心子域
- 能够给公司带来核心竞争力的领域模块,拥有很高的复杂度和差异化价值
- 比如滴滴的调度算法,阿里的交易系统,钉钉的 IM 系统等等
- 该模块的 “度” 几乎没有天花板,投入精兵强将,尽可能地拉开和竞争对手的聚合,再怎么设计也不过“度”
- 支持子域
- 用来支撑核心子域,但是不能带来竞争力
- 比如运营管理系统,后台排查系统等等
- “度”很低,外包,或者尽可能使用搭建系统搭建
- 通用子域
- 通用的业务或者技术问题领域,一般有现成的解决方案,可以直接采购
- 比如财务系统,可以直接采购用友,金蝶;分库分表,消息队列可以直接使用开源软件,或者购买云上解决方案
- 尽可能减少投入,购买尽可能完善的解决方案,投入的每一点都是 “过度”;这些年上云的趋势就是在尽可能地削减这一部分投入
以 DDD 中经典的货运管理系统为例(简化):
子域划分大厂前几年都非常喜欢把业务“铺开”,所有东西都自己做一遍,导致对 “支持子域” 和 “通用子域” 的 “过度” 投入。最近经济下行,没有这么多资金支持这种 “过度” 投入了,只好大量裁员,这正是对自己 “核心子域” 没有清晰认知的结果。
网友评论