software-design-philosophy

Compare original and translation side by side

🇺🇸

Original

English
🇨🇳

Translation

Chinese

A Philosophy of Software Design Framework

《软件设计的哲学》框架

A practical framework for managing the fundamental challenge of software engineering: complexity. Apply these principles when designing modules, reviewing APIs, refactoring code, or advising on architecture decisions. The central thesis is that complexity is the root cause of most software problems, and managing it requires deliberate, strategic thinking at every level of design.
这是一个应对软件工程核心挑战——复杂度的实用框架。在设计模块、评审API、重构代码或提供架构决策建议时,均可应用这些原则。核心论点是:复杂度是大多数软件问题的根源,管理复杂度需要在设计的每个层面进行审慎的、策略性的思考。

Core Principle

核心原则

The greatest limitation in writing software is our ability to understand the systems we are creating. Complexity is the enemy. It makes systems hard to understand, hard to modify, and a source of bugs. Every design decision should be evaluated by asking: "Does this increase or decrease the overall complexity of the system?" The goal is not zero complexity -- that is impossible in useful software -- but to minimize unnecessary complexity and concentrate necessary complexity where it can be managed.
编写软件的最大局限在于我们理解所创建系统的能力。 复杂度是敌人,它让系统难以理解、难以修改,还会滋生bug。每个设计决策都应通过这个问题来评估:“这会增加还是降低系统的整体复杂度?” 我们的目标不是实现零复杂度——这在实用软件中是不可能的——而是将不必要的复杂度降至最低,并将必要的复杂度集中到可管理的地方。

Scoring

评分标准

Goal: 10/10. When reviewing or creating software designs, rate them 0-10 based on adherence to the principles below. A 10/10 means deep modules with clean abstractions, excellent information hiding, strategic thinking about complexity, and comments that capture design intent. Lower scores indicate shallow modules, information leakage, tactical shortcuts, or missing design documentation. Always provide the current score and specific improvements needed to reach 10/10.
目标:10/10。 在评审或创建软件设计时,根据以下原则的遵循程度为其评分(0-10分)。10分意味着模块深度足够、抽象清晰、信息隐藏出色、对复杂度有策略性思考,且注释能准确传达设计意图。低分则表明模块浅层次、存在信息泄露、采用战术性捷径,或缺失设计文档。评分时需始终给出当前分数,以及达到10分所需的具体改进措施。

The Software Design Framework

软件设计框架

Six principles for managing complexity and producing systems that are easy to understand and modify:
六条用于管理复杂度、打造易于理解和修改的系统的原则:

1. Complexity and Its Causes

1. 复杂度及其成因

Core concept: Complexity is anything related to the structure of a software system that makes it hard to understand and modify. It manifests through three symptoms: change amplification, cognitive load, and unknown unknowns.
Why it works: By identifying the specific symptoms of complexity, developers can diagnose problems precisely rather than relying on vague notions of "messy code." The two fundamental causes -- dependencies and obscurity -- provide clear targets for design improvement.
Key insights:
  • Change amplification: a simple change requires modifications in many places
  • Cognitive load: a developer must hold too much information in mind to make a change
  • Unknown unknowns: it is not obvious what needs to be changed, or what information is relevant (the worst symptom)
  • Dependencies: code cannot be understood or modified in isolation
  • Obscurity: important information is not obvious from the code or documentation
  • Complexity is incremental -- it accumulates from hundreds of small decisions, not one big mistake
  • The "death by a thousand cuts" nature of complexity means every decision matters
Code applications:
ContextPatternExample
Change amplificationCentralize shared knowledgeExtract color constants instead of hardcoding
#ff0000
in 20 files
Cognitive loadReduce what developers must knowUse a simple
open(path)
API instead of requiring buffer size, encoding, and lock mode
Unknown unknownsMake dependencies explicitUse type systems and interfaces to surface what a change affects
Dependency managementMinimize cross-module couplingPass data through well-defined interfaces, not shared global state
Obscurity reductionName things precisely
numBytesReceived
not
n
;
retryDelayMs
not
delay
See: references/complexity-symptoms.md
核心概念: 复杂度指与软件系统结构相关、使其难以理解和修改的任何因素。它通过三种症状表现出来:变更放大、认知负荷和未知的未知。
为何有效: 通过识别复杂度的具体症状,开发者可以精准诊断问题,而非依赖“代码混乱”这类模糊的概念。复杂度的两个根本成因——依赖关系和模糊性——为设计改进提供了明确的目标。
关键见解:
  • 变更放大:一个简单的变更需要在多个地方进行修改
  • 认知负荷:开发者在进行变更时,必须在脑中记住大量信息
  • 未知的未知:不清楚需要修改什么,也不知道哪些信息是相关的(最严重的症状)
  • 依赖关系:代码无法独立理解或修改
  • 模糊性:重要信息无法从代码或文档中直接获取
  • 复杂度是逐步累积的——它源于数百个小决策,而非某个重大错误
  • 复杂度的“千刀万剐”特性意味着每个决策都至关重要
