学习软件架构
摘要
一位软件工程师分享了学习软件架构的见解,强调组织架构与激励机制优先于代码本身,并结合 rust-analyzer 与科学计算代码的实例进行了说明。
暂无内容
查看缓存全文
缓存时间: 2026/05/12 09:58
# Learning Software Architecture
Source: https://matklad.github.io/2026/05/12/software-architecture.html
May 12, 2026 回复一位作为物理学研究员询问如何学习软件设计技能的邮件:
我职业生涯早期曾在一个生物信息学实验室工作(https://lp.jetbrains.com/biolabs/),所以我想我理解你在说什么,也就是“科学代码”这一现象!我的想法如下:
**第一点**元观察是:“软件设计”最好在实践中学习。虽然我在大学里上过一些正式的“设计”课程,甚至还在课程项目中担任过“架构师”,但那些大多只是过家家般的模拟,就像幼儿园小孩扮演消防员一样闹着玩。真正教会我做事的,是我职业生涯中的一个偶然机会:我的第二个真实项目 IntelliJ Rust(https://github.com/intellij-rust/intellij-rust)把我推向了软件领导的岗位,让“设计”成了我必须解决的问题。我在 IJ Rust 上确实犯过几个错误,但都不至于太糟,而且我从中收获颇丰。所以好消息是——软件工程其实没那么复杂,一个好奇心强的人完全可以通过第一性原理(加上随机读几篇博客文章)自己摸索出来。
**第二点**元观察,这是个坏消息:康威定律(https://en.wikipedia.org/wiki/Conway%27s_law)很重要。软件系统的诞生会复制出生产它的组织的社会结构。或者用 neugierig(https://neugierig.org/software/blog/2020/05/ninja.html)那句精辟的话来说:
> 如果我用一句话来总结我的所学,那就是:我们总把编程当作写代码来讨论,但最终发现代码本身不如架构重要,而架构又远不及社会因素重要。
我怀疑,你感知到的工业软件与科学软件之间的差异,主要不在于软件开发知识本身,而在于驱动人们去开发这些软件的激励环境。比如“我的博士论文需要在三个月内发一篇文章”,这或许就是一个很好的解释?
对此你可以做两件事。*一*,有时你会获得设计或微调项目激励结构的机会。这种机会可遇不可求,但一旦抓住就会极具影响力。*这*正是 TIGER_STYLE(https://github.com/tigerbeetle/tigerbeetle/blob/0.17.4/docs/TIGER_STYLE.md)背后的秘诀所在:关键不在于规则集本身,而在于能让这套规则发挥良效的社会上下文。
*二*,你可以速通“哀伤的四个阶段”以达至“接受”。激励结构几乎永远不符合你的理想状态,但如果无法改变它,你可以选择适应它。大多数工业软件项目也是如此——你永远找不到一个“合适”的时候去把某件事做标准,你必须在既定约束下做到力所能及的最佳。
让我以 rust-analyzer(https://github.com/rust-lang/rust-analyzer)为例。该项目的客观现实是,它既非常深(它是个编译器!耶!)又非常广(与 LLM 不同,经典 IDE 包含*大量*针对特定用途构建的特色功能)。其社会现实则是:“深度编译器”部分可以吸引少数才华横溢且全职投入的贡献者,而“广度功能”部分则非常适合一群“周末战士”——那些正在学习 Rust、没有持续参与度、但能抽出几个小时来满足自己实际需求的人。
我坚持要求 `rust-analyzer` 不需要编译 `rustc`,基于稳定版构建,没有任何 C 依赖,并且整个测试套件只需几秒钟就能跑完,这一切都是为了实现“吸引高影响力贡献者”这一目标。我不断折腾构建系统,就是为了确保人们可以专心搞定借用检查器,而不必被其他琐事分心。
为了吸引周末战士,rust-analyzer 的内部被拆分为多个独立的功能模块,每个模块在运行时都由 `catch_unwind` 保护起来。我的想法是,在这些地方我*故意*不太在意代码质量,Feature PR 的上游合并标准仅仅是“主流程跑得通且已测试通过”。代码崩溃也没关系,只要满足以下条件,反而只会吸引更多贡献者:
- 质量问题被隔离在该功能内部,不会蔓延扩散;
- 在运行时,崩溃对用户不可见(至关重要的一点是 rust-analyzer 的功能需配合不可变快照工作,且绝不能污染数据)。
相比之下,当编写提供功能支持的底层核心*主干*时,我对质量的把关要严苛得多。
关于“适应而非修复激励结构”,这里提个醒:未来充满了不确定性,而且往往以最不方便的方式降临。最初发起 rust-analyzer*实验*的动机是为了避免重复开发一套并行编译器(即 IntelliJ Rust 里的那套),并*原型化*一种更好的 LSP 架构,以便将经验反哺给 `rustc`。因此,即使在核心部分(尤其是核心部分),代码也带有*非常*强烈的实验性质。唉,好吧。看来现在又多了一套需要维护的编译器了,是吧?
我猜 uutils 项目可能经历了类似的情况:它最初是人们学习 Rust 的首选目标,最终却演变成了 Ubuntu coreutils 的实现方案。
**第三**,下面是一些具体的建议。遗憾的是,我不知道有哪一本书能包揽所有真理。我怀疑只能在博尔赫斯的虚构短篇里找到这样的书:实践在这里似乎是不可或缺的关键要素。但以下几样东西值得留意:
Gary Bernhardt 的 Boundaries(https://www.destroyallsoftware.com/talks/boundaries)演讲是我的心头好。其中包含了扎实的面向对象层面的建议,对我而言,它更是激发了对“元认知”的思考。
《How to Test》(https://matklad.github.io/2021/05/31/how-to-test.html)这篇是我真希望早就看到的文章。我一眼就明白测试的重要性,但过了很久我才“狂妄”到足以承认:绝大多数广为流传的测试建议不过是神棍般的江湖骗术,并真正理清了到底什么方法才有效。
∅MQ Guide(https://zguide.zeromq.org/docs/chapter6/)以及更广义上 Pieter Hintjens(http://hintjens.com/)的文章,让我接触到了康威定律的思维模式。rust-analyzer 那种“功能开发”架构?其实就是乐观合并策略(http://hintjens.com/blog:106)的实践应用。
Jamii 写的 Reflections on a decade of coding(https://www.scattered-thoughts.net/writing/reflections-on-a-decade-of-coding/)非常出色,思考层面相当深入。这也是我链接列表(https://matklad.github.io/links.html)中特意排在第一位的文章。
Ted Kaminski(https://www.tedinski.com/archive/)的博客是最接近一套连贯软件开发理论的存在,很恰当地被包装成一本“不存在的书”的笔记集!
至于具体的书籍,《Software Engineering at Google》(https://abseil.io/resources/swe-book)和 John Ousterhout 的《The Philosophy of Software Design》经常被推荐。它们写得不错。特别是 SWE 那本,帮我对齐了几个重要概念的名称(https://matklad.github.io/2022/07/04/unit-and-integration-tests.html)。但它们对我来说并没有带来颠覆性的启发。
相似文章
优秀的架构不需要胡萝卜,也不需要大棒
这篇博客文章主张,良好的软件架构应当是不言自明且毫无阻力的,倡导采用 Netflix/Spotify 式的“铺平道路”模式,而非依赖强制性的治理委员会或嵌入式架构师。
Martin Fowler:技术债、认知债与意图债
Martin Fowler 反思 AI 对代码质量的影响,指出人类的“懒惰”反而促成清晰抽象,而 LLM 则可能用不必要的复杂性把系统拖胖。
软件工程定律
精心整理的 56 条软件工程定律与原则,涵盖系统、团队与决策。
@rohit4verse:AI 并没有让代码变得廉价,而是让劣质代码变得致命。Matt Pocock:“软件基础比以往任何时候都更重要”AI 在……
探讨了 AI 如何放大代码质量的影响,强调软件基础比以往任何时候都更重要,并推荐了构建可靠 AI agent 的五种设计模式。
@ainunnajib:代码免费,编码时代终结,系统设计成为软件工程的新核心
本文探讨了软件工程的重心正从传统编码向系统设计转移,反映出随着代码生成功能日趋普及,整个行业的优先级正在发生变化。