## 嘉宾背景 John Ousterhout是一位独特的计算机科学家,既有深厚的学术背景,也有丰富的工业界经验。他曾在伯克利任教14年,后转入工业界创办公司,再回到斯坦福任教。他创造了TCL脚本语言,发明了Raft一致性算法(被MongoDB、CockroachDB、Kafka等广泛使用),并著有《软件设计的哲学》一书。 ## 核心观点与洞察 ### 1. 学术界与工业界的差异 **相似之处**: - 都是与小团队合作 - 都在尝试做相对新颖的事情 - 都致力于构建真正有用的软件 **关键差异**: - 工业界有巨大的营销压力,需要让自己看起来比实际更好 - 学术界可以诚实地说"这个项目失败了,让我们继续下一个" - 工业界需要面对更广泛的人群(销售、市场、投资人等) ### 2. 战术龙卷风现象 **定义**:战术龙卷风是指那些能快速产出代码的多产程序员,但采用完全战术性的方式工作。 **特征**: - 实现快速功能时无人能及 - 不关心留下的技术债务 - 被某些管理层视为英雄 - 实际上给其他工程师留下需要清理的混乱 **根本原因**: - 特定的个性类型 - 组织过分重视速度(特别是初创公司) - 缺乏长期思维 ### 3. AI对软件工程的影响 **相对确定的趋势**: - AI工具将使底层代码生成变得更容易 - 自动补全将变得更好,可能产生相当高质量的代码 **不确定的领域**: - AI工具在多大程度上能替代高层设计任务 **关键洞察**: - 随着AI处理越来越多的底层编程任务,软件设计师的工作将越来越聚焦于设计 - 软件设计将变得更加重要,占开发者时间的比重越来越大 - 这使得大学不教授软件设计变得更加令人遗憾 ### 4. 软件设计的本质 **核心定义**:软件设计是一个分解问题——如何将大型复杂系统划分为可以相对独立实现的较小单元。 **设计方法**: - **自上而下**:从顶层开始,将系统分解为相对独立的组件 - **自下而上**:从具体功能开始,逐步构建整体架构 - **实际过程**:两种方法的迭代结合,在大部件和小部件之间来回思考 ### 5. 管理复杂性的两种方法 1. **消除复杂性**:通过设计完全消除某些复杂性(最强大的方法) 2. **隐藏复杂性**:使用模块化设计,将复杂性封装起来,使其他人不需要意识到这种复杂性 ### 6. 设计两次的重要性 **观察**:聪明的人往往坚持实现第一个想法,这会限制他们的真正潜力。 **原因**: - 许多顶尖学生一生中一切都很容易 - 第一个想法总是足够好,从未有动机去思考第二遍 - 当面对真正困难的问题时,第一个想法往往不是最好的 **实践方法**: - 强制自己考虑至少两种方法 - 即使认为其中一种很糟糕,也要进行比较 - 这个过程通常只占总时间的1-2%,但能带来巨大回报 ### 7. 深度模块 vs 浅层模块 **深度模块**: - 提供简单的接口 - 内部有大量功能和复杂性 - 为用户提供巨大的认知负担减轻 - 是对抗复杂性的有力工具 **浅层模块**: - 宽接口但功能有限 - 可能几乎是透明的,没有太多隐藏 - 增加系统复杂性而非减少 **设计目标**:以最简单的接口获得最多的功能。 ### 8. 错误处理的设计原则 **核心观点**:异常处理是复杂性的巨大来源。 **设计原则**: - 更多异常并不意味着更好的编程 - 每个异常都给类的用户增加复杂性 - 通过轻微的设计变更,整类错误可以完全消失 - 从调用者角度思考异常设计 **重要警告**:这个原则容易被误解,不是忽略错误,而是通过设计消除错误的可能性。 ### 9. 设计中的同理心 **关键能力**:能够改变思维模式,从不同角度思考问题。 **具体应用**: - 设计模块时考虑内部细节 - 使用模块时完全忘记内部细节,只使用接口 - 这种思维转换能力在社会环境中同样有价值 ### 10. 与Clean Code的分歧 #### 关于短方法 **Robert Martin观点**:方法应该尽可能短,做一件事。 **Ousterhout观点**: - 设计是关于权衡的 - 过度追求短方法会导致过多接口,增加系统复杂性 - 深度概念更重要:大量功能+简单接口 - 如果方法紧密耦合,最好将它们组合在一起 #### 关于测试驱动开发(TDD) **反对理由**: - TDD与设计背道而驰 - 鼓励小增量设计而非整体思考 - 没有鼓励退后思考整体架构的环节 - 导致战术性开发风格 - 推向专门化而非通用化解决方案 **替代建议**:以抽象为开发单元,而非单个测试。 #### 关于注释 **Clean Code观点**:代码应该自我解释,尽可能少的注释。 **Ousterhout观点**: - 代码永远无法完全自我解释 - 注释应该提供代码中不明显的信息 - 接口是最需要注释的地方 - 类成员变量需要详尽文档 - 方法内部通常不需要太多注释 ### 11. 设计评审的价值 **实践方法**: - 相对非正式的设计讨论 - 多个头脑思考同一个主题显然比一个人更好 - 在分析瘫痪和充分设计之间找到平衡 **白板技巧**(解决复杂争议): 1. 列出所有支持和反对的论点 2. 任何人都可以提出论点,不能被删除 3. 不允许重复已有论点 4. 最后进行无记名投票 5. 通常会得到令人震惊的一致结果 ### 12. 设计的时机 **个人观点**:设计贯穿整个开发过程 - 前期设计 - 编码时设计 - 测试时设计 - 修复bug时设计 **建议**: - 总是做一些前期设计(不是瀑布模型) - 有一些假设来指导工作 - 准备好在发现问题时修改设计 - 唯一不做设计就编码的情况:过于年轻和缺乏经验 ### 13. 当前项目:Linux内核中的Homa协议 John正在将学生Ben Montazeri的PhD研究成果Homa传输协议引入Linux内核。 **性能优势**:在许多有趣的情况下比TCP快10-100倍。 **上游过程**: - 已提交补丁6个月 - Linux内核开发者反馈质量很高 - 过程比预期更合理 - 通过代码审查显著改进了Homa ### 14. 教学方法:斯坦福软件设计课程 **教学模式**:基于高中英语写作课的模式 - 学生完成项目 - 接受广泛代码审查 - 重写项目整合反馈 - 通过重做过程真正内化概念 **项目安排**: - 三个阶段,构建重要功能 - 前两个项目是Raft一致性协议 - 每个团队获得50-100条详细反馈 - 第二轮项目质量显著提升 **效果**: - 学生思考软件的方式发生根本改变 - 毕业后在公司中表现出比同级工程师更强的设计意识 ### 15. 通用化vs专门化 **重要原则**:推动自己朝着通用化方向发展,尽可能避免专门化。 **应用**: - 寻找能解决多个问题的通用解决方案 - 避免为每个测试创建专门化解决方案 - 这是区分优秀设计师的关键因素之一 ## 书籍推荐与资源 **《软件设计的哲学》第二版**: - 更加强调通用化和消除专门化 - 需要特别注意异常处理章节的正确理解 - 作者主页有额外的推荐资源 ## 结语 这次访谈深入探讨了软件设计的核心原则和实践方法。John Ousterhout强调,随着AI工具处理越来越多的底层编程任务,软件设计将变得更加重要。他的核心理念——管理复杂性、深度模块、设计两次、通用化解决方案——为软件工程师提供了宝贵的指导原则。 特别值得注意的是,他对当前流行的一些软件工程实践(如TDD、过度简短的方法、避免注释)提出了深思熟虑的挑战,这些观点值得每个软件工程师认真考虑和讨论。 ## 来源引用 [The Philosophy of Software Design – with John Ousterhout](https://www.youtube.com/watch?v=lz451zUlF-k)