代码应用场景:
场景模式示例
变更放大集中共享知识提取颜色常量,而非在20个文件中硬编码
#ff0000
认知负荷减少开发者需了解的内容使用简单的
open(path)
API,而非要求开发者指定缓冲区大小、编码和锁模式
未知的未知明确依赖关系使用类型系统和接口来展示变更会影响的范围
依赖关系管理最小化跨模块耦合通过定义清晰的接口传递数据,而非使用共享全局状态
模糊性降低精准命名使用
numBytesReceived
而非
n
;使用
retryDelayMs
而非
delay
参考:references/complexity-symptoms.md

2. Deep vs Shallow Modules

2. 深度模块与浅度模块

Core concept: The best modules are deep: they provide powerful functionality behind a simple interface. Shallow modules have complex interfaces relative to the functionality they provide, adding complexity rather than reducing it.
Why it works: A module's interface represents the complexity it imposes on the rest of the system. Its implementation represents the functionality it provides. Deep modules give you a high ratio of functionality to interface complexity. The interface is the cost; the implementation is the benefit.
Key insights:
  • A module's depth = functionality provided / interface complexity imposed
  • Deep modules: simple interface, powerful implementation (Unix file I/O, garbage collectors)
  • Shallow modules: complex interface, limited implementation (Java I/O wrapper classes)
  • "Classitis": the disease of creating too many small, shallow classes
  • Each interface adds cognitive load -- more classes does not mean better design
  • The best abstractions hide significant complexity behind a few simple concepts
  • Small methods are not inherently good; depth matters more than size
Code applications:
ContextPatternExample
Deep moduleHide complexity behind simple API
file.read(path)
hides disk blocks, caching, buffering, encoding
Shallow moduleAvoid thin wrappers that just pass throughA
FileInputStream
wrapped in
BufferedInputStream
wrapped in
ObjectInputStream
Classitis cureMerge related shallow classesCombine
RequestParser
,
RequestValidator
,
RequestProcessor
into one
RequestHandler
Method depthMethods should do something substantialA
delete(key)
that handles locking, logging, cache invalidation, and rebalancing
Interface simplicityFewer parameters, fewer methods
config.get(key)
with sensible defaults, not 15 constructor parameters
See: references/deep-modules.md
核心概念: 最佳模块是深度模块:它们通过简单的接口提供强大的功能。浅度模块的接口复杂度与其提供的功能不成正比,反而会增加系统复杂度。
为何有效: 模块的接口代表了它给系统其他部分带来的复杂度,而实现则代表了它提供的功能。深度模块的功能与接口复杂度之比很高。接口是成本,实现是收益。
关键见解:
  • 模块深度 = 提供的功能 / 带来的接口复杂度
  • 深度模块:简单接口,强大实现(如Unix文件I/O、垃圾回收器)
  • 浅度模块:复杂接口,有限实现(如Java I/O包装类)
  • “类泛滥症(Classitis)”:创建过多小型浅度类的问题
  • 每个接口都会增加认知负荷——类越多并不意味着设计越好
  • 最佳抽象会通过几个简单概念隐藏大量复杂度
  • 小方法本身并非优点;深度比大小更重要
代码应用场景:
场景模式示例
深度模块通过简单API隐藏复杂度
file.read(path)
隐藏了磁盘块、缓存、缓冲、编码等细节
浅度模块避免仅做转发的薄包装避免将
FileInputStream
包装在
BufferedInputStream
再包装在
ObjectInputStream
类泛滥症解决合并相关浅度类
RequestParser
RequestValidator
RequestProcessor
合并为一个
RequestHandler
方法深度方法应实现实质性功能
delete(key)
方法负责处理锁、日志、缓存失效和重新平衡
接口简洁性更少参数,更少方法使用带有合理默认值的
config.get(key)
,而非15个构造函数参数
参考:references/deep-modules.md

