Domain
Software Design
A systematic learning path for software design — from clean code to architecture, testing, and quality culture. Covers code quality, TDD, DDD, distributed system design, and DevOps/quality organization.
The Terrain of This Field
The terrain of software design can be read as a single ascending path: it begins at "readable code" under your feet, rises through the habits that preserve quality (refactoring and test-driven development), and continues up to the highlands of "architecture" that overlook the whole system.
The first continent is the realm of "code quality" — variable names, functions, and responsibilities at the micro scale. Beyond it spread the hills of "testing and refactoring" for growing code without breaking it, and further on rise the mountain ranges of "clean architecture" and "domain-driven design," where you design the direction of dependencies and the boundaries between modules.
Deeper still lie the plateaus of "scale and operations" — distributed systems, data-intensive design, and DevOps/quality organizations. The key to surveying this field is recognizing that the scale of concerns connects continuously, from the micro (code) to the macro (organization and operations).
Follow the arrows to read in order / solid = required, dashed = recommended
Share this map
Grouping
Difficulty
Difficulty
Dependencies
Computing layout...
Books in this domain
33 books
Head Firstデザインパターン
頭とからだで覚えるデザインパターンの基本
Eric Freeman, Elisabeth Robson
リーダブルコード
より良いコードを書くためのシンプルで実践的なテクニック
Dustin Boswell, Trevor Foucher
LeanとDevOpsの科学[Accelerate]
テクノロジーの戦略的活用が組織変革を加速する
Nicole Forsgren, Jez Humble, Gene Kim
マイクロサービスアーキテクチャ
第2版
Sam Newman
Clean Architecture
達人に学ぶソフトウェアの構造と設計
Robert C. Martin
Clean Code
アジャイルソフトウェア達人の技
Robert C. Martin
Designing Distributed Systems
Patterns and Paradigms for Scalable, Reliable Services
Brendan Burns
Effective Software Testing
A developer's guide
Maurício Aniche
ソフトウェアアーキテクチャの基礎(第2版)
エンジニアリングに基づく体系的アプローチ
Mark Richards, Neal Ford
生成AI時代のソフトウェア開発
ツールを賢く選択、評価、活用し、より速く効率的な開発を進めるために
Sergio Pereira
ドメイン駆動設計をはじめよう
ソフトウェアの実装と事業戦略を結びつける実践技法
Vlad Khononov
達人プログラマー
熟達に向けたあなたの旅 第2版
David Thomas, Andrew Hunt
リファクタリング
既存のコードを安全に改善する 第2版
Martin Fowler
責任あるソフトウェアエンジニアリング
現実社会におけるGoogleのケーススタディとともに
Daniel Barrett, Google Engineering
テスト駆動開発
Kent Beck
チームトポロジー
価値あるソフトウェアをすばやく届ける適応型組織設計
Matthew Skelton, Manuel Pais
単体テストの考え方/使い方
Vladimir Khorikov
レガシーコード改善ガイド
Michael C. Feathers
進化的アーキテクチャ
絶え間ない変化を支える
Neal Ford, Rebecca Parsons, Patrick Kua
Building Secure and Reliable Systems
Best Practices for Designing, Implementing, and Maintaining Systems
Heather Adkins, Betsy Beyer, Paul Blankinship, Piotr Lewandowski, Ana Oprea, Adam Stubblefield
データ指向プログラミング
ソフトウェアがもつ複雑さの軽減に向けて
Yehonathan Sharvit
データ指向アプリケーションデザイン
信頼性、拡張性、保守性の高い分散システム設計の原理
Martin Kleppmann
エリック・エヴァンスのドメイン駆動設計
Eric Evans
フルスタックテスティング
10のテスト手法で実践する高品質ソフトウェア開発
Gayathri Mohan
オブジェクト指向における再利用のためのデザインパターン
Erich Gamma, Richard Helm, Ralph Johnson, John Vlissides
実践テスト駆動開発
テストに導かれてオブジェクト指向ソフトウェアを育てる
Steve Freeman, Nat Pryce
LEADING QUALITY
優れたリーダーはいかにして高品質のソフトウェアを提供し成長を加速させるか
Ronald Cummings-John, Owais Peer
モノリスからマイクロサービスへ
モノリスを進化させる実践移行ガイド
Sam Newman
エンタープライズ アプリケーションアーキテクチャパターン
Patterns of Enterprise Application Architecture
Martin Fowler
A Philosophy of Software Design, 2nd Edition
John Ousterhout
実践プロパティベーステスト
PropErとErlang/Elixirではじめよう
Fred Hebert
ソフトウェアアーキテクチャ・ハードパーツ
分散アーキテクチャのためのトレードオフ分析
Neal Ford, Mark Richards, Pramod Sadalage, Zhamak Dehghani
Googleのソフトウェアエンジニアリング
持続可能なプログラミングを支える技術、文化、プロセス
Titus Winters, Tom Manshreck, Hyrum Wright
Dependencies
Reason: After learning DevOps culture and practices in 'The DevOps Handbook', move to a concrete example of how a hyperscale organization operates them over the long term. 'Software Engineering at Google' frames engineering as 'programming integrated over time', offering insight into large-scale, long-lived engineering culture as a cross-domain bridge.
Reason: Once you've established a JavaScript testing strategy, you broaden your view beyond the frontend to whole-system quality optimization including CI/CD. Full Stack Testing provides a quality strategy spanning contract, performance, security, and E2E, positioning testing as part of development culture.
Reason: Grasp the idea of splitting the frontend into independent parts, and you notice it shares the same roots as backend microservices. Building Microservices provides the server-side framework of boundaries, autonomous deployment, and alignment with organization, letting you understand the principles of decomposition from both sides.
Reason: Once you know what good code looks like, you need techniques to safely move existing code toward that standard. Refactoring offers a systematic way to improve structure without changing behavior, guided by code smells.
Reason: To keep writing clean code, you need a foundation that lets you change it without fear. Test-driven development instills the discipline of growing clean, working code in small cycles, turning quality into a habit.
Reason: Once quality at the function and class level is second nature, the next step is to design the direction of dependencies and boundaries across the whole system. Clean Architecture provides the principle of pushing details outward and keeping business rules at the core.
Reason: After grasping patterns intuitively through illustrations and examples, you solidify the vocabulary with the original text, where intent, applicability, and consequences are rigorously defined. The Gang of Four codifies patterns into a shared design language that grounds discussion.
Reason: Once the small TDD cycle makes writing working tests second nature, you advance to principles of what and at what granularity to test. Good tests are resistant to refactoring, do not get in its way, and reliably catch regressions.
Reason: After getting comfortable with unit-level TDD, you move to outside-in TDD—driving from acceptance tests down to units—to design the collaboration between objects itself. Mocks become a tool for expressing collaboration, not just a stand-in for implementations.
Reason: Once safe refactoring moves are in hand, you take on the hardest case: legacy code without tests. You first find seams to break dependencies, cover them with tests as a safety net, and only then improve the structure.
Sources
Reason: After gaining an intuition for the ideal shape from Clean Architecture, you formalize architectural characteristics and trade-offs into a shared vocabulary. This book elevates design judgment from personal instinct to a discipline you can reason about.
Reason: Once you can control the direction of dependencies, the next question becomes where to draw the boundaries. Domain-Driven Design derives bounded contexts from the language of the business, giving architectural decomposition real meaning.
Reason: Once you have a vocabulary of architectural characteristics and trade-offs, you apply that judgment to the concrete case of distributed systems. Microservices demand a design that deliberately breaks coupling in exchange for independent deployment and autonomy.
Reason: After grasping the fundamental characteristics, you advance to trade-off analysis in the hard parts that have no single right answer—service granularity, data ownership, distributed transactions. The same authors show not the answer but how to decide.
Reason: After learning static architectural decisions, you widen your view to designs that keep adapting to change. You gain the idea of using fitness functions to continuously verify architectural characteristics, making evolution measurable.
Reason: After mapping the strategic and tactical landscape with an introductory text, you verify the origin and precise definitions of the concepts in the source. Evans' DDD grounds the ubiquitous language and model-driven design, forming the foundation for applied judgment.
Reason: Once you understand microservice principles, you advance to realistic strategies for migrating from an existing monolith. Most successes peel services off a monolith incrementally, so you also learn when not to distribute from the start.
Reason: Once you split services, the next hard problem becomes the distribution, consistency, and reliability of data. DDIA systematically provides the foundational theory and trade-offs of distributed data systems—replication, partitioning, and transactions.
Reason: After grasping the principles of good tests, you apply them to legacy code that resists testing. You introduce seams to break dependencies and pin current behavior with characterization tests before changing it safely.
Reason: Once you can judge the quality of an individual test, you extend to a design approach that grows object responsibilities and collaboration through tests. Choosing the right test double becomes feedback on the design itself.
Reason: Once you have the principles of dependencies and boundaries, you descend to the universal question beneath them: how to contain complexity. Ousterhout systematizes complexity management through the lens of deep modules and information hiding.
Reason: Once you have tactical means of improvement, you raise your view to the strategic question of why—the nature of complexity itself. A new criterion enters your refactoring decisions: does this actually reduce complexity?
Reason: After grasping the qualities of good tests—protection against regressions, resistance to refactoring, fast feedback—you raise the question of what to test with systematic techniques like boundary analysis, equivalence partitioning, and structural testing. Case selection moves from intuition to engineering.
Reason: Once example-based testing techniques are in hand, you advance to property-based testing, which generates inputs broadly and verifies invariants. You let the machine find counterexamples a human would miss and expose gaps in the spec.
Reason: Once unit tests form a solid base, you stack integration, contract, and end-to-end tests in the right proportions along the test pyramid, scaling up to a system-wide quality strategy. The rule is many at the bottom, few at the top.
Reason: Once testing and CI/CD give you a foundation for building in quality, you frame how it affects organizational delivery performance through measurement. DORA's four key metrics show empirically that speed and stability are not a trade-off.
Reason: Once you can improve delivery performance through measurement, you widen your view to the engineering culture and practices that sustain it at scale and over time. Google frames this as 'programming integrated over time.'
Reason: After understanding the engineering practices of large organizations, you advance to a leadership view that raises quality from individual effort to a culture the organization cultivates. Quality becomes a strategic concern of management.
Reason: Once you have a technical quality strategy in hand, you widen your view to how to embed it at the team and organizational level. The subject shifts from the quantity and kinds of tests to decision-making and culture around quality.
Reason: Once you can design technical boundaries, you widen your view to the fact that those boundaries and team structure shape each other—Conway's Law. Architecture is not only a code problem but an organizational one.
Reason: After designing team boundaries for fast flow, you back those boundaries with the language of the business domain. A bounded context defines the outline of both the team and the model at once.
Reason: As you carve out services, the question becomes whether the unit of decomposition matches the cognitive load of a team. The inverse Conway maneuver reorganizes teams to fit the architecture you want.
Reason: Once you have the idea of guiding evolution with fitness functions, you advance to concrete analysis of the hard parts of distributed architecture—granularity, data ownership, and communication trade-offs—from the same authors.
Reason: After practicing how to grow design through tests, you raise the sufficiency of the test cases themselves with systematic techniques. You turn both wheels—good design and thorough cases—to reduce gaps in testing.
Reason: Once you have universal principles for containing complexity, you apply them specifically to the complexity of the domain. DDD tames the essential complexity inherent in the business through a model and a ubiquitous language.
Reason: Once you have quality standards at the code level, you point that expressiveness toward the language of the domain. Meaningful names become a ubiquitous language that bridges business and code, making the model speakable in code.
Reason: The principles of dependency direction and boundaries apply directly to designing service boundaries. You connect them to concrete decisions that map bounded responsibilities onto independently deployable units.
Reason: The principles of test design carry over to the frontend. Building on the test pyramid, you cover the essentials of the UI with a few end-to-end tests and protect logic densely with unit tests—the criteria stay the same across layers.
Reason: After grasping the basics of readability such as naming and function decomposition, you move on to binding them into principles of why. Clean Code connects individual techniques into a coherent system of craftsmanship and design principles.
Reason: Once you have the concrete techniques of readability such as naming and formatting, you widen your view to the professional philosophy that runs through daily decisions—DRY, orthogonality, and a stance toward change. The Pragmatic Programmer binds individual techniques into an attitude of why.
Reason: Once you know what readable code looks like, you need techniques to move existing code toward that shape without breaking it. Refactoring offers a step-by-step way to improve structure in small moves without changing behavior, guided by code smells.
Sources
Reason: After adopting the pragmatic mindset of keeping code healthy, you ground those attitudes in concrete quality standards at the function and class level. Clean Code systematizes what good code is through principles and worked examples.
Reason: Refactoring is how the pragmatic discipline of not living with broken windows is applied to real code. It turns 'spot the decay, fix it now' into a habit of small, behavior-preserving improvements.
Sources
Reason: Once you have the principles of layering and dependency direction, you advance to the source of the canonical patterns that implement them—Repository, Service Layer, Domain Model. Mapping principles to patterns deepens your design vocabulary.
Reason: After mastering enterprise patterns that assume a single database, you widen your view to consistency, replication, and partitioning of data spread across many nodes. The assumptions of scale change.
Reason: After learning general-purpose object patterns, you advance to patterns that address enterprise-specific contexts—layering, persistence, and distribution. Fowler's PoEAA supplies that vocabulary, such as Repository and Domain Model.
Reason: Once you can recognize patterns, techniques for safely moving existing code toward the pattern it wants to be become valuable. Refactoring lets you introduce patterns not in one leap but as a sequence of incremental, safe transformations.
Sources
Reason: Once you can verify invariants, you place that skill within a quality strategy spanning unit, integration, and end-to-end. You design what property each layer guarantees, giving the whole pyramid coherence.
Reason: After learning to express a domain model with objects, you encounter the contrasting data-oriented idea of separating code from data and taming complexity with immutable data, relativizing the assumptions of your design.
Reason: Once you have general principles for managing complexity, you examine data-oriented programming as one concrete prescription—separating data from behavior and embracing immutability. The same goal admits different paths.
Reason: When you can read the structure of existing code through the lens of patterns, you can move on to building a safe foothold in untested legacy code—finding seams, covering them with tests, and improving the design from there.
Reason: After acquiring a vocabulary of class- and object-level patterns, you widen your view to governing the direction of dependencies and boundaries across the whole system. Clean Architecture pushes details outward and keeps business rules at the center.
Reason: Once you can draw bounded contexts, you map those boundaries onto team structure. Aligning contexts with teams lowers cognitive load and speeds the flow of value.
Reason: When the hard parts of distributed architecture force decisions about decomposing data, you descend to the underlying theory of distributed data. The principles of consistency, replication, and storage engines become the grounds for your design decisions.
Reason: After understanding the engineering practices of large organizations, you view how generative AI changes the flow of development with the same discipline. AI is a tool that pays off only on a foundation of review, testing, and design judgment.
Reason: Once you have the pragmatic mindset—sharpen your tools, own your judgment—you take in generative AI as a new tool. The ability to verify AI output rather than trust it blindly is the very craftsmanship of the AI era.
Reason: Once you can bring AI into development, you advance to the question of responsibility—the impact that power has on society. You take a view that weaves correctness, bias, and accountability of outputs into design from the start.
Reason: Once you can build security and reliability into a system's design, you extend that reach to responsibility toward users and society. Technical robustness becomes the foundation for fulfilling ethical and social responsibility.
Explore next
Connected fields
Domain
DevOps / SRE
A staged learning path covering DevOps culture, continuous delivery, SRE, observability, containers, and IaC — moving from narrative to implementation. Build modern operations that balance high reliability and agility across organization, process, and technology.
Domain
Frontend Development
A systematic learning path for frontend development — from JavaScript/TypeScript to React/Vue, performance optimization, and accessibility, covering component design and architecture.