PostsMapsLinks
架构设计

软件架构

软件架构的定义、复杂度三轴、质量属性、结构决策与技术债务

软件架构是难以改变的结构决策集合

功能跑通只回答「能不能用」,回答不了三件事:负载上来扛不扛得住、改动会不会牵连、失败后能不能恢复。 开发视角看到的是功能清单,架构视角看到的是承重墙——单点在哪里、依赖链会不会被下游拖死、加一个字段要动几个文件。 框图只是某个时刻的快照,真正的架构是那串已落地的结构决策:单库还是拆库、同步调用还是消息队列、失败时重试还是降级。 决策一旦通过代码和数据固化,回退成本极高,Ralph Johnson 与 Martin Fowler 因此把架构定义为「一组重要的决策,其重要性在于难以改变」。

架构优化的对象是质量属性:性能(快)、可用性(稳)、可扩展性(能扩)、可维护性(能改)。 这些能力不会出现在产品验收清单里,却决定系统寿命。 经典质量属性清单(如 Bass《Software Architecture in Practice》与 ISO/IEC 25010 模型)还包括安全性、易用性、可测试性等, 可扩展性在其中通常并入性能而非独立一等属性。

见:Software architecture - Wikipedia

复杂度沿人、模块、时间三条轴增长

复杂度不是突然出现的,它沿三条轴同时上涨:团队规模扩张抬高沟通成本,模块数量增加拉长排查路径, 时间抹掉设计动机(当初为什么这么写没人记得,写代码的人可能已离职)。 单独一条轴还能应付,三轴同涨才是压垮系统的原因。

沟通成本按平方增长:n 个人之间有 n(n-1)/2 条沟通线,3 人 3 条、30 人 435 条——人头涨 10 倍,沟通线涨 145 倍。 这个公式出自 Brooks 1975 年的《人月神话》,它解释了为什么「人多了」不能靠多开会解决,只能靠结构解决: 拆小团队、拆边界清晰的模块,都是在给平方曲线踩刹车。

见:The Mythical Man-Month - Wikipedia

结构决策前先问什么会变、什么会炸

选结构被多数人做反了:先看中某个框架,再给它找理由。正确的顺序是先回答两个问题—— 什么会变:字段、规则、流量形态里明年一定会动的那部分,在变的那侧留可改的口子; 什么会炸:并发洪峰、下游故障、单点堵塞里会打穿系统的场景,先把承重墙立住。 两问答完再决定拆几个服务、怎么连接、失败谁兜底。

每个结构决策都是取舍,快交付和以后好改很少同时成立,区别只是利息什么时候付。 今天把订单和库存写进同一张宽表省一周,明年加字段时十七处读取全要跟着改。 判断口子留没留上的标准是演进成本:会变的那侧今天不焊死。 决策落定后还要能讲清「为什么选它、放弃了什么」——讲不清的决策半年后没人敢动, 这个义务的现代载体是架构决策记录(Architecture Decision Record, ADR),用短文档把决策背景与备选项沉淀下来。

见:Architecture decision record - GitHub

技术债的原意是主动借债换学习

Ward Cunningham 1992 年在 OOPSLA 的经验报告里写道: 「Shipping first time code is like going into debt. A little debt speeds development...」——先上线第一版代码如同举债,少量债务能加速开发。 他发明这个比喻不是为了批判脏代码,而是向不懂技术的管理者解释:为什么尽快交付原型、从真实用户反馈里学习是理性的。 借债换回的是学习机会,利息是日后重构。

Cunningham 后来(2009 年的 Debt Metaphor 演讲)澄清,这个比喻只适用于「因学习而写的代码被新需求追上」的场景。 据此判断一笔债该不该欠:复制这段逻辑真的换回了学习或反馈吗?团队知道自己欠了、利息记在哪吗? 两者都成立是杠杆;都不成立(比如把同一段校验逻辑无意识复制进十七个文件)不是债,是失职。 识别标准是「每次改动是不是越来越慢」。

见:TechnicalDebt - WikiWikiWeb

模块划分的判据是藏住难预判的设计决策

David Parnas 1972 年的论文 "On the Criteria to Be Used in Decomposing Systems into Modules" 否定了当时的主流做法——按处理步骤划分模块(每个环节一个模块)。 他提出的判据是信息隐藏(information hiding):每个模块藏一个最难预判的设计决策(他称之为该模块的 secret),接口只暴露稳定抽象。 他用 KWIC 索引系统做了对照:按流程分解的系统换存储方式要动多个模块,按信息隐藏分解只动字符存储一个模块。

落到评审里,问的不是「职责清不清晰」,而是「这个模块藏的是什么可变决策、真的藏住了吗」。 接口一旦泄漏实现细节(比如暴露数据来自宽表),口子就等于没留,外部调用方会依赖它,改动时全线被牵连。

见:Information hiding - Wikipedia

向进度落后的项目加人只会更落后

沟通线平方律的直接推论就是 Brooks 定律(Brooks's Law):向进度落后的软件项目加人,只会让它更落后。 机制有两层:新人上手前没有产出,现有工程师要停下来培训,Brooks 估计这部分消耗接近把工作重做一遍; 同时每加一人新增 n 条沟通线,n 增大让平方项更大。

延期时更有效的动作是砍范围,或者拆小团队——拆团队是唯一直接压低 n 的动作。

见:The Mythical Man-Month - Wikipedia

Copyright © 2024 Lionad - CC-BY-NC-CD-4.0