3. Information Hiding and Leakage

3. 信息隐藏与信息泄露

Core concept: Each module should encapsulate knowledge that is not needed by other modules. Information leakage -- when a design decision is reflected in multiple modules -- is one of the most important red flags in software design.
Why it works: When information is hidden inside a module, changes to that knowledge require modifying only that module. When information leaks across module boundaries, changes propagate through the system. Information hiding reduces both dependencies and obscurity, the two fundamental causes of complexity.
Key insights:
  • Information hiding: embed knowledge of a design decision in a single module
  • Information leakage: the same knowledge appears in multiple modules (a red flag)
  • Temporal decomposition causes leakage: splitting code by when things happen forces shared knowledge across phases
  • Back-door leakage through data formats, protocols, or shared assumptions is the subtlest form
  • Decorators are frequent sources of leakage -- they expose the decorated interface
  • If two modules share knowledge, consider merging them or creating a new module that encapsulates the shared knowledge
Code applications:
ContextPatternExample
Information hidingEncapsulate format detailsOne module owns the HTTP parsing logic; callers get structured objects
Temporal decompositionOrganize by knowledge, not timeCombine "read config" and "apply config" into a single config module
Format leakageCentralize serializationOne module handles JSON encoding/decoding rather than spreading
json.dumps
everywhere
Protocol leakageAbstract protocol detailsA
MessageBus.send(event)
hides whether transport is HTTP, gRPC, or queue
Decorator leakageUse deep wrappers sparinglyPrefer adding buffering inside the file class over wrapping it externally
See: references/information-hiding.md
核心概念: 每个模块都应封装其他模块不需要知道的知识。信息泄露——即一个设计决策体现在多个模块中——是软件设计中最重要的预警信号之一。
为何有效: 当信息被隐藏在模块内部时,对该知识的修改只需改动这一个模块。当信息泄露到模块边界之外时,变更会在整个系统中传播。信息隐藏同时减少了依赖关系和模糊性这两个复杂度的根本成因。
关键见解:
  • 信息隐藏:将设计决策的知识嵌入单个模块
  • 信息泄露:同一知识出现在多个模块中(预警信号)
  • 时间分解会导致泄露:按事件发生时间拆分代码会迫使不同阶段共享知识
  • 通过数据格式、协议或共享假设进行的“后门”泄露是最隐蔽的形式
  • 装饰器是常见的泄露来源——它们暴露了被装饰的接口
  • 如果两个模块共享知识,考虑将它们合并,或创建一个新模块来封装共享知识
代码应用场景:
场景模式示例
信息隐藏封装格式细节由一个模块负责HTTP解析逻辑;调用者获取结构化对象
时间分解按知识组织,而非按时间将“读取配置”和“应用配置”合并到单个配置模块中
格式泄露集中序列化逻辑由一个模块处理JSON编码/解码,而非在各处散布
json.dumps
协议泄露抽象协议细节
MessageBus.send(event)
隐藏了传输方式是HTTP、gRPC还是队列
装饰器泄露谨慎使用深度包装优先在文件类内部添加缓冲功能,而非在外部包装它
参考:references/information-hiding.md

4. General-Purpose vs Special-Purpose Modules

4. 通用模块与专用模块

Core concept: Design modules that are "somewhat general-purpose": the interface should be general enough to support multiple uses without being tied to today's specific requirements, while the implementation handles current needs. Ask: "What is the simplest interface that will cover all my current needs?"
Why it works: General-purpose interfaces tend to be simpler because they eliminate special cases. They also future-proof the design since new use cases often fit the existing abstraction. However, over-generalization wastes effort and can itself introduce complexity through unnecessary abstractions.
Key insights:
  • "Somewhat general-purpose" is the sweet spot between too specific and too generic
  • The key question: "What is the simplest interface that will cover all my current needs?"
  • General-purpose interfaces are often simpler than special-purpose ones (fewer special cases)
  • Push complexity downward: modules at lower levels should handle hard cases so upper levels stay simple
  • Configuration parameters often represent failure to determine the right behavior -- each parameter is complexity pushed to the caller
  • When in doubt, implement the simpler, more general-purpose approach first
