核心问题
我们的判断能不能被证据推翻?
认识论里有一个重要思想:可证伪性。
一个说法如果无论发生什么都能解释,那它就很难成为可靠知识。
映射到软件工程:
一个工程判断如果不能被验证或推翻,它就只是意见。
例如:
这个架构更灵活。
这个页面体验更好。
这个优化会更快。
这个抽象以后会有用。
这个功能能提高转化。
这些话不一定错,但它们还不是可验证判断。
我们要把它们变成假设:
如果我们把购买流程从 4 步减少到 2 步,支付完成率会提升至少 5%。
如果我们缓存课程详情页,P95 响应时间会从 800ms 降到 300ms 以下。
如果我们引入 CourseAccessGrant,新增访问来源时只需要修改 course-access 模块。
这才有可能被证据支持或推翻。
工程里的三类假设
1. 产品假设
产品假设关心用户行为。
例如:
给用户展示学习进度,会提高课程完成率。
减少注册字段,会提高注册转化率。
企业管理员需要批量分配课程。
这些不能靠开会决定,要靠数据、访谈、实验或使用行为验证。
2. 技术假设
技术假设关心系统性质。
例如:
Postgres outbox 足够支撑当前异步任务量。
当前查询瓶颈来自 N+1,而不是数据库索引。
Redis 缓存可以把课程详情页 P95 降到 300ms 以下。
这些要靠压测、profiling、日志、指标验证。
3. 设计假设
设计假设关心模型和抽象是否适合变化。
例如:
CourseAccessGrant 能统一购买、订阅、企业分配、兑换码带来的访问权。
OrganizationMembership 能支持一个账号加入多个组织。
canAccessCourse 能隐藏访问来源细节,让调用方不再拼规则。
这些要靠后续需求落地时的修改范围验证。
把意见改写成假设
意见
我们应该上 Kafka,这样更可靠。
假设
当前异步任务失败主要来自 worker 崩溃和消息丢失。
如果引入持久化消息队列,并支持重试和重放,
支付后访问权发放失败率会从 0.5% 降到 0.05% 以下。
这时就能继续追问:
- 现在失败率是多少?
- 失败原因真的是消息丢失吗?
- Postgres outbox 能不能解决?
- Kafka 的运维成本是否值得?
- 上线后看什么指标判断它成功?
假设把讨论从“谁更有经验”拉回到“什么证据能证明”。
一个好的假设长什么样
好的工程假设通常包含五个部分:
如果我们做 X,
在条件 Y 下,
指标 Z 会发生变化,
达到阈值 T,
否则说明假设不成立。
例如:
如果我们给课程详情页增加缓存,
在日常流量下,
P95 响应时间会从 800ms 降到 300ms 以下,
缓存命中率达到 80% 以上,
否则说明课程详情页瓶颈不主要在重复查询。
这比“加缓存会更快”强很多。
假设驱动开发流程
1. 写下当前判断
例如:
课程详情页太慢,应该加缓存。
2. 找到可观测指标
P50/P95/P99 latency
database query count
cache hit rate
error rate
CPU usage
3. 写成可证伪假设
如果课程详情页瓶颈来自重复读取稳定数据,
那么引入 5 分钟缓存后,
P95 latency 应该下降到 300ms 以下,
且 cache hit rate 应该超过 80%。
4. 做最小实验
不一定立刻做完整缓存平台。
可以先对一个接口、一个课程类型、一个小流量段做实验。
5. 看结果,而不是维护面子
如果 P95 没降,说明假设可能错了。
可能真正瓶颈是:
- 前端渲染
- 第三方接口
- 权限判断
- 数据库锁
- 冷启动
- 网络传输
这不是失败,而是获得了知识。
用假设保护架构决策
架构讨论最容易变成信仰之争。
例如:
单体 vs 微服务
REST vs GraphQL
Kafka vs Redis
SQL vs NoSQL
假设驱动的问法是:
这次选择要改善哪个可观察性质?
例如微服务:
如果拆出 billing service,
billing 团队可以独立发布支付和退款逻辑,
不再被主应用发布周期阻塞。
成功标准:未来 4 周内 billing 相关变更无需主应用发布即可上线,
且跨服务调用错误率低于 0.1%。
这比“微服务更可扩展”清楚得多。
用假设保护抽象
抽象也应该可证伪。
例如你想引入:
CourseAccessGrant
可以写假设:
如果 CourseAccessGrant 是正确抽象,
那么新增一种访问来源时,
调用方不需要修改自己的访问判断,
只需要 course-access 模块增加新的 grant 来源。
如果后来新增兑换码访问,需要全系统到处改:
checkout
course page
mobile API
admin panel
notification worker
那说明抽象没有真正吸收变化。
抽象不是因为看起来漂亮而正确。抽象要能承受变化检验。
失败实验不是失败
假设被推翻不是坏事。
坏的是:
花很大成本做了一个判断,但没有任何证据告诉我们它对不对。
例如:
做了三个月微服务拆分,但没有定义成功指标。
上线后系统更复杂了,没人知道是否值得。
这才是真正失败。
好的失败是:
我们以为缓存能把 P95 降到 300ms。
实验后发现只降到 650ms。
trace 显示瓶颈在权限规则查询。
下一步优化 canAccessCourse 的数据访问路径。
这叫知识增长。
假设和直觉的关系
假设驱动不是否定经验。
经验丰富的人可以更快提出好假设。
区别是:
成熟工程师不会把直觉伪装成结论,而是把直觉改写成可以验证的假设。
直觉是起点,证据是终点。
小结
- 可证伪性让工程判断从意见变成知识。
- 产品、技术、设计都可以用假设表达。
- 好假设包含动作、条件、指标、阈值和失败标准。
- 假设能让架构讨论从信仰之争回到证据。
- 抽象也应该接受变化检验。
- 假设被推翻不是失败,而是获得知识。
- 成熟工程师会把直觉改写成可验证假设。