3277 字
约 10 分钟
18
S18-B01 · 什么是架构:约束条件下的取舍

"你们系统用什么架构?"——这个问题通常期待一个名词:微服务、Spring Cloud、DDD、中台。但名词回答不了任何实际问题。换个问法就露馅了:这个决定如果三个月后要改,要付多少代价? 付不起的那个,才是架构。

所以架构有一个朴素定义:架构是那些事后改起来很贵的早期决定,加上做这些决定时不得不接受的限制。 它不是框架选型清单,也不是那张框框图——图是架构的副产品,不是架构本身。

这篇给三样立刻能用的东西:怎么判断一个决定算不算架构决定、约束怎么写得让方案空间显形、取舍怎么写成一句别人能反驳的话。


1. 朴素定义:改起来很贵的早期决定

同一个团队同一周做出的决定,改起来的代价可以差三个数量级。判断标准只有一条:看改它的代价,不看它听起来高不高级。

决定 改一次的典型代价 算架构决定吗
构建工具用 Maven 还是 Gradle 半天,改脚本与 CI 不算
单体还是拆成多个服务 数月,涉及部署、事务、联调、运维 算
数据按什么维度分库分表 数月,涉及迁移与双写 算
日志框架用 logback 还是 log4j2 一两小时 不算
对外接口用 REST 还是 gRPC 接口一旦发布就难收回 算
主键用自增还是 UUID 一周到数月,取决于数据量级 视数据量算

架构工作的意义,是把注意力压在上面那几行"贵"的决定上,而不是花三天争论下面那几行"便宜"的决定。大部分团队所谓的架构争论,其实是在为便宜的决定付昂贵的会议成本。


2. 架构决策的三个特征

同时具备下面三条里的两条以上,就该按架构决策对待、留下书面记录。

特征 怎么判断 反例(不满足的)
难改 改它需要停机、迁移数据、改多个团队的系统 换一个工具类
影响面广 波及过半模块或超过一个团队 只影响一个页面的展示
约束他人 它规定别人"只能怎么做" 一个可选的工具函数

第三条最容易被忽略。约束他人意味着这个决定会成为别人的前提:选了同步调用,别人就不能假设有消息重投;选了单库单表,别人就不能假设能按用户分片。测法是问一句:"这个决定定下来之后,谁的方案被砍掉了?"一个都没砍掉,它大概不是架构决定。

架构决策三问(贴进评审模板,逐条打勾)
[ ] 一年内改它,需要停机或数据迁移吗?
[ ] 它会让两个以上团队的工作方式发生变化吗?
[ ] 它排除了某些人原本想做的方案吗?
三条全否 → 按普通技术决定处理,不要上升为架构讨论。

3. 约束的四类:约束决定方案空间

新手最容易犯的错是先想方案再找约束。顺序应相反:约束先定,方案空间才收敛。 没有约束,任何方案都能被论证成"更好",讨论就永远不结束。

约束类型 具体表现 它砍掉了什么方案
业务规模 日订单 3 千 vs 3 千万;峰均比 规模小时分库分表是纯负债
团队能力 5 人、无人有 K8s 运维经验 砍掉"上服务网格"
存量系统 老库不能改表、老接口不能下线 砍掉"重新设计数据模型"
时间与成本 6 周上线;预算 3 台机器 砍掉需要半年的重构路线

写成清单比写成散文有用:

## 约束清单(开工前必填)
- 业务规模:日活 / 峰值 QPS / 数据量年增长,来源与时间点
- 团队:人数、值班能力、已有技术栈熟练度
- 存量:不可改的表 / 不可改的接口 / 必须兼容的客户端版本
- 时间:硬上线日期,以及这个日期由谁决定
- 成本:机器与人力上限,超出后谁批
- 不可谈判项:上面哪一条绝不松口

最后一行是关键。约束里一定有一条是硬的(合规、合同、老客户),把它单独标出来,讨论就有了裁判。


4. 质量属性的六个常见项,以及它们必然互相冲突

质量属性不是形容词,是可度量的目标。写不出度量方式的形容词,等于没写。

质量属性 入门者该用的度量口径 常见误判
性能 P99 延迟、吞吐(每秒请求数) 只看平均值,忽略长尾
可用性 月度不可用分钟数 把"没重启过"当成高可用
可维护性 改一个需求平均触碰几个模块 用代码行数衡量
可扩展性 加一台机器带来多少线性提升 把"能加机器"当成已扩展
安全 鉴权覆盖率、密钥轮换周期 只在登录处做校验
成本 每万次请求的机器与带宽开销 只算机器不算人力

关键认知:这六项不能同时最优,优化任何一项都在向另一项借钱。

你想要的 付出的代价 具体表现
更低延迟 一致性 本地缓存快,但可能读到旧值
更高可用 一致性 跨机房强一致在分区时拒绝写
更强可维护性 性能 多一层抽象多一次跳转与分配
更强可扩展性 成本 预留容量、常驻连接、空闲节点
更高安全 延迟与成本 每次调用验签、加密、审计落盘
更快交付 可维护性 先堆逻辑上线,半年后还债

