01 / 导读
导读
引用
Thomas, D., & Hunt, A. (2019). The Pragmatic Programmer: Your Journey to Mastery (20th anniversary ed., 2nd ed.). Addison-Wesley.
章节概要
本书由五十三个简短、独立的"话题"组成,分为九章,另附后记、参考书目以及作者给出的习题参考答案。主要建议由带编号的"提示"承载,这些提示在正文中以方框标出,并汇总在一张可抽出的卡片上;许多话题以习题(答案相对明确)和开放式的"挑战"结尾,相关话题之间有交叉引用。序言说明这些话题可以按任意顺序阅读。据作者介绍,本版约三分之一的话题是新写的,其余大部分也经过改写;并发部分作了重组,资源附录被删除,新增内容反映了敏捷实践、函数式编程惯用法以及隐私与安全。代码示例使用多种语言,包括Ruby、Python和Java。
第1章:A Pragmatic Philosophy(务实的哲学)
阐述贯穿全书的态度:为自己的职业和错误负责("The Cat Ate My Source Code")、抵御软件熵、推动变化("Stone Soup and Boiled Frogs")、判断软件何时"足够好"、投资于知识组合,以及有效沟通。
第2章:A Pragmatic Approach(务实的方法)
讨论一般性的设计原则:好设计的本质、DRY(避免的不只是代码重复,而是知识和意图的重复,适用于文档、数据和API,也适用于程序)、正交性、可逆性、曳光弹、原型、领域语言和估算。
第3章:The Basic Tools(基本工具)
纯文本、命令行shell、熟练使用编辑器、版本控制、调试、文本处理语言,以及记工程日志。
第4章:Pragmatic Paranoia(务实的偏执)
面向不完美软件的防御性做法:契约式设计、让出错的程序停下来("Dead Programs Tell No Lies")、断言、资源平衡,以及小步前进而不去预测遥远的未来("Don't Outrun Your Headlights")。
第5章:Bend, or Break(宁弯不折)
保持代码的灵活性:解耦、应对现实世界中的事件、把程序看作数据的变换、继承的代价("Inheritance Tax",建议改用接口、委托和混入),以及把配置移出代码。
第6章:Concurrency(并发)
本版重写的一章,涵盖打破时间耦合、共享状态的危险("Shared State Is Incorrect State")、参与者与进程,以及黑板。
第7章:While You Are Coding(编码时)
编程过程中的习惯:倾听直觉、避免"靠巧合编程"、算法速度、重构、测试("Test to Code")、基于属性的测试、安全("Stay Safe Out There")以及命名。
第8章:Before the Project(项目开始之前)
需求与项目启动:挖掘真正的需求、解决看似不可能的难题、协作,以及敏捷的本质。
第9章:Pragmatic Projects(务实的项目)
把本书的思想应用于团队和项目:务实的团队、"Coconuts Don't Cut It"、务实入门套件、取悦用户,以及为自己的工作感到自豪("Pride and Prejudice")。
核心概念
第1–2章:哲学与方法
- 软件熵:软件随时间推移而退化,本书敦促读者与之斗争。
- 知识组合:把持续学习当作一项需要定期管理的投资。
- DRY:系统中的每一项知识都必须有单一、明确、权威的表示;它适用于文档、数据和API,而不仅是代码。
- 正交性与可逆性:各组件独立设计,并让决策易于撤回。
第3–5章:工具、偏执与灵活性
- 契约式设计与断言式编程:明确并检查代码所期望和所保证的内容。
- 小步前进:只迈出能看到结果的步子,而不是为无法预知的未来做设计。
- 继承税:继承造成的耦合,以及改用接口、委托和混入的理由。
第6–7章:并发与编码
- 共享状态就是错误状态:对共享资源的并发访问需要独占访问或事务;随机出现的故障往往意味着并发问题。
- 靠巧合编程:依赖碰巧能运行的代码,本书告诫读者不要这样做。
- 基于属性的测试:用自动生成的输入检验代码的一般性质。
第8–9章:项目与团队
- 需求陷阱:了解用户真正需要什么的困难,出版社将其概括为"了解真正的需求"。
- 务实入门套件:作者建议每个项目都应建立的基本实践。
评析
优点
- 简短、独立的话题。 每个话题自成一体并有交叉引用,因此可以按任意顺序阅读,也可以配合课程项目逐个布置。
- 全面更新。 序言称约三分之一的话题是新的,其余大部分也经过改写;出版社说新增了十节,目录中也能看到基于属性的测试、安全、参与者模型和工程日志等当下的主题。
- 内置练习。 书中有附参考答案的习题和开放式挑战,作者建议在高级程序设计课程中把挑战用于小组讨论或写作;出版社还列出了面向课堂的教师资料和习题集。
- 不依赖语言的建议与具体代码。 原则以一般性的语言表述,代码示例简短,并使用多种语言。
局限
- 重广度而轻深度。 约300页中有五十三个话题,每个主题只有几页;并发、测试、需求和架构都需要在别处得到更充分的讲解。
- 是建议而非方法。 本书提供的是提示和故事,而不是系统化的流程或实证依据;作者自己也请读者自行判断某些建议是否错误。
- 有一定经验后才最有用。 许多话题假定读者与他人合作写过代码、用过版本控制,并遇到过重复或不稳定的并发等问题;完全的新手可能会觉得部分建议较为抽象。
在课程中的定位
在软件工程这门课的书单中,本书是关于个人开发者习惯的、覆盖面最广的一本。它天然的搭档是 Ousterhout 的 A Philosophy of Software Design:后者深入探讨一个问题,即通过模块设计来管理复杂性,而 Thomas 与 Hunt 则用短小的篇章概览设计、工具、测试、并发和团队合作。把DRY、正交性和继承这几个话题与 Ousterhout 关于深模块和信息隐藏的章节对照阅读,可以看出两者的一致与分歧。
Sommerville 的 Software Engineering 提供本书只是略有涉及的系统化生命周期视角(需求、过程、验证);Software Engineering at Google 在组织规模上展示同样的关切;Bass、Clements 与 Kazman 的 Software Architecture in Practice 以及 Jackson 的 Software Abstractions 则在架构和形式化建模方面走得更远。本书最好尽早阅读,在第一个较大的项目期间读,以后再回头重读。
如何使用本书
出版社把本书的读者定为新手程序员、有经验的程序员以及负责软件项目的管理者。有任何一种语言的编程经验就足够,不需要软件工程背景。
- 核心: 第1–2章(哲学与方法)和第7章(编码时)。
- 项目进行中: 讲工具的第3章和讲防御性编程的第4章,然后是介绍务实入门套件的第9章。
- 按需阅读: 代码难以修改时读第5章,遇到并发时读第6章,在有真实用户的项目开始时读第8章。
每周读一两个话题,并在自己的工作中付诸实践:开始写工程日志,把一个构建步骤自动化,或在自己的代码中找出一处违反DRY的地方。先做习题再看作者的答案,把挑战题当作学习小组的讨论题。把提示卡放在手边,积累一两年经验后再回来重读本书。
