读书笔记:软件设计的哲学
A Philosophy of Software Design
- 是什么(What):
- 以
降低复杂度为核心的软件设计方法论,讨论如何通过模块划分、接口设计、信息隐藏和注释构建易理解、易修改的系统。
- 以
- 为什么(Why):
- 能工作的代码并不等于设计良好的代码;复杂度会在持续迭代中以依赖和模糊性的形式累积,使每次修改都更慢、更危险。
- 怎么做(How):
- 设计深模块和简单接口,把复杂度与决策封装在实现内部;明确职责与抽象层次,减少透传、配置和特殊情况,并通过比较多个方案持续改善设计。
核心观点:
复杂度通常不会凭空消失,而是在不同模块、不同角色之间重新分配;优秀设计会先明确系统职责与接口能力,再尽量把复杂度留在实现内部,而不是转嫁给接口使用者。
- 软件设计的首要目标不是尽快把功能写出来,而是持续降低系统复杂度。
- 好的设计应当把复杂度消灭在模块内部,用简单接口隐藏复杂实现,让未来的修改更小、更稳、更容易理解。
- 复杂度一旦以依赖和模糊性的形式扩散出去,后续所有开发都会持续为今天的捷径付利息。
启发点(关键洞察):
- 复杂度不是"代码变多"本身,而是小改动要改很多地方、读代码必须记住很多隐含前提、以及你甚至不知道风险藏在哪。
- 深模块比浅模块更有价值。接口应尽量简单,但模块内部可以承担足够多的实现复杂度。
- 设计接口之前,先定义模块职责:这个系统边界内到底该负责什么、不该负责什么;接口能力应服务于职责,而不是把未想清楚的决策暴露给外部。
- 信息隐藏的重点不是"藏得越多越好",而是隐藏不重要的实现细节,同时把真正重要的约束和语义说清楚。
- 相邻层必须提供不同层级的抽象;如果只是原样透传参数和语义,这一层大概率没有设计价值。
- 很多配置项、布尔开关和异常分支,本质上是在把设计问题转嫁给调用方。能内部消化的复杂度,尽量不要上抛。
- 好的注释不是复述代码,而是补充代码本身无法清楚表达的设计意图、边界条件和接口契约。
- 重要设计至少想两个方案。第一反应通常只是"先想到的方案",未必是复杂度最低的方案。
- 修改旧代码时,不应只打补丁,而要顺手把结构往"如果一开始就知道这个需求,会怎么设计"那个方向推近一点。
行动:
- 以后做设计评审时,先问一句:这次改动是在消除复杂度,还是把复杂度转移给别人。
- 写接口前先写一句注释,逼自己先说明职责、输入输出、约束和失败语义。
- 遇到 pass-through wrapper、层层透传参数、满天飞布尔参数时,优先考虑是否该重构抽象边界。
- 新增配置项和错误分支前先判断:它是否真的需要交给调用方决策,还是应该在模块内部给出默认策略。
- 拆分类或拆函数时,不再机械追求短小,而是以"是否形成更深的抽象、是否减少认知负担"为判断标准。
- 对关键模块尝试至少两个设计方案,再比较接口复杂度、信息隐藏程度和未来演进成本。
金句:
- The most fundamental problem in computer science is problem decomposition: how to take a complex problem and divide it up into pieces that can be solved independently.
- Complexity is anything related to the structure of a software system that makes it hard to understand and modify the system.
- The best modules are those that provide powerful functionality yet have simple interfaces.
- Working code isn't enough.
- Modules should be deep.
评论