索引 / 001 ZH-CN
The Pragmatic Programmer: Your Journey to Mastery(程序员修炼之道:通向务实的最高境界) cover

计算机科学

计算机科学

The Pragmatic Programmer: Your Journey to Mastery(程序员修炼之道:通向务实的最高境界)

David Thomas; Andrew Hunt

英文原名: The Pragmatic Programmer: Your Journey to Mastery

一本关于高效软件开发的习惯、态度与技术的实用指南,由一系列简短而独立的主题组成。内容涉及如何编写灵活且易于维护的代码、应对变化、使用工具、测试与调试,以及在团队中对自己的工作负责。

需要的基础: 有任意一种语言的编程经验即可;不需要系统学过软件工程。

难度等级
入门
学术层次
本科
software engineeringprofessional practicesoftware designtesting编程教科书

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的地方。先做习题再看作者的答案,把挑战题当作学习小组的讨论题。把提示卡放在手边,积累一两年经验后再回来重读本书。