设计红旗
综合之前,把每个候选筛一遍。出现红旗,就说明这个形态该改或该拒。
浅模块对外暴露的接口很大,藏住的复杂度却很少。判断深度,要看公开接口背后藏了多少能力和策略,再跟接口本身的大小比。接口简单、背后行为扎实的,优先。
深模块和深调用链不是一回事。深调用链把理解拆散到好几层。深模块把能力集中在一个接口后面。
留意这些迹象:
- 调用方要配合调好几个方法,才能完成一次操作。
- 公开选项把内部阶段或实现上的选择暴露了出来。
- 学会了接口,调用方还是得去了解实现。
信息泄漏会让多个模块依赖同一个内部决定。同一种表示、策略或协议细节出现在不止一处,改它就得几处一起改。
把传输层或 wire 格式的类型公开再导出,就是泄漏。在接口后面把外部数据解析成领域类型。存储 schema、框架对象和协议细节都留在内部。
按时间顺序拆分
Section titled “按时间顺序拆分”按时间顺序拆分,是按执行先后来组织模块,而不是按模块掌握的知识。把加载、校验、转换、保存拆成几个独立阶段,往往会让同一种表示和它的不变量在好几道边界上重复出现。
围绕领域知识和归属来组织代码。不同时间运行的方法,只要守护的是同一组决定,照样可以放在一个模块里。
透传方法把同样的参数原样转给另一个形状相同的方法。多了一层,却没藏住任何复杂度。
删掉它,或者把职责挪到能完成这个操作的模块。只有转发这一层加了策略、做了适配,或者是一个独立的抽象时,才保留它。
状态有多个写入方
Section titled “状态有多个写入方”不止一个模块写入同一份状态,或各自留一份副本。改其中一个写入方的代理看不到其他写入方,规则就会分叉。
每一份状态只留一个所有者。其他模块读取它,或请所有者去改。
同一件事有两种做法
Section titled “同一件事有两种做法”设计里同一件事有不止一种做法。代理先碰到哪一种就抄哪一种,于是每种做法都不断多出调用方。
只留一种。同一次改动里把调用方迁走,并删掉其余做法。
内部可以被外部导入
Section titled “内部可以被外部导入”调用方可以导入模块的内部。代理会走能编译通过的最短路径,于是直接导入内部,内部就变成了接口的一部分。
让模块外部到不了内部,这样从外部导入会让构建失败。
靠人手保持同步的清单
Section titled “靠人手保持同步的清单”两个或更多地方列出同样的条目,加一条就要改每一份清单。代理只看见其中一份,就只更新那一份。
只留一份清单,其余从它推导。推导不了的,清单不一致时让构建失败。
