本文读完《架构整洁之道-组件耦合》的总结和个人的思考,并写一个很无聊的小工具:SDP-Analyzer,可以对组件包依赖的稳定性进行评分。
软件工程有个评判术语叫可定量(可量化),意思是说可以使用某种数值标准去测量。那么如何衡量一个组件的稳定性?在书中,作者认为组件的耦合关系会直接影响其稳定性,并提出需要关注三条原则来指导组件依赖关系的设计:
- 无循环依赖环原则
- 稳定依赖原则
- 稳定抽象原则
无循环依赖原则
组件依赖图中不应该出现环,否则会出现一种痛苦的病症:一觉醒来综合征,意思是今天可以跑的代码,由于依赖了其他人的代码,但依赖代码在你下班后发生了变更,第二天过来上班发现你的代码不能工作了。
从管理手段上(被各大互联网公司经常使用)有个策略叫:每周构建,只允许指定的时间窗口(比如周五),对所有人的代码进行集成测试、构建和部署,这种策略有个问题是项目规模越大,集成的难度会指数上升,只能加班或提前集成的窗口时间,最终也会导致产品的迭代周期拉长。
作者提倡另外一种做法:每个开发者自主发布带有版本信息的组件,但必须消除循环依赖,如果组件之间的关系存在依赖关系,又会出现「一觉醒来综合征」,以下的组件依赖图就存在循环依赖:
添加图片注释,不超过 140 字(可选)
上面的组件依赖图就不是一个有向无环图,其中存在环:
B -> C -> D -> B
这会引入一个问题,假如 B - C - D 修改任何一个包,都必须需要保持相同的版本号且整体发布,这影响了组件发布的独立发布能力。
作者提出两种方案:
- 应用依赖反转原则(DIP),让 C 去依赖 B,也就是原本需要的实现移动了 B 里面。
- 引入新组件让 B 和 C 共同去依赖一个新的组件 F。
作者认为组件依赖不可能是完美的自上而下的设计,一个组件从设计到应用,是无法被预测的,因此最终会形成组件依赖图,并且存在环的风险,当存在循环依赖时,借用外力(新增组件)去消除,这本身符合系统架构是处于不断扩张和演进的事实。
稳定性原则
基本思路是,组件依赖关系必须要指向更稳定的方向,也就是容易变更的组件不应该被稳定的组件所依赖。那么如何衡量稳定性呢?
作者认为一个组件存在两种依赖方向:
- 入向依赖(I),表示外部组件依赖该组件。
- 出向依赖(O),表示该组件依赖外部组件。
因此产生了两个数据:出向依赖的数量和入向依赖的数量,而衡量组件稳定性的指标就可以用以下公式表示(S 表示 Stable,原文是 I):
S = O / (I+O)
因此指标的区间是[0,1],S=0 表示组件是最稳定的,S=1 表示组件是最不稳定的,因此该原则要求在组件依赖图中,各组件的 S 指标应按依赖关系方向递减:
添加图片注释,不超过 140 字(可选)
如果稳定组件依赖一个易于变更的组件时,比如上图中的 D -> B,此时它的 S=0.5,这违反了稳定性原则,此时需要创建一个新的组件 E,去实现 B 的功能(D 对 B 的部分依赖),然后让 D 依赖于 E,而 F 稳定性就是最稳定的 S=1。
稳定抽象原则
有个事实是,稳定的组件一般处于高阶层次上,如果实现太具体的话,就越难被修改,这个原则就要求稳定的组件应该是抽象,保证其稳定性不会影响扩展性。
而衡量组件的抽象化指标是,A 表示抽象程度,NA 表示组件中抽象类和接口的数量,NC 表示组件中类的数量:
A= NA / NC
取值区间为[0,1],0 表示组件中没有任何抽象类,1 表示组件只有抽象类,就前端组件库来说,我理解,一个组件中,抽象出来的子组件越多,该组件的抽象程度就越高。
如果结合稳定性原则的 S 指标,可以用一张坐标图来表示,一个设计良好的组件应该如何处于什么位置。
添加图片注释,不超过 140 字(可选)
- 痛苦区 是不够抽象,也不够稳定的,这类组件修改起来很麻烦,例如数据库的表结构,前端的业务组件。
- 无用区 是表示无限抽象,没有其他组件依赖它,这类组件正在逐步被放弃的状态。
- 主序列线 是从坐标(1,0)和(0,1), 一个设计良好的组件应该是贴近这条线的,既满足抽象程度,又能确保稳定性。
总结
前端生态逐渐稳定且成熟的今天,搭建组件库基本是前端工程师的必备技能,当被问起「你们的组件稳定性如何」时,大部分都是八股文式的回答,比如单元测试覆盖率达 x%,异常监控上报,CI 发布之类的手段,当然这些都是必须的,但如果需要用数学符号化的指标去量化,就可以应用本文的理论指导了。
再次推荐这本书,有趣还很干(理论层面上)。
《架构整洁之道 (美)RobertC.Martin(罗伯特 C.马丁),孙宇聪 电子工业出版社 9787》【摘要 书评 试读】- 京东图书
哦对了,那个无聊小玩意在这:sdp-analyzer
感谢您的阅读,觉得有用的话那就点个赞吧。
[本文谢绝转载,谢谢]