抽象二问 — Why Abstraction

发布于 Jan 13, 2026 更新于 Jan 13, 2026

这篇文章来自于review pr时,发现owner对一个简单需求进行了有些复杂的抽象。review完后在想怎么和他讲这个事情:直觉告诉我不太OK,我也知道怎么改合适。但是我不知道怎么能让他未来遇到其它问题时能够进行恰当的抽象。于是就开始思考,有没有什么系统化的方法论,来指导确定一个设计需要进一步抽象,而不是靠直觉。

结论是,可以用两个问题帮助自己确认是否要进行抽象:

  • 为什么直接写不可以?
  • 抽象的代价是什么?

问题 1:为什么直接写不可以?

—— 说不上来往往是可以直接写。

 可以接受的常见答案:

  1. 修改面不可控:直接写会导致未来新增/变更需要改 N 处(N 明显大于 2 或者分散在多模块),且容易漏改。
  2. 不变式无法集中表达:直接写会让关键不变式(安全/风控/状态一致性/资源释放)散落在各处,难以审计和测试。
  3. 边界无法建立:直接写会导致调用方必须知道内部细节才能正确使用(例如:必须按特定顺序调用、必须手动对齐某些时序/锁),这说明缺少“语义边界”。
  4. 性能或资源目标达不到:直接写会导致无法满足 O(Δn)/延迟/内存上限/并发安全等硬指标,而抽象可以把这些约束固化成结构。
  5. 可观测/运营不可持续:直接写会导致指标口径不一致、排障路径不统一,无法在团队规模下稳定运行。

如果回答不落在以上之一,默认结论通常是:可以直接写

问题 2:抽象的代价是什么?

—— 抽象不是免费午餐

四类税:

  1. 概念税:引入了几个新概念/新类型/新协议?新人理解需要多长路径?是否需要读多个文件才能理解?
  2. 耦合税:抽象把哪些东西绑定死了?未来替换实现是否更难?抽象边界是否泄漏(调用方仍需理解内部细节)?
  3. 性能税:从 O(Δn) 变 O(n) 了吗?多了分配/拷贝/解码/unique/sort 吗?热路径是否可证明不退化?
  4. 演进税:为了适配一个新需求,需要改抽象本身吗?如果要改抽象,会不会影响所有调用方?

恰当进行抽象时,上述四个代价应当是想清楚的,如果答不出来,说明是凭感觉抽象,不可取。

补充一问:核心不变量是什么?

—— 可能的回击:未来可能会拓展

针对这种潜在需求,要求写出未来可能出现的两个扩展示例,并说明它们如何落在同一契约下。写不出来,就说明抽象是预支。

总结

这次 code review 让我意识到:判断是否需要抽象,不能只靠“直觉觉得不对”,而应当有一套可复用的决策流程。抽象的价值在于建立稳定语义边界、集中不变式并隔离变化,但它永远伴随成本,因此必须先问清楚两件事:为什么不能直接写、抽象要付出什么代价。若“不能直接写”的理由无法落在修改面不可控、不变式无法集中、边界无法建立、性能/资源目标达不到、可观测/运营不可持续这类硬约束上,默认就应该直接写;而一旦选择抽象,就必须显式核算概念税、耦合税、性能税、演进税,答不出来往往意味着抽象是凭感觉而非证据驱动。最后,为了防止用“未来可能扩展”合理化过度设计,还需要补充追问核心不变量与变化轴:要求给出至少两个具体扩展示例,并证明它们确实落在同一契约之下,否则就是在预支复杂度。通过这套问题集,抽象从审美与习惯变成可审计的工程决策,也更容易在团队内形成一致的代码风格与演进路径。

Noam Chi

An Innovative Quant Developer. 2018 VEX World Final THINK Award🏆