拿这张表跟业务方对齐一次,比讲十页 PPT 有效。


5. 取舍的写法:用 A 换 B,而不是"这个更好"

"Redis 更好"不是取舍,是偏好。取舍必须能写成一句带对手方和代价的话。

坏写法:
  选用 Redis 做缓存,性能更好,社区活跃。

好写法:
  选用集中式 Redis 而不是本地 Caffeine,
  换取多实例之间的数据一致与容量共享;
  代价是每次读多一跳网络(典型量级:亚毫秒到数毫秒),
  并新增一个必须运维的高可用组件。
  当数据以只读配置为主、单机命中率足够高时,推翻这个决定。
维度 坏写法 好写法
主语 技术名 被放弃的选项
动词 更好 / 主流 换取
宾语 无 具体收益 + 具体代价
可反驳性 无法验证 别人能说"这代价我付不起"
推翻条件 缺失 写明什么情况下改

最后一行是入门者最该抄的习惯:每个决定都写一句"什么情况下要推翻它"。写不出推翻条件,通常是因为代价没想清。


6. 架构的粒度:不同粒度决定不同的事

"架构"在不同场合指三种大小的东西,混着谈就会吵不出结果。

粒度 决定什么 不该在这里决定
系统级 系统边界、外部集成方式、数据归属 某个接口的字段命名
服务级 服务拆分、通信方式、事务边界 内部类的分层方式
模块级 包结构、依赖方向、模块间接口 是否上云、是否拆库

对应的最小记录模板,五个字段就够:

### 决定:<一句话,动宾结构>
- 问题:现在遇到的具体麻烦是什么(不带方案)
- 约束:来自四类约束里的哪几条
- 选项:A / B / C,每个一句话
- 决定:选 B
- 代价:放弃了什么,谁承担
- 推翻条件:出现什么信号时重开这个话题
- 粒度:系统级 / 服务级 / 模块级

一个决定一页,按时间归档。三个月后有人问"当初为什么这么定",翻这一页比翻会议记录快。


7. 常见误解

误解 为什么错 改成什么
微服务就是架构目标 它是交付与边界的手段 先写目标,再问微服务是否服务于它
架构是一次性设计 约束会变,设计必须跟着重开 按推翻条件复核,不按季度重画图
技术先进 = 质量高 先进性不度量,不匹配团队能力是负债 用第 4 节的度量口径说话
图画完就完成了 图不含代价与推翻条件 图 + 决策记录,两者都要
架构是一个人的事 被约束方不参与,落地即变形 决定由承担代价的一方共同签字

入门者的三个动作,今天就能做:

1. 先写清约束:四类约束写成清单,标出哪条不可谈判。
2. 记录决定与理由:每个"贵"的决定留一页,含代价与推翻条件。
3. 给每个决定写"什么情况下要推翻":写不出就说明代价没想清,
   回到第 5 节,把"用 A 换 B"补完。

8. 排错:五种"以为在讨论架构"的情况

现象 真实原因 处理
讨论三轮无结论 约束没写清,方案空间没收敛 先补约束清单
所有人都在说"更好" 缺度量口径,只能比形容词 每项给一个数或"典型量级"
决定做了但落地走形 只约束了自己,没通知被约束方 写进接口文档与评审清单
半年后无法解释设计 只留了图,没留代价 从当前最贵的三个决定开始补记录
新技术引入后维护成本飙升 团队能力约束被忽略 回看第三类约束,评估是否换回

9. 边界:什么情况不该用架构决策的方式处理

场景 更合适的做法 理由
单个工具库选择 谁用谁定,评审兜底 可逆,成本低于讨论成本
代码风格与命名 工具链自动格式化 争论收益为零
一次性脚本 直接写,不记录 生命周期短于记录成本
明确的 bug 修复 直接改 + 回归测试 是缺陷,不是取舍
未到瓶颈的性能优化 先测再改 无度量就无取舍

一句话收束:架构只处理那些"改起来贵、且必须现在定"的事。 其余交给人、工具和时间。


10. 自测

  1. 为什么"换日志框架"不算架构决定,而"是否拆服务"算?
  2. 架构决策的第三个特征最容易被忽略,用什么问句能测出来?
  3. 约束清单里为什么必须单独标出"不可谈判项"?
  4. 把"我们用 Kafka,因为吞吐高"改写成符合第 5 节要求的取舍句。
  5. 系统级、服务级、模块级三种粒度,各自"不该决定"什么?
  6. 一个决定写不出"推翻条件",通常说明哪一步没做完?
S18-B01 · 什么是架构:约束条件下的取舍
https://www.clxhxhhr.top/posts/5992/
作者
clxstart
发布于
2024-12-31
许可协议
CC BY-NC-SA 4.0
评论
0 条
还没有评论,先写一条吧。