abstraction
- S:设计、review 和取舍时反复落到"抽象"上——模块、接口、类型、协议、服务边界都被称作抽象,但大家说的往往不是同一件事。
- C:"抽象好 / 过度抽象坏"两种结论并存:既要靠抽象压缩复杂度,又总在它失效时付出代价;只记结论无法指导判断。
- Q:抽象的本质是什么?它解决什么问题、靠什么机制生效?代价和失效边界在哪里?
- A:抽象 = 用边界、接口与信息隐藏,把底层复杂度压缩成可局部推理的契约;它不消灭复杂度,只重新分配;代价是能力与性质的交换,以及必然的泄漏。设计就是在这两者之间找平衡点。
优秀的 abstraction 把最常见的复杂度隐藏掉,同时让不可避免的泄漏发生在可预测、可理解的位置。
抽象是什么
抽象是对底层复杂事物的简化,同时定义两件事:它是什么、它不是什么。— Tedinski
- 抽象的实质是"假装":string 库假装字符串和数字一样容易操作;文件系统假装硬盘不是磁盘阵列而是文件夹层级;TCP 假装网络是可靠的。逐个剥开,都是"简化 + 约定"。
- 抽象 = 边界 + 接口 + 信息隐藏:模块、函数、类型、协议、服务边界、领域模型都是抽象的形态(软件工程)。
- 定义"是什么"必然同时定义"不是什么":一个抽象必须守住自己不覆盖的部分,否则它只是给"东西"换了个名字。
解决什么问题
- 压缩认知负担:支持局部推理——理解、修改一个模块不必掌握整个系统(软件设计心智模型)。
- 复用与可替换:接口不变,实现可以换。
- 并行协作:以接口为界,多个模块、多个团队各自演化互不阻塞。
- 学习成本分摊:先掌握抽象即可上手,不必一次性理解全部底层——注意这只是推迟,不是免除(见"泄漏")。
抽象不消灭复杂度,只重新分配复杂度。系统核心抽象的三个问题:核心抽象是什么?它提供什么结构?把问题 Y 转成什么问题 Z?再补一问:它让我不用操心什么、又必须操心什么?
核心机制
- 边界:切开"什么被保护、什么可以变化";变化落在内部,稳定落在接口。
- 接口:最小契约 + 显式意图;好的接口让正确用法自然、非法状态难以表达、调用者表达意图而非理解实现。
- 命名:概念具名之后才能被讨论、推理和演进。
- 不变量:把规则从人的记忆搬进结构(Design = move invariants into structure,软件设计底层原则)。
关键取舍
能力与性质之间的交换
https://www.tedinski.com/2018/01/30/the-one-ring-problem-abstraction-and-power.html
越通用、越强、越抽象,则越失去其可分析的性质。
Ted Kaminski 的核心论点:抽象设计是一个双向取舍——你不可能在不牺牲性质的情况下增加能力,也不可能在不牺牲能力的情况下增加性质。
- 全能的抽象是无意义的(你只是给"东西"换了个名字),高度约束的抽象只能是少数几种东西。设计就是找到中间的那个点。
- 抽象有内外两面。
id :: a -> a外部可以传入任何类型,但内部被持有为抽象——正因为内部什么都不知道,反而获得了性质:这个签名只有唯一实现(parametricity)。给inc从Integer -> Integer放宽到Num a => a -> a,能力增加了(能处理浮点数),但性质减少了(不再知道是整数,可能效率更低)。 - 常见错误是单向思考:看到设计做不到 X,就想"修复"它、让它更强大——却忘了这必然让它更无意义。C++/Scala 就是这种"不断增加能力"的产物。
- 插件系统的反直觉:插件能做任何事 → 你对插件一无所知 → 真正被约束的是宿主应用(不能破坏插件兼容性)。Python 2→3 迁移困难、Vim/Emacs 无法重构核心,都是同一个问题。
- DSL/配置文件的教训:声明式 → 意外图灵完备,是"追求能力"的典型路径。更好的做法是分离声明与自动化——用代码生成声明式配置(如 Kubernetes 的声明式 YAML + 编程生成),而不是让配置本身变成代码。
泄漏是必然的
All non-trivial abstractions, to some degree, are leaky. — Joel Spolsky 详见 读博客:The Law of Leaky Abstractions
- 抽象只能保护"契约承诺覆盖的失败模式";底层现实(断网、拥塞、无等价语义)会穿透抽象泄漏出来。
- 泄漏不是 bug,而是定价:承诺越多、能力越强,泄漏时代价越大。
- 与"能力 vs 性质"同源:抽象未覆盖的部分,在设计层面表现为失去可分析的性质,在运行层面表现为泄漏的底层——同一个不完整的两面。
统一透镜:核心抽象三问 × 泄漏四问
分析任何系统先问两轮:核心抽象是什么,它在哪里泄漏。这不是两个话题,而是同一枚硬币的正反面——三问看向"它承诺了什么",四问看向"承诺在什么条件下失效"。
第一问:核心抽象是什么?(系统核心抽象)它隐藏了什么复杂度、暴露了什么简单模型?把问题 Y 转成了什么问题 Z?它让我不用操心什么、又必须操心什么?
第二问:这个抽象在哪里泄漏?
- 它隐藏了什么复杂度?——被藏的复杂度不会消失,只是潜伏;
- 它暴露了什么简单模型?——模型越简单、藏得越深,泄漏时越难在抽象层解释;
- 哪些底层性质仍然会影响上层?——预登记泄漏面,别等它漏;
- 在什么条件下抽象会泄漏?——断网 / 拥塞 / 规模 / 并发 / 性能 / 语义不完美等价……列出击穿条件的清单。
两者的联系:
- 隐藏点 = 泄漏候选点:"抽象的实质是隐藏"和"泄漏是必然"是同一条界线的两面;被推迟的复杂度总在某个边界上兑现(Tesler 复杂度守恒)。
- 简单模型 = 泄漏面:暴露的模型越简单,越依赖底层保持"假象"成立,击穿条件越多。
- 三种时态统一:设计时失去可分析性质(能力 vs 性质)→ 理解时缺底层知识(学习时间守恒)→ 运行时现实穿到上层(Leaky Abstractions),是同一个"抽象未覆盖部分"在设计 / 理解 / 运行三个时刻的表现。
- 泄漏条件 = 底层性质 ≠ 抽象假设的瞬间:预先答出第 3、4 问,就是在替未来的排障者省时间。
实例(基础行来自 系统核心抽象,泄漏列来自 The Law of Leaky Abstractions 与常规排障经验):
| 系统 | 核心抽象 | 隐藏的复杂度 | 简单模型 | 什么条件下泄漏 |
|---|---|---|---|---|
| Redis | 内存中的数据结构服务器 | 内存分配、淘汰、单线程调度、持久化 | 对 key 的 O(1) 操作 | 内存超预算触发淘汰、大 key / 慢命令阻塞全部请求、BGSAVE fork 抖动 |
| MySQL | 关系模型 + 事务 + 索引 | B+ 树存储、锁、MVCC、查询优化器 | 声明式 SQL 与一致性保证 | 等价查询性能差千倍(优化器选错路径)、死锁与锁竞争、隔离级别可见性、复制延迟 |
| Kafka | 分布式追加日志 | 分区、复制、顺序与 offset 管理 | 有序事件流、消费进度自管 | 跨分区无序、rebalance 暂停消费、leader 切换丢失未复制数据、at-least-once 需应用侧幂等 |
| NFS | 远程文件 = 本地文件 | 网络、缓存一致性、权限 | 路径语义 | 断网 / 服务器宕机;与 .forward 叠加时无人负责端到端语义 |
学习任何系统:先答上表的前两列,再预填泄漏面(后两列);设计任何抽象:先声明核心抽象,再显式列出泄漏条件。
工程实践(怎么做)
- 找稳定接缝:接口落在稳定的业务概念上,把变化塞进实现(机制与策略分离)。
- 契约小而诚实:只承诺能兑现的;已知泄漏点(失效模式)写进文档而不是藏起来。
- 面向意图设计接口,不面向实现暴露细节(api-design)。
- 抵抗"加能力"的单向诱惑:每次想让抽象更强大,同时回答"我因此失去什么性质?"。
- 声明式与自动化分离:用代码生成声明式配置,不要让配置本身演变成图灵完备的语言。
适用边界
- 过度抽象(抽象反转,abstraction inversion):使用者被迫亲手实现抽象本应提供的功能,抽象层反而变成阻碍。
- 内平台效应(inner platform effect):在应用内部重造一个通用平台或编程语言,换来"能力幻觉"和永久维护负担。
- 插件系统、声明式 DSL 失控:见"能力与性质之间的交换"——这两类都是"追求能力"的典型代价。
相关笔记
- 软件的复杂度:抽象是压缩偶然复杂度的工具,不消灭本质复杂度。
- 系统核心抽象:用"核心抽象 / 结构 / 问题转换"三问学习任何系统。
- The Law of Leaky Abstractions:泄漏的详细案例(TCP、SQL、NFS、C++ string、ASP.NET)。
- law-sofsoftware-engineering:Leaky Abstractions、Tesler 复杂度守恒、Hyrum 定律等工程定律集合。
links
- https://www.tedinski.com/2018/01/30/the-one-ring-problem-abstraction-and-power.html
- https://www.joelonsoftware.com/2002/11/11/the-law-of-leaky-abstractions
- https://en.wikipedia.org/wiki/Abstraction_inversion
- https://en.wikipedia.org/wiki/Inner-platform_effect
- https://en.wikipedia.org/wiki/Law_of_leaky_abstractions
评论