一个科研背景的读者问 matklad:怎么学软件设计和架构?
这个问题看着像在要书单。matklad 的回答却把问题往回拽了一步:你真正要学的,不是架构名词,而是在真实约束里做取舍。
这篇随笔有意思的地方也在这里。matklad 早年参与过生物信息实验室,见过所谓 scientific code:代码服务于实验、论文和截止日期。它粗糙,不等于写代码的人笨;很多时候,是激励不允许他们慢慢做工程。
软件架构不是漂亮图纸。它更像组织压力在代码里的投影。
真实项目会收费,课程项目不会
matklad 的建议可以压成三条。
| 问题 | 他的判断 | 对读者的影响 |
|---|---|---|
| 怎么学设计 | 靠真实项目练出来 | 不要把课程项目当架构训练的终点 |
| 科研代码为什么常显得乱 | 多半是激励问题 | 先看论文、实验、交付期限怎么设定质量标准 |
| 架构怎么落地 | 适配贡献者结构 | 边界、测试、准入门槛要按协作现实设计 |
他也上过设计课,甚至在课程项目里当过“架构师”。但那更像小孩扮消防员:姿势像,代价不真。
真正让他学会设计的,是后来在 IntelliJ Rust 里被推到软件领导位置上。设计变成自己的问题,错误也要自己吞。
这点对想学架构的程序员很不友好,但很实在。架构能力不是听懂 SOLID、DDD、分层、插件化这些词。它是你在约束里回答一串问题:哪里必须硬,哪里可以软;哪里必须加测试,哪里可以先容忍粗糙;哪里要拦住复杂度,哪里要让新人能进来。
对有工程经验但卡在“架构感”上的程序员,最直接的动作不是再收藏十本书,而是找一个真实项目承担边界设计:模块怎么拆、接口怎么稳、坏代码怎么隔离、测试卡在哪里。没有后果,训练很容易变成讲道理。
对科研项目负责人,动作更具体:如果论文截止日期永远压倒维护成本,就别指望代码自然长成工业系统。要么承认它是一次性实验代码;要么给核心流程、数据格式和复现实验留出最低限度的工程预算。
架构是激励的投影,不是审美比赛
matklad 把 Conway 定律放在主轴上:软件系统会复制生产它的组织沟通结构。说得更直白一点,代码最后常常长得像团队本身。
科研代码、工业代码、开源项目的分水岭,不是“专业”和“不专业”。真正的分水岭是:谁为长期后果买单。
科研项目的核心目标可能是三个月后发论文。工业项目可能要赶季度交付。开源项目面对的是另一种现实:贡献者流动很大,有人能长期啃硬骨头,也有人只能周末修一个自己需要的小功能。
rust-analyzer 是 matklad 举的好例子。这个项目既深又宽:深处像编译器,宽处像 IDE,有大量面向具体场景的小功能。
所以它没有把所有地方都要求成同一种质量。
核心 spine 要严。它支撑分析能力,不能塌。
外围功能可以降低门槛。每个功能相对独立,用 catch_unwind 隔离崩溃;只要 happy path 能跑、有测试,就可以先接进来。前提也很清楚:坏代码不能污染核心数据,运行时崩溃不能让用户感知。
这不是通用最佳实践。换个项目,可能就是灾难。
它成立,是因为 rust-analyzer 的贡献者结构需要这种设计:用较低门槛吸引周末贡献者,用高质量核心保护系统底盘。好架构不是把每个角落都修成神殿,而是知道哪里是承重墙,哪里只是临时隔断。
这里最该观察的变量,不是某个模式有没有被采用,而是质量门槛有没有分层:核心路径是否被保护,外围贡献是否被隔离,测试是否能挡住破坏性变更。如果这三件事没有设计好,所谓开放协作很快会变成维护债务。
“天下熙熙,皆为利来。”这句话放到软件里并不俗。项目结构、测试策略、代码边界,背后都是成本、收益、责任和人力流动。看不见这些,只盯着模式和书名学架构,很容易学成装修学。
科学代码、工业代码、开源代码,差在谁结账
这篇随笔最有价值的地方,是它没有把 scientific code 写成对科研人员的嘲讽。
很多科研代码的问题,不是作者没有工程常识,而是系统不奖励长期维护。论文发表、实验结果、组会进度、基金节点,都会把代码质量压到“够用就行”。这不是道德问题,是激励问题。
工业代码也不天然高贵。它只是更早遇到付费用户、线上故障、客户合同和团队交接。代价会回来敲门,所以组织不得不把一部分工程质量制度化。
开源项目更微妙。它既没有完整雇佣关系,也不能只靠热情续命。好的架构设计,常常是在给不同强度的贡献者安排入口:长期维护者守核心,偶发贡献者做边缘,测试和边界负责兜底。
rust-analyzer 还有一个反讽后果。它起初带有实验意味:避免再写一个平行编译器,探索更好的 LSP 架构,再把经验回流到 rustc。但现实没有按剧本走。实验架构被用户和生态固定下来,最后像 matklad 自嘲的那样:好吧,现在又多维护了一个编译器。
这就是技术项目常见的命运。原型解决了真问题,就会被现实钉住。补丁跑得足够久,就会变成平台。权宜之计,最容易长命百岁。
所以,读这篇随笔以后,真正该做的不是抄 rust-analyzer 的方案。
对程序员,下一步是把学习目标从“掌握架构知识”改成“承担架构后果”:接手一个模块,定义边界,写下质量门槛,观察半年后的维护成本。
对科研或开源项目负责人,下一步是先画出贡献者结构:谁长期维护,谁偶尔贡献,谁只关心结果。然后再决定哪些代码必须严,哪些入口可以放低,哪些失败必须隔离。
matklad 也给了资源,但语气很克制:Gary Bernhardt 的《Boundaries》、他自己的《How to Test》、ZeroMQ 与 Pieter Hintjens、Jamii、Ted Kaminski,以及《Software Engineering at Google》和 Ousterhout 的《A Philosophy of Software Design》。这些都值得看,但没有一本是圣经。
原因很简单。架构不是答案集,而是判断力。判断力只在真实后果里生长。
