前言

本书介绍软件工程师经常用于编写可靠的、易于维护的代码的关键概念与技术。本书并不是简单列举“该做”和“不该做”的事项,而是旨在解释每种概念和技术背后的核心理论,以及需要权衡的因素。这应该能够帮助读者对如何像一位经验丰富的软件工程师那样思考和编程有基本的理解。

本书的读者

本书的目标读者是那些已经具备基本编程技能,想继续提高编程技能的人。本书适合有0~3年软件工程师工作经验的人阅读。有丰富工作经验的工程师可能发现,本书中的许多内容他们都已经掌握,但我希望他们把这本书当作指导其他同行的有用资源。

本书的组织结构

本书分为三部分,共11章。第一部分介绍较为理论性的概念,它们组成了我们对代码的思考方法。第二部分转向较为实用的经验教训。第二部分的每一章都分为一系列主题,分别涵盖特定的考虑因素或技术。第三部分介绍创建有效和可维护的单元测试的原则与方法。

本书各章节的总体形式是:先阐述一个可能有问题的场景(以及部分代码),然后说明消除部分或全部问题的替代方法。从这个意义上说,每个章节往往是从展示“坏”代码过渡到“好”代码,但需要注意的是,是主观的说法,与语境相关。正如本书所要强调的,在编程工作中往往要考虑一些微妙的差别和权衡,这也就意味着好坏的区别并不总是一目了然。

第一部分“理论”为一些总体性和较为理论性的考虑因素打下基础。这些考虑因素组成我们像软件工程师那样编写代码的方法。

第1章介绍代码质量的概念,特别是我们打算用高质量代码要实现的一组实际目标。然后,我们将这些目标展开为“代码质量的六大支柱”,为日常编程使用提供高层策略。

第2章讨论抽象层次。这是指导我们如何构造代码,并将其分解为不同部分的基本考虑因素。

第3章强调考虑必须使用我们的代码开展工作的其他工程师的重要性。本章还将讨论代码契约,以及如何仔细考虑这些契约以防止软件缺陷。

第4章讨论软件错误,并阐释为何认真思考错误通知与处理方法是编写优良代码的关键部分。

第二部分“实践”以更贴合实践的方式,用特定的技术与示例介绍代码质量的前五大支柱(第1章定义的)。

第5章介绍提高代码可读性的方法。这能确保其他工程师理解代码的意义。

第6章介绍避免意外情况的方法。这能确保其他工程师不会误解代码的功能,从而最大限度地降低出现缺陷的可能性。

第7章介绍使代码不容易被误用的方法。这使得工程师不容易在不经意间编写出逻辑错误或者违反假设的代码,最大限度地降低出现缺陷的可能性。

第8章介绍实现代码模块化的方法。这种关键技术有助于确保代码表现出清晰的抽象层次,能够适应不断变化的需求。

第9章介绍代码的重用性和可推广性。这能避免软件工程师重复编写类似代码,使得添加新功能或构建新特性更加方便、安全。

第三部分“单元测试”介绍编写高效单元测试的关键原则和实用方法。

第10章介绍影响单元测试代码的一些原则和考虑因素。

第11章以第10章介绍的原则为基础,为编写单元测试提供一系列具体、实用的建议。

阅读本书的理想方式是从头到尾完整阅读,因为本书前面的章节是后续章节的基础。尽管如此,第二部分(以及第11章)中的主题通常相对独立,而且每个主题篇幅较小,因此,即使单独阅读,也是有益处的。这样的编写方式是有意为之,目的是提供向其他工程师快速解释既定优秀实践的有效手段。对希望在代码评审中解释特定概念或指导其他工程师的工程师来说,这是非常有用的。

关于代码

本书的目标读者是使用静态类型、面向对象编程语言,例如Java、C#、TypeScript、JavaScript(ECMAScript 2015或有静态类型检查器的更新版本)、C++、Swift、Kotlin、Dart 2或类似语言的工程师。在使用类似语言编程时,本书涵盖的概念有广泛的适用性。

不同编程语言表达逻辑与代码结构的语法与范式也不同。但为了在本书中提供代码示例,必须标准化某些语法和范式。为此,本书借鉴了不同编程语言的伪代码。使用伪代码的目的是为大多数工程师提供明确、清晰且易于理解的信息。请牢记这一实用的意图,本书的目的不是说明某种编程语言的优劣。