Code applications:
ContextPatternExample
API generalityDesign for the concept, not one use caseA
text.insert(position, string)
API instead of
text.addBulletPoint()
Push complexity downHandle defaults in the moduleA web server that picks reasonable buffer sizes instead of requiring callers to configure them
Reduce configurationDetermine behavior automaticallyAuto-detect file encoding instead of requiring an
encoding
parameter
Avoid over-specializationRemove use-case-specific methodsOne
store(key, value, options)
instead of
storeUser()
,
storeProduct()
,
storeOrder()
Somewhat generalGeneral interface, specific implementationA
Datastore
interface that currently backs onto PostgreSQL but does not expose SQL concepts
See: references/general-vs-special.md
核心概念: 设计“适度通用”的模块:接口应足够通用,以支持多种用途,同时不局限于当前的特定需求;而实现则专注于满足当前需求。可以问自己:“能覆盖所有当前需求的最简单接口是什么?”
为何有效: 通用接口通常更简单,因为它们消除了特殊情况。它们还能让设计面向未来,因为新的用例往往能适配现有的抽象。然而,过度通用会浪费精力,还可能通过不必要的抽象引入复杂度。
关键见解:
  • “适度通用”是过于专用和过于通用之间的平衡点
  • 关键问题:“能覆盖所有当前需求的最简单接口是什么?”
  • 通用接口通常比专用接口更简单(更少特殊情况)
  • 将复杂度向下转移:底层模块应处理复杂情况,让上层模块保持简洁
  • 配置参数通常代表未能确定正确行为——每个参数都是推给调用者的复杂度
  • 如有疑问,先实现更简单、更通用的方案
代码应用场景:
场景模式示例
API通用性针对概念设计,而非单一用例使用
text.insert(position, string)
API,而非
text.addBulletPoint()
复杂度向下转移在模块内处理默认值Web服务器自动选择合理的缓冲区大小,而非要求调用者配置
减少配置自动确定行为自动检测文件编码,而非要求传入
encoding
参数
避免过度专用移除特定用例的方法使用单个
store(key, value, options)
,而非
storeUser()
storeProduct()
storeOrder()
适度通用通用接口,专用实现
Datastore
接口当前基于PostgreSQL,但不暴露SQL概念
参考:references/general-vs-special.md

5. Comments as Design Documentation

5. 作为设计文档的注释

Core concept: Comments should describe things that are not obvious from the code. They capture design intent, abstraction rationale, and information that cannot be expressed in code. The claim that "good code is self-documenting" is a myth for anything beyond low-level implementation details.
Why it works: Code tells you what the program does, but not why it does it that way, what the design alternatives were, or what assumptions the code makes. Comments capture the designer's mental model -- the abstraction -- which is the most valuable and most perishable information in a system.
Key insights:
  • Four types: interface comments, data structure member comments, implementation comments, cross-module comments
  • Interface comments are the most important: they define the abstraction a module presents
  • Write comments first (comment-driven design) to clarify your thinking before writing code
  • "Self-documenting code" works only for low-level what; it fails for why, assumptions, and abstractions
  • Comments should describe what is not obvious -- if the code makes it clear, don't repeat it
  • Maintain comments near the code they describe; update them when the code changes
  • If a comment is hard to write, the design may be too complex
Code applications:
ContextPatternExample
Interface commentDescribe the abstraction, not the implementation"Returns the widget closest to the given position, or null if no widgets exist within the threshold distance"
Data structure commentExplain invariants and constraints"List is sorted by priority descending; ties are broken by insertion order"
Implementation commentExplain why, not what"// Use binary search here because the list is always sorted and can contain 100k+ items"
Cross-module commentLink related design decisions"// This timeout must match the retry interval in RetryPolicy.java"
Comment-driven designWrite the interface comment before the codeDraft the function's contract and behavior first, then implement
See: references/comments-as-design.md
核心概念: 注释应描述代码中不明显的内容。它们记录设计意图、抽象原理以及无法用代码表达的信息。“好代码自文档化”的说法,除了底层实现细节外,都是不成立的。
为何有效: 代码告诉你程序做了什么,但不告诉你为什么这么做、有哪些设计备选方案,或者代码基于哪些假设。注释记录了设计者的思维模型——即抽象——这是系统中最有价值也最容易丢失的信息。
关键见解:
  • 四种类型:接口注释、数据结构成员注释、实现注释、跨模块注释
  • 接口注释最重要:它们定义了模块呈现的抽象
  • 先写注释(注释驱动设计),在编写代码前理清思路
  • “自文档化代码”仅适用于底层的“是什么”,无法解释“为什么”、假设和抽象
  • 注释应描述不明显的内容——如果代码已经清晰表达,就不要重复
  • 注释应靠近其描述的代码;代码变更时同步更新注释
  • 如果注释难以撰写,说明设计可能过于复杂
