Mercury 工程师 Ian Duncan 在 Haskell 官方博客新系列 Haskellers from the trenches 中写了一篇文章,题目是《A Couple Million Lines of Haskell: Production Engineering at Mercury》。
里面最抓人的数字,是约 200 万行 Haskell。原文也说清楚了:这是去掉注释等内容后的 Haskell 代码量,不等同于 Mercury 的全部代码规模。
有意思的地方不只是“冷门语言跑进金融系统”。更反常的是,Mercury 是一家金融科技公司,约 1500 名员工,服务 30 万以上企业客户,2025 年交易量达到 2480 亿美元;而多数工程师入职前并不会 Haskell。
所以这篇文章真正要回答的问题不是:Haskell 到底优不优雅。
更硬的问题是:在强监管、快速扩张、很多新人加入的组织里,一门不大众的语言,能不能靠工程边界稳定落地。
Mercury 的反常识:不是选了 Haskell,而是敢把它用大
金融后端通常更偏爱 Java、C#、Go,或者更保守的 JVM 技术栈。理由很现实:招聘池大,生态成熟,工具链稳,合规和监控经验也多。
Mercury 长期使用 Haskell,就天然要付两笔成本。
新人要学。团队知识也更容易集中在少数熟手身上。
Ian Duncan 没有把答案写成“编译器会拯救一切”。他强调的可靠性,是 adaptive capacity:系统吸收变化、降级运行、让操作者理解并调整的能力。
这句话很关键。可靠性不只是“没有 bug”,也不是一次性证明正确。生产系统每天都在变:业务规则变,监管要求变,外部 API 变,团队成员也在变。
Haskell 在 Mercury 里的角色,更像 operational aid。类型系统不是论文里的 correctness proof,而是运营辅助工具:把容易忘、容易错、容易出事故的知识,压进接口和类型里。
用一张表看,会更清楚:
| 问题 | 常见后端做法 | Mercury 文中强调的做法 | 我的判断 |
|---|---|---|---|
| 招聘与上手 | 选 Java、Go、C#,降低招聘摩擦 | 多数工程师入职后再学 Haskell | 可行,但要用培训和工具链补成本 |
| 可靠性来源 | 测试、文档、代码审查、事故复盘 | 类型边界、可理解架构、提前评审 | 不是替代测试,而是减少低级误用 |
| 高风险流程 | 靠规范提醒“不要这样写” | 让危险路径不能被直接调用 | 比口头规则更适合快速扩张团队 |
| 适用范围 | 通用企业后端 | 金融交易、事件发布、状态机等高约束场景 | 不能外推到所有公司、所有金融系统 |
这也是这篇文章克制的地方。它没有说 Haskell 因为“纯粹性”就能自动解决生产问题。
现实系统里有数据库连接池、重试、缓存、并发状态和外部 API。副作用不会消失。问题是,能不能把副作用关在更窄、更清楚的边界里。
类型系统真正管住的,是那些“漏一步就出事”的流程
原文最有价值的例子,是事务和事件发布。
很多事故不是算法太难,而是流程被写散了。比如先写数据库,再发事件。两步必须保持一致,但工程师赶进度时,很容易漏掉某一步,或者在错误位置调用。
传统做法是写文档、加 code review、在团队频道里反复提醒:请用某个安全方法,不要自己先写事务再发事件。
这类提醒当然有用,但它有个弱点:它假设每个人在每次改代码时,都记得旧规则。
Mercury 的做法,是把流程封装成 Transact。开发者可以 record 事务,也可以 emit 事件,但真正执行只有一个出口:commit。
commit 内部负责把数据库提交和事件发布放进安全路径。这样,正确做法不再是一条需要背下来的规矩,而是代码里唯一能走通的门。
这就是“类型系统作为运营记忆”的意思。
它不负责替人理解业务,也不保证所有需求都正确。它做的是另一件事:把已经确认过的危险区,用接口围起来,让后来者少走错路。
这对后端和基础设施工程师有直接影响。
如果你维护的是支付、账务、订单状态机、消息投递、权限变更这类系统,真正该检查的不是“我们有没有文档”。而是这几件事:
- 高风险操作有没有唯一入口;
- 调用顺序能不能被类型或接口约束;
- 危险方法是不是还暴露给普通业务代码;
- code review 里反复提醒的规则,能不能下沉到库设计里。
换句话说,不一定要换 Haskell。用 Kotlin、Rust、TypeScript,甚至 Go,也能做一部分边界设计。只是表达能力、样板代码和团队习惯不同。
工具有差别,问题是同一个:别把组织记忆只放在人的脑子里。
对管理者的启示:别先问换不换语言,先问边界谁来守
技术管理者读这篇文章,最不该得到的结论是“我们也该上 Haskell”。
Mercury 的案例只能说明:在特定团队、特定业务压力和长期投入下,Haskell 可以支撑大规模生产系统。它不能证明 Haskell 适合所有金融系统,也不能证明冷门语言适合所有大公司。
更现实的问题是:当团队变大,新人变多,哪些规则必须进入代码结构,哪些规则可以留在培训材料里。
如果一个风险点每次都靠资深工程师口头把关,那它就是组织扩张的隐性瓶颈。人少时还能靠熟人网络兜住,人一多,就会“口耳相传,递减失真”。
对管理者,动作可以更具体一点:
| 角色 | 该做什么 | 不该做什么 |
|---|---|---|
| 后端 / 基础设施负责人 | 盘点事故复盘里反复出现的误用路径,把它们改成库和接口约束 | 只增加文档、流程和审批层级 |
| 技术管理者 | 给关键基础库、类型建模、内部培训留出时间 | 把类型设计当成少数专家的个人洁癖 |
| 架构评审者 | 关注“非法路径是否仍可调用” | 只看模块图和服务拆分是否好看 |
这里也有现实限制。
原文没有给出完整事故率、可用性指标、培训成本,也没有证明这套体系在跨语言、跨服务场景中同样强。Mercury 还在申请美国 OCC national bank charter,并不是已经获得银行牌照。
所以判断要收住:这是一份有价值的生产工程样本,不是通用处方。
接下来真正该看的,不是 Haskell 会不会变成金融行业主流。更该看三件事:
- 新人培训能否跟上团队继续扩张;
- 类型边界能否覆盖更多跨服务流程;
- 监管要求变复杂后,这套工程纪律是否还能保持低摩擦。
回到开头那个数字,约 200 万行 Haskell 真正说明的不是“函数式语言赢了”。
它说明另一件更朴素的事:生产系统靠人记规矩,规模一大就会漏。能把规矩写进边界,经验才不会随人流动而流失。