同样,当我们需要在无歧义与简洁之间做出权衡的时候,伪代码的例子倾向于无歧义这一方面。这方面的例子之一是使用明确的变量类型,而不是使用var之类关键字的推断类型。另一个例子是用if语句处理空值,而不是更简洁(但或许更不熟悉)的空值合并和空值条件运算符(参见附录B)。在真实的代码库中(本书的语境之外),工程师可能更希望强调简洁性。

如何运用本书中的建议

在阅读任何关于软件工程的书籍或文章时,一定要记住这是主观的论题,并且对现实问题的解决方案通常不是完全明晰的。按照我的经验,优秀的工程师总是带着健康的怀疑心态去阅读任何文章,并渴望理解其中的基本思路。人们的观点各不相同且不断发展,同时可用的工具和编程语言也在不断改进。想要知道在何时运用特定建议、何时忽略它们,就必须理解它们的缘由、背景以及限制范围。

本书旨在收集一系列有用的主题和技术,以引导工程师写出更好的代码。尽管考虑这些主题和技术或许是明智之举,但不应该将其看成绝对正确的理论,或者将其作为绝不能破坏的硬性规则。良好的判断力是优秀工程师必不可少的特征。

延伸阅读

本书旨在成为软件工程师进入编程世界的敲门砖。它应该能够帮助读者大致了解代码的相关思维方式、可能出现的问题以及避免这些问题的技术。但我们的旅程不应该止于此,软件工程是一个庞大且不断发展的领域,博览群书并跟上最新发展是可取的做法。除阅读文章和博客之外,下面这些相关书籍也可能对读者有帮助:

Refactoring: Improving the Design of Existing Code[1], second edition, Martin Fowler (Addison- Wesley, 2019);


[1] 本书中文版《重构:改善既有代码的设计(第2版)》已由人民邮电出版社引进出版,ISBN:978-7-115- 50865-2。

Clean Code: A Handbook of Agile Software Craftsmanship[2], Robert C. Martin (Prentice Hall, 2008);


[2] 本书中文版《代码整洁之道》已由人民邮电出版社引进出版,ISBN:978-7-115-21687-8。

Code Complete: A Practical Handbook of Software Construction, second edition, Steve McConnell (Microsoft Press, 2004);

The Pragmatic Programmer: Your Journey to Mastery, 20th anniversary, second edition, David Thomas and Andrew Hunt (Addison-Wesley, 2019);

Design Patterns: Elements of Reusable Object-Oriented Software, Erich Gamma, Richard Helm, Ralph Johnson, and John Vlissides (Addison-Wesley, 1994);

Effective Java, third edition, Joshua Bloch (Addison-Wesley, 2017);

Unit Testing: Principles, Practices and Patterns, Vladimir Khorikov (Manning Publications, 2020)。

致谢

写书并非单打独斗,我要感谢每一位为本书的出版提供帮助的人。特别感谢我的开发编辑Toni Arritola在整个写作过程中的耐心指导,以及她对读者和高质量教学始终如一的关注。我还要感谢策划编辑Andrew Waldron从一开始就相信本书介绍的理念。他在出版过程中提出了许多宝贵意见。感谢我的技术开发编辑Michael Jensen在技术方面的洞察力,以及对全书各章节提供的建议。感谢我的技术校对Chris Villanueva仔细审查本书的代码和技术内容,并感谢他给出的出色建议。

我还要感谢所有的审稿人员——Amrah Umudlu、Chris Villanueva、David Racey、George Thomas、Giri Swaminathan、Harrison Maseko、Hawley Waldman、Heather Ward、Henry Lin、Jason Taylor、Jeff Neumann、Joe Ivans、Joshua Sandeman、Koushik Vikram、Marcel van den Brink、Sebastian Larsson、Sebastián Palma、Sruti S、Charlie Reams、Eugenio Marchiori、Jing Tang、Andrei Molchanov和Satyaki Upadhyay——在出版的各个阶段花时间阅读本书,并提供了准确、可付诸行动的反馈。对这些反馈的重要性和实用性如何夸大都不过分。

本书涉及的绝大多数概念是软件工程领域享有盛誉的理念与技术,因此最后我要向多年来所有对这些知识做出贡献、分享成果的人表示感谢。