代码应用场景:
场景模式示例
接口注释描述抽象,而非实现“返回最接近指定位置的widget;如果阈值范围内没有widget,则返回null”
数据结构注释解释不变量和约束“列表按优先级降序排列;优先级相同时按插入顺序排序”
实现注释解释原因,而非内容“// 此处使用二分查找,因为列表始终有序且可能包含10万+条数据”
跨模块注释关联相关设计决策“// 此超时时间必须与RetryPolicy.java中的重试间隔匹配”
注释驱动设计先写接口注释再写代码先草拟函数的契约和行为,再进行实现
参考:references/comments-as-design.md

6. Strategic vs Tactical Programming

6. 策略式编程与战术式编程

Core concept: Tactical programming focuses on getting features working quickly, accumulating complexity with each shortcut. Strategic programming invests 10-20% extra effort in good design, treating every change as an opportunity to improve the system's structure.
Why it works: Tactical programming appears faster in the short term but steadily degrades the codebase, making every future change harder. Strategic programming produces a codebase that stays easy to modify over time. The small upfront investment compounds -- systems designed strategically are faster to work with after a few months.
Key insights:
  • Tactical tornado: a developer who produces features fast but leaves wreckage behind; often celebrated short-term but destructive long-term
  • Strategic mindset: your primary job is to produce a great design that also happens to work, not working code that happens to have a design
  • The 10-20% investment: spend roughly 10-20% of development time on design improvement
  • Startups need strategic programming most -- early design shortcuts compound into crippling technical debt as the team grows
  • "Move fast and break things" culture (early Facebook) vs design-focused culture (Google) -- Google engineers were more productive on complex systems
  • Every code change is an investment opportunity: leave the code a little better than you found it
  • Refactoring is not a special event -- it is part of every feature's development
Code applications:
ContextPatternExample
Tactical trapResist quick-and-dirty fixesDon't add a boolean parameter to handle "just this one special case"
Strategic investmentImprove structure during feature workWhen adding a feature, refactor the module interface if it has become awkward
Tactical tornadoRecognize and interveneA developer who writes 2x the code but creates 3x the maintenance burden
Startup disciplineInvest in design from day oneClean module boundaries and good abstractions even under time pressure
Incremental improvementFix one design issue per PREach pull request improves at least one abstraction or eliminates one piece of complexity
Design reviewsEvaluate structure, not just correctnessCode reviews should ask "does this make the system simpler?" not just "does it work?"
See: references/strategic-programming.md
核心概念: 战术式编程专注于快速实现功能,每个捷径都会累积复杂度。策略式编程额外投入10-20%的精力用于良好设计,将每个变更都视为改进系统结构的机会。
为何有效: 战术式编程在短期内看似更快,但会持续恶化代码库,让未来的每个变更都更困难。策略式编程打造的代码库长期保持易于修改的特性。前期的小投入会产生复利效应——几个月后,策略式设计的系统会更易于开发。
关键见解:
  • 战术龙卷风:快速交付功能但留下烂摊子的开发者;短期内常被称赞,但长期具有破坏性
  • 策略式思维:你的首要工作是打造优秀的设计,而这些设计恰好能运行;而非先写出能运行的代码,再考虑设计
  • 10-20%的投入:将约10-20%的开发时间用于设计改进
  • 初创公司最需要策略式编程——早期的设计捷径会随着团队规模扩大,演变成严重的技术债务
  • “快速行动,打破常规”文化(早期Facebook)与注重设计的文化(Google)——Google工程师在复杂系统上的生产力更高
  • 每个代码变更都是投资机会:让代码比你接手时更好一点
  • 重构不是特殊事件——它是每个功能开发的一部分
