Learning Software Architecture: Practice, Conway's Law, and Incentive Structures
Published: 2026-05-13 Reading time: 10 minutes Software Engineering / Architecture
This article is a deep dive into matklad's (Aleksey Kladov) recent email reply on learning software architecture. Kladov is the author of IntelliJ Rust and rust-analyzer, two of the most impactful Rust IDE tools ever built. His post hit 500 points and 101 comments on Hacker News — a signal that the software engineering community hungers for honest, practical wisdom about architecture that goes beyond textbooks.
The Core Thesis: Architecture Is Learned by Doing
matklad opens with a blunt observation: formal software design courses are largely "make-believe, kindergarteners playing fire-fighters." His own formal education in architecture was worthless compared to the real learning that happened when he was thrust into a position of software leadership on IntelliJ Rust.
This is the uncomfortable truth that most architecture training ignores. You can read all the Gang of Four patterns, memorize SOLID principles, and pass any design exam — but none of it prepares you for the messy reality of a living codebase used by thousands of developers.
The good news? "Software engineering is simple enough that an inquisitive mind can figure it out from first principles (and reading random blog posts)."
Conway's Law: Software Mirrors Social Structure
matklad cites Conway's Law as the most important concept for understanding software architecture. The law states that organizations design systems that mirror their communication structures. But matklad, quoting neugierig, takes it further:
"We talk about programming like it is about writing code, but the code ends up being less important than the architecture, and the architecture ends up being less important than social issues."
This single sentence reframes the entire discipline. The difference between industrial and scientific software isn't about knowledge — it's about the field of incentives that compels people to produce that software.
When a PhD student needs to publish in three months, the resulting "scientific code" isn't bad because they don't know how to write good code. It's bad because the incentive structure rewards speed-to-publication over maintainability, correctness, or clean architecture.
This insight applies everywhere. The messy microservice soup at your company? Check the org chart. The undocumented monolith that everyone is afraid to touch? Check who gets promoted and why.
Incentive Structures Matter More Than Code Quality
This is the most powerful section of matklad's post. He describes two approaches to dealing with incentive structures:
1. Design the Incentive Structure (Rare but Impactful)
Occasionally you get a chance to shape the incentives of a project. This is "the secret sauce behind TIGER_STYLE" — not the specific coding rules, but the social context that makes those rules appropriate. When you can set the norms, the hiring criteria, the review process, and the success metrics, you're doing architecture at the highest level.
2. Adapt to the Incentive Structure (The Default Reality)
Most of the time, you can't change the incentives. The PhD timeline, the quarterly revenue target, the startup's "move fast" culture — these are constraints, not bugs. matklad's advice is pragmatic to the point of being Buddhist: "You can speedrun the four stages of grief to acceptance."
Accept that there's never time to do things properly. Do the best you can, given the constraints. This isn't defeatism — it's realism that lets you ship software rather than polish a perfect architecture that never sees the light of day.
Case Study: rust-analyzer's Two-Track Architecture
The most concrete and fascinating part of matklad's post is how he designed rust-analyzer to attract two completely different types of contributors:
- Deep contributors — brilliant developers who can work on compiler internals (borrow checker, type inference, name resolution)
- Weekend warriors — people learning Rust who can scratch an itch in an hour or two, submitting a single feature PR
This dual-track design explains many of rust-analyzer's technical decisions:
For Deep Contributors: Lowering Barriers to Entry
matklad insisted that rust-analyzer shouldn't require building rustc, that it builds on stable Rust, has zero C dependencies, and runs its entire test suite in seconds. Every decision was aimed at letting someone work on the borrow checker "without thinking about anything else." No build system wrangling, no waiting for compilation, no environmental setup friction.
For Weekend Warriors: Catch-Unwind Isolation
This is the most creative and controversial decision. matklad split rust-analyzer's internals into independent features, each guarded by catch_unwind at runtime. The bar for getting a feature PR accepted was deliberately low: "happy path works & tested."
If the code crashes? That's fine — it attracts further contributors, provided two conditions hold:
- The quality is isolated to a single feature and doesn't spill over
- At runtime, the crash is invisible to the user — features work with an immutable snapshot and can't poison shared data
Meanwhile, the core spine — the infrastructure that supports all features — received far more pedantic quality treatment. The architecture itself enforces the quality gradient.
This is brilliant because it recognizes that not all code needs to be high quality. Weekend warrior code is allowed to be imperfect, as long as the architecture contains the imperfection. The architecture creates the incentive for weekend warriors to contribute, and the incentive isolation — not code reviews or style guides — protects the project from their mistakes.
The Future Is Uncertain and Happens Inconveniently
matklad shares a cautionary tale about rust-analyzer itself. The original motivation was to avoid writing a parallel compiler for IntelliJ Rust and to prototype a better LSP architecture that could backport learnings to rustc. The core code was intentionally experimental.
"Oh well. Stuck with one more compiler now, I guess?"
This understated comment masks a massive outcome: what started as an experiment became the de facto Rust language server. The future happened in the least convenient way — the experimental project became the production project, and there's no way to go back.
matklad suspects the same happened to the uutils project, which started as a place for people learning Rust and ended up as Ubuntu's coreutils implementation.
Recommended Resources: Where to Actually Learn Architecture
matklad doesn't know of a single book that contains all the truths about software architecture. He suspects "one can only find such a book in an apocryphal short story by Borges." But he does point to several resources worth your time:
- Boundaries — Gary Bernhardt's legendary talk. Solid object-level advice that also triggers meta-level inquiry.
- How to Test — matklad's own essay that cuts through the "shamanistic snake-oil" of most testing advice.
- ØMQ Guide and Pieter Hintjens' writings — the source of Conway's Law thinking that shaped rust-analyzer's optimistic merging approach.
- Reflections on a decade of coding — Jamii's excellent meta-level reflection.
- Ted Kaminski's blog — "the closest there is to a coherent theory of software development."
- Software Engineering at Google and A Philosophy of Software Design (Ousterhout) — mentioned as good but not groundbreaking.
Practical Takeaways for Developers
- Stop seeking architecture from courses. The best way to learn is to build something real, make mistakes, and read honest postmortems.
- Read your organization's org chart as an architecture document. Conway's Law isn't a theory — it's a diagnostic tool.
- When you can't change incentives, accept them and adapt. The best code in the world is useless if it doesn't ship within your constraints.
- Design your project for different contributor archetypes. Not everyone needs to write perfect code. Design your architecture to contain imperfection safely.
- Use architecture to create quality gradients. Protect the core with rigor, but make the periphery welcoming to newcomers.
- Plan for the future to happen inconveniently. Your experimental project today might be someone's production dependency tomorrow.
matklad's post is a rare artifact in software engineering writing: practical wisdom that doesn't pretend the world is clean. It acknowledges that code is the least interesting part of software — the architecture matters more, and the social dynamics matter most of all. Reading it feels like getting career advice from someone who has actually built world-class software, not just taught a course about it.
Also on EasyTool.me: Check out our guides on Agent Skills by Addy Osmani, Simon Willison on Vibe Coding vs Agentic Engineering, and The Hidden Costs of Great Abstractions.
Read the original: Learning Software Architecture by matklad (2026-05-12)