核心问题

我们的判断能不能被证据推翻?

认识论里有一个重要思想:可证伪性。

一个说法如果无论发生什么都能解释,那它就很难成为可靠知识。

映射到软件工程:

一个工程判断如果不能被验证或推翻,它就只是意见。

例如:

这个架构更灵活。
这个页面体验更好。
这个优化会更快。
这个抽象以后会有用。
这个功能能提高转化。

这些话不一定错,但它们还不是可验证判断。

我们要把它们变成假设:

如果我们把购买流程从 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% 以下。

这时就能继续追问:

  1. 现在失败率是多少?
  2. 失败原因真的是消息丢失吗?
  3. Postgres outbox 能不能解决?
  4. Kafka 的运维成本是否值得?
  5. 上线后看什么指标判断它成功?

假设把讨论从“谁更有经验”拉回到“什么证据能证明”。

一个好的假设长什么样

好的工程假设通常包含五个部分:

如果我们做 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 的数据访问路径。

这叫知识增长。

假设和直觉的关系

假设驱动不是否定经验。

经验丰富的人可以更快提出好假设。

区别是:

成熟工程师不会把直觉伪装成结论,而是把直觉改写成可以验证的假设。

直觉是起点,证据是终点。

小结

  1. 可证伪性让工程判断从意见变成知识。
  2. 产品、技术、设计都可以用假设表达。
  3. 好假设包含动作、条件、指标、阈值和失败标准。
  4. 假设能让架构讨论从信仰之争回到证据。
  5. 抽象也应该接受变化检验。
  6. 假设被推翻不是失败,而是获得知识。
  7. 成熟工程师会把直觉改写成可验证假设。