代码应用场景:
场景模式示例
战术陷阱抵制快速粗糙的修复不要添加布尔参数来处理“仅此一个特殊情况”
策略式投入在功能开发时改进结构添加功能时,如果模块接口变得笨拙,就重构它
战术龙卷风识别并干预某个开发者编写的代码量是别人的2倍,但带来的维护负担是3倍
初创公司纪律从第一天起就投入设计即使时间紧张,也要保持清晰的模块边界和良好的抽象
渐进式改进每个PR修复一个设计问题每个拉取请求至少改进一个抽象,或消除一处复杂度
设计评审评估结构,而非仅评估正确性代码评审应问“这会降低还是增加系统复杂度?”,而非仅问“它能运行吗?”
参考:references/strategic-programming.md

Common Mistakes

常见错误

MistakeWhy It FailsFix
Creating too many small classesClassitis adds interfaces without adding depth; each class boundary is cognitive overheadMerge related shallow classes into deeper modules with simpler interfaces
Splitting modules by temporal order"Read, then process, then write" forces shared knowledge across three modulesOrganize around information: group code that shares knowledge into one module
Exposing implementation in interfacesCallers depend on internal details; changes propagate everywhereDesign interfaces around abstractions, not implementations; hide format and protocol details
Treating comments as optionalDesign intent, assumptions, and abstractions are lost; new developers guess wrongWrite interface comments first; maintain them as the code evolves
Configuration parameters for everythingEach parameter pushes a decision to the caller, increasing cognitive loadDetermine behavior automatically; provide sensible defaults; minimize required configuration
Quick-and-dirty tactical fixesEach shortcut adds a small amount of complexity; over time the system becomes unworkableInvest 10-20% extra in good design; treat every change as a design opportunity
Pass-through methodsMethods that just delegate to another method add interface without adding depthMerge the pass-through into the caller or the callee
Designing for specific use casesSpecial-purpose interfaces accumulate special cases and become bloatedAsk "what is the simplest interface that covers all current needs?"
错误失败原因修复方案
创建过多小型类类泛滥症增加了接口数量但未提升深度;每个类边界都会带来认知负担将相关的浅度类合并为接口更简单的深度模块
按时间顺序拆分模块“读取→处理→写入”的拆分迫使三个模块共享知识按知识组织:将共享知识的代码分组到单个模块中
在接口中暴露实现细节调用者依赖内部细节;变更会在整个系统中传播围绕抽象而非实现设计接口;隐藏格式和协议细节
将注释视为可选设计意图、假设和抽象丢失;新开发者会错误使用模块先写接口注释;随着代码演进同步维护注释
一切都用配置参数每个参数都将决策推给调用者,增加认知负荷自动确定行为;提供合理默认值;最小化必填配置
快速粗糙的战术修复每个捷径都会增加少量复杂度;长期来看系统会变得无法维护额外投入10-20%的精力用于良好设计;将每个变更视为设计改进的机会
转发方法仅做转发的方法增加了接口复杂度但未提升深度将转发方法合并到调用方或被调用方中
针对特定用例设计专用接口会累积特殊情况,变得臃肿问自己“能覆盖所有当前需求的最简单接口是什么?”

Quick Diagnostic

快速诊断

