3.2 软件设计:画好车厢与转向架 货单冻结后,设计站决定这趟车造出来是客车还是货车、能不能加挂车厢。设计是把需求基线翻译成可装配图纸的过程:先定整车的编组结构,再画每节车厢的详图。本节讲两级设计的分工、分层架构怎么约束依赖,以及三条最常用的设计原则——配一段能看懂的正反例代码。 图纸的深度:画到哪一层 设计分两级,分工必须清楚: 概要设计(架构设计):定系统怎么分块、块间怎么通信、依赖朝哪边指。产物是分层图、模块清单、接口契约、技术选型说明。它回答"这列车有几节车厢、车钩是什么制式"; 详细设计:定每个模块内部怎么实现——关键类的职责、数据结构、算法流程、异常处理。它回答"转向架里每个零件怎么装"。
货单冻结后,设计站决定这趟车造出来是客车还是货车、能不能加挂车厢。设计是把需求基线翻译成可装配图纸的过程:先定整车的编组结构,再画每节车厢的详图。本节讲两级设计的分工、分层架构怎么约束依赖,以及三条最常用的设计原则——配一段能看懂的正反例代码。
设计分两级,分工必须清楚:
两级深度的分界线有一个实用判据:概要设计评审时,评审员不需要看代码就能判断结构是否扛得住需求;详细设计评审时,开发者拿到图纸不必再做结构决策,照图施工即可。图画得太粗,编码时人人都在做架构决策,结构就漂了;画得太细,文档比代码还长,维护两份真相必然失同步。

设计原则几十条,真正每天用得上的是这三条:
高内聚、低耦合:一个模块只干一类事(内聚),模块之间通过窄接口往来(低耦合)。检验问句:能不能用一句话说清这个模块是干什么的?说清了是内聚的;改一处要牵动五个文件,是耦合泄漏。
依赖抽象而非实现:上层依赖接口而不是具体实现,换实现不动上层。反例与正例各一段:
反例:计费编排直接 new 具体规则引擎 编排模块内写死: engine = new StepRuleEngine() 要换成决策表引擎,编排模块的代码必须改动、重测—— 上层被下层的一个具体类绑架。 正例:编排只认识接口,引擎由外部注入 engine = factory.getRuleEngine() 编排模块只依赖"规则引擎"这个抽象契约, 换实现只是装配线换个零件,图纸一行不改。 配套收益:测试时可以注入一个假引擎, 让编排逻辑脱离真实引擎独立试跑。
信息隐藏:模块对外只暴露必须暴露的,内部结构是私产。公开面越窄,日后改内部越自由——这条是所有可维护性的根。
设计评审不是念 PPT,而是拿真实场景过图。有效的做法是备三个代表性场景——最高峰、最复杂、最异常——沿图纸走查:高峰场景看结构有没有瓶颈点,复杂场景看规则编排是否清晰,异常场景看失败路径有没有交代(超时怎么办、重试谁负责、半成品数据怎么清)。云梯的结算引擎评审就靠一个异常场景救命:评审员问"计费到一半消息队列断了,运费算一半怎么办",图纸答不上来——补上了事务补偿设计,这一处若留到线上,就是错账事故。
⚠️ 设计评审最常见的空转是把评审开成选型辩论会——为用哪种缓存吵半天。选型吵不出结论时先记两条待验证项,让证据进场;评审的主体责任是看结构是否承载得住需求,不是替团队做所有技术决定。
模块边界画不准时,有条土办法屡试不爽:按"变化的原因"切,而不是按"技术层次"切。问每个候选模块:它因为什么会改?如果答案混杂着"业务规则变了要改"与"存储方案换了要改",说明两种变化原因被捆在一个模块里,未来任何一种变化都会惊动整个模块。云梯初版把计费规则与数据库访问写在一起,税则调整这样纯业务的变化,也要让懂存储的人来改——后来按变化原因重新划线,规则归规则、存取归存取,两类变更再没互相牵连过。这条线画下去,往往顺带把团队的责任分工也理顺了:业务规则模块的变更评审请业务方到场,存取模块的变更评审只看技术。
图纸不必厚,但骨架要全。云梯的模块设计文档固定五段:定位(一句话说清它为什么存在,删掉它什么功能消失)、边界(管什么、不管什么,"不管"半句更重要)、接口(对外契约与依赖方向)、关键决策(选型理由与被否掉的备选,防止半年后重炒冷饭)、风险与待验证项(评审时挂起的疑问及验证计划)。全文控制在一两页,评审会前发、会上只议分歧——第 3.1 节需求评审的规矩原样适用。决策记录那一段尤其值钱:它让"当时为什么不用另一种方案"从考古问题变成检索问题。
设计站有几类高频翻车,各给一个自救动作。翻车一:图纸与代码两张皮——文档写的是理想架构,代码里早就绕开了。自救:设计文档里加一列"实际状态",评审时核对,漂移超两成要么改代码要么改文档,不许共存。翻车二:接口先定死,调用方后哭——提供方按自己的方便定接口,接入方拿到才发现缺字段、粒度太粗。自救:接口评审必须请至少一位真实消费方到场,用他们的调用场景过一遍。翻车三:性能问题纸面拍板——"这个量级没问题"是设计会上说得最多的错误结论。自救:拿不准的性能结论降级为待验证项,配一个小型原型实验,让数据进场代替争论。
问:敏捷还要不要写设计文档? 要,写的是"活不过两个迭代就会过期的那种薄文档"。敏捷反对的是把文档当交付物精心装裱、与代码双轨漂移;不反对把决策与边界落在纸面上——恰恰相反,人员流动频繁的团队,几页准确的图纸比人脑记忆可靠得多。判据老样子:这条信息离开人脑了吗,新人接手能靠它上手吗。
问:设计原则执行到什么程度算过度? 出现这些信号就该收手:为只有一种实现可能的接口建抽象层、为不会变化的点预留扩展点、为一个用不到的"通用性"多出两个模块。原则是应对变化的工具,对没有变化的点使用工具,就是纯开销。判断"会不会变"别靠想象,看历史与业务路线图。
图纸定了,下一节进装配车间——代码怎么写、怎么查、怎么自证清白。