选型讨论里最常见的一种失效模式是:候选列了四五个,会议开了两小时,最后拍板的人说一句”我觉得 B 好一些”。这个结论本身不一定错,但它不可复用、不可追溯。半年后新人问”为什么是 B”,没人答得上来。
差别不在于选出哪个,而在于能不能把判断过程外化成一份别人能检查的东西。
约束先于候选
多数选型从”我们有哪些选择”开始,这个顺序是反的。候选空间在约束确定之前接近无限,先列候选等于把讨论锚定在几个恰好被想起来的名字上——通常是某人最近用过的,或者刚看过文章的。
先把约束写死,候选会自己收敛。约束至少覆盖四类:
| 约束维度 | 要回答的问题 | 典型硬约束示例 |
|---|---|---|
| 团队规模与构成 | 几个人维护?平均经验年限?有无专职运维 | 3 人以下不选需要独立运维集群的方案 |
| 交付时间 | 上线窗口多长?有无中期里程碑 | 6 周内上线不引入需要重写数据层的方案 |
| 运维能力 | 有无监控告警与值班?故障响应目标 | 无人值班时排除需手动干预才能恢复的组件 |
| 合规要求 | 数据能否出境?日志留存多久? | 涉个人信息时排除无法私有化部署的 SaaS |
约束分两种:硬约束是不满足就出局的过滤条件,软约束是进入评分的维度。把二者混在一起是评分表失效的头号原因——某方案在五个维度上总分最高,却在合规上直接不合格,最后照样被否,讨论白做。
加权评分表的生命线是打分依据
评分表的形式大同小异,真正决定它有没有用的是打分依据能不能被验证。
维度 权重 方案A(自建) 方案B(托管) 方案C(无新组件)
满足硬约束 过滤 不通过 通过 通过
学习成本 0.20 3 8 9
运维负担 0.25 2 9 7
吞吐上限 0.20 9 8 4
一致性保证 0.20 8 8 7
长期可持续性 0.15 7 6 8
加权总分 — 出局 7.95 7.20
权重应当来自约束,而不是来自”大家觉得哪个重要”。一个四五人的小团队把”生态活跃度”赋到 0.25 而”学习成本”只给 0.05,通常说明权重是照抄来的,没有过约束这一关。
打分依据要写成可复核的形式。不要写”性能:8 分”,要写”性能 8 分,依据:官方基准在 100 并发下 P99 约 40ms(附链接与测试条件),我们的目标是不劣于 100ms”。可验证的意思是:另一个人拿同一份依据能推出同样的分数。做不到这一点,评分表只是给个人偏好套了件外衣。
还有一步常被跳过:权重敏感性分析。把权重上下浮动 20% 再算一遍,若第一名换位,说明结论对权重设定过于敏感,此时应该回到约束重新讨论,而不是直接采纳当前第一名。
可逆性决定该花多少时间
决策按可逆程度分档,投入的时间应该跟档位匹配:
| 决策类型 | 例子 | 回退时要迁移的资产 | 建议投入 |
|---|---|---|---|
| 易逆 | 换日志库、换格式化工具 | 少量调用点 | 时间盒 1–2 天,到点就选 |
| 半逆 | 换序列化格式、换缓存中间件 | 已落盘的数据、客户端兼容 | POC + 灰度 |
| 难逆 | 换主数据库、换编程语言 | 全部代码、数据、人员技能 | 完整流程 + POC + 回滚预案 |
判断依据不是”改代码难不难”,而是”回退时要迁移多少既有资产”——数据、代码、团队技能、运维流程四样加起来。
两条对等的错误:把不可逆决策当可逆的快做,代价是几年还债;把可逆决策当不可逆的慢做,代价是机会成本。后者更常见,也更隐蔽,因为它看起来很”严谨”。
“最熟悉”不等于”最合适”,但常常是对的
维护成本通常大于技术先进性带来的收益。团队熟悉 A、不熟悉 B,即使 B 在评分表上高出几分,选 A 往往仍然正确。理由可以写得更硬一点:
引入 B 的额外成本 ≈ 学习期效率折损 × 人数 × 月数
+ 故障排查时长增加 × 预期故障次数
+ 招人与交接成本
这不意味着永远选熟悉的。区分方法是看这个包袱要背多久:如果这次选型决定的是未来三年都要维护的东西,学习成本可以被摊销,值得为更好的特性付费;如果是一次性脚本、短生命周期服务,熟悉的胜出。
一条经验上的止损线:一个团队同时引入超过两个”大家都不熟”的核心组件时,故障率和延期概率会明显上升。要引入新东西,一次引入一个,并且尽量不放在关键路径上。
POC 只验证风险点
POC 最典型的失败是做成了 demo:happy path 跑通,宣布”技术可行”。可 happy path 从来不是风险所在。
正确做法是先从约束和评分表里找出这个方案的”致命未知”,然后只验证它,其余一概跳过。
例:引入一个新消息队列,风险点大概是——
- 高吞吐下会不会丢消息(而不是”能不能发出去”)
- 消费端积压到百万级后恢复要多久(而不是”能不能消费”)
- 节点故障时转移是否自动、数据是否还在(而不是”能不能启动”)
POC 的验收标准必须可判定,写成”在条件 X 下指标 Y 达到 Z 则通过”:
验收条件:5000 QPS 持续写入 30 分钟,期间 kill 一个 broker 节点
通过标准:消息零丢失,且消费端 P99 < 200ms
不通过的处理:直接记为不通过,不允许"再调调参数看看"
POC 同样要设时间盒与退出条件。是否继续投入取决于剩余风险有多大,而不是已经投了多少。
把决策写成 ADR
ADR(Architecture Decision Record)的最小结构如下,写完大约半小时:
# ADR-014: 订单创建链路异步化
- 状态:已接受(2026-10-21)
- 参与人:后端 4 人 + 一次架构评审
## 背景
订单创建同步调用 5 个下游,P99 约 1.2s,其中 3 个下游允许异步。
约束:4 人团队无专职运维;上线窗口 8 周;消息不允许丢失。
## 候选
A. 自建消息队列 —— 违反"无专职运维"硬约束,出局
B. 托管队列服务 —— 合规通过,运维负担低
C. 数据库表轮询(outbox)—— 无新组件,吞吐上限受限
## 决策
一期选 C。当前量级远低于 C 的上限,且零新增运维负担。
触发重评的条件:日订单量超过 X,或积压行数持续高于 Y。
迁移路径:C 的生产端表结构可直接对接 B,迁移仅限消费端改造。
## 后果
正面:链路 P99 下降,无新组件引入。
负面:轮询对主库有额外压力,需新增积压行数监控。
跟踪项:每周检查一次积压峰值。
ADR 的价值出现在半年后:当有人问”当初为什么不直接上托管队列”,答案连同当时的约束一起被保留下来,讨论就不必从零重来。末尾那句”触发重评的条件”尤其重要,它给决策设了有效期,避免它变成没人再敢质疑的默认。
一份可执行的选型清单
把上面的步骤压成一张检查表,评审时逐条打勾:
[ ] 硬约束已列出,且每个候选都做了通过/出局判定
[ ] 权重从约束推导,不是照抄模板
[ ] 每个分数都附了可验证依据(链接/实测/文档章节)
[ ] 做过权重敏感性分析,结论稳定
[ ] 已判定该决策的可逆档位,投入与之匹配
[ ] POC 验证的是风险点,有可判定的通过标准
[ ] ADR 已写,含背景、候选、决策、后果、重评条件
[ ] 明确了"这次不做什么"
选型的产出不是那个技术名字,是这一叠能被质疑的记录。名字会过时,记录里的推理方法不会。
评论(2)
看标题以为又是水文,读完默默点了关注。
看完第一反应是:我们架构就是这么烂的。
请 登录 后参与评论。