QuestionIf NoAction
Can you describe what each module does in one sentence?Modules are doing too much or have unclear purposeSplit into modules with coherent, describable responsibilities
Are interfaces simpler than implementations?Modules are shallow -- they leak complexity outwardRedesign to hide more; merge shallow classes into deeper ones
Can you change a module's implementation without affecting callers?Information is leaking across module boundariesIdentify leaked knowledge and encapsulate it inside one module
Do interface comments describe the abstraction, not the code?Design intent is lost; developers will misuse the moduleWrite comments that explain what the module promises, not how it works
Is design discussion part of code reviews?Reviews only catch bugs, not complexity growthAdd "does this reduce or increase system complexity?" to review criteria
Does each module hide at least one important design decision?Modules are organized around code, not around informationReorganize so each module owns a specific piece of knowledge
Can a new team member understand module boundaries without reading implementations?Abstractions are not documented or are too leakyImprove interface comments and simplify interfaces until they are self-evident
Are you spending 10-20% of time on design improvement?Technical debt is accumulating with every featureAdopt a strategic mindset; include design improvement in every PR
问题如果答案为否行动
你能用一句话描述每个模块的功能吗?模块职责过多或不明确拆分为职责清晰、可描述的模块
接口比实现更简单吗?模块是浅度模块——将复杂度泄露到外部重新设计以隐藏更多细节;将浅度类合并为深度模块
你能修改模块实现而不影响调用者吗?信息在模块边界之间泄露识别泄露的知识,将其封装到单个模块中
接口注释描述的是抽象而非代码吗?设计意图丢失;开发者会错误使用模块编写解释模块承诺的注释,而非其实现方式
设计讨论是代码评审的一部分吗?评审仅能发现bug,无法阻止复杂度增长将“这会降低还是增加系统复杂度?”加入评审标准
每个模块至少隐藏一个重要设计决策吗?模块是围绕代码而非知识组织的重新组织,让每个模块负责特定的知识领域
新团队成员无需阅读实现就能理解模块边界吗?抽象未被文档化或过于泄露改进接口注释并简化接口,直到它们不言自明
你是否将10-20%的时间用于设计改进?每个功能都会累积技术债务采用策略式思维;每个PR中包含设计改进

Reference Files

参考文件

  • complexity-symptoms.md: Three symptoms of complexity, two causes, measuring complexity, the incremental nature of complexity
  • deep-modules.md: Deep vs shallow modules, interface-to-functionality ratio, classitis, designing for depth
  • information-hiding.md: Information hiding principle, information leakage red flags, temporal decomposition, decorator pitfalls
  • general-vs-special.md: Somewhat general-purpose approach, pushing complexity down, configuration parameter antipattern
  • comments-as-design.md: Four comment types, comment-driven design, self-documenting code myth, maintaining comments
  • strategic-programming.md: Strategic vs tactical mindset, tactical tornado, investment approach, startup considerations
  • complexity-symptoms.md:复杂度的三种症状、两个成因、复杂度衡量、复杂度的渐进性
  • deep-modules.md:深度与浅度模块、功能与接口复杂度之比、类泛滥症、深度设计
  • information-hiding.md:信息隐藏原则、信息泄露预警信号、时间分解、装饰器陷阱
  • general-vs-special.md:适度通用方法、复杂度向下转移、配置参数反模式
  • comments-as-design.md:四种注释类型、注释驱动设计、自文档化代码误区、注释维护
  • strategic-programming.md:策略式与战术式思维、战术龙卷风、投入式方法、初创公司考量

Further Reading

延伸阅读

This skill is based on John Ousterhout's practical guide to software design. For the complete methodology with detailed examples:
本技能基于John Ousterhout的实用软件设计指南。如需完整方法学及详细示例:
  • John Ousterhout所著《A Philosophy of Software Design》(第二版):亚马逊链接

About the Author

关于作者

John Ousterhout is the Bosack Lerner Professor of Computer Science at Stanford University. He is the creator of the Tcl scripting language and the Tk toolkit, and co-founded several companies including Electric Cloud and Clustrix. Ousterhout has received numerous awards, including the ACM Software System Award, the UC Berkeley Distinguished Teaching Award, and the USENIX Lifetime Achievement Award. He developed A Philosophy of Software Design from his CS 190 course at Stanford, where students work on multi-phase software design projects and learn to recognize and reduce complexity. The book distills decades of experience in building systems software and teaching software design into a concise set of principles that apply across languages, paradigms, and system scales. Now in its second edition, the book has become a widely recommended resource for software engineers seeking to improve their design skills beyond correctness and into clarity.
John Ousterhout 是斯坦福大学Bosack Lerner计算机科学教授。他是Tcl脚本语言和Tk工具包的创造者,还共同创立了Electric Cloud和Clustrix等多家公司。Ousterhout获得了众多奖项,包括ACM软件系统奖、加州大学伯克利分校杰出教学奖和USENIX终身成就奖。他从斯坦福大学的CS 190课程中发展出《软件设计的哲学》,该课程中学生参与多阶段软件设计项目,学习识别和降低复杂度。这本书将他数十年构建系统软件和教授软件设计的经验提炼为一套简洁的原则,适用于各种语言、范式和系统规模。目前已出第二版,成为软件工程师提升设计技能(超越正确性,追求清晰性)的广泛推荐资源。