第 1 章 为什么说 "优秀的 PHP 开发人员" 不是一个贬义词?

回到 2010 年,MailChimp 在其博客上发表了一篇题为《Ewww,你还用PHP?》的文章。在这篇博客文章中,他们描述了在向那些认为 “优秀的PHP程序员” 这个短语是矛盾的开发者解释他们选择PHP时的恐怖。他们辩解说他们的 PHP 不是那种古老的 PHP,而是他们使用了一种尖端的框架。我倾向于根据 PHP 的功能、安全性以及架构来判断 PHP 的质量。这本书关注的是你应该如何设计你的代码。软件的架构允许开发人员以无错误和优雅的方式轻松地扩展代码超出其原始目的。

任何傻瓜都能写出计算机能理解的代码。好的程序员写出的代码人类可以理解。
— 马丁-福勒

这不仅限于代码风格,还包括开发人员如何架构和构造他们的代码。我曾遇到过许多开发人员,他们总是把自己的鼻子塞在文档里,复制和粘贴代码片段,直到能用为止;把代码片段拼凑在一起,直到能用为止。此外,我经常看到软件开发过程迅速恶化,因为开发人员越来越紧密地将他们的类与越来越长的函数结合在一起。

软件工程师不仅要编写软件代码,还必须懂得如何设计软件。事实上,一个优秀的软件工程师在面试其他软件工程师时,往往会问一些关于代码设计本身的问题。要得到一段能执行的代码是很琐碎的,询问开发人员函数的正确名称是 strtolower 还是 str2lower 也是善意的(顺便说一下,是 strtolower)。知道类和对象之间的区别并不能说明你就是一个合格的开发人员;例如,一个更好的面试问题应该是,你如何将子类型多态性应用到实际的软件开发挑战中。如果不对软件设计技能进行评测,就会使面试变得乏味,无法区分哪些人擅长设计,哪些人不擅长设计。这些高级话题将在本书中讨论,通过学习这些策略,你将更好地理解在讨论软件架构时应该问哪些正确的问题。

软件工程师不能只写代码;他们必须知道如何设计它。事实上,一个优秀的软件工程师在面试其他软件工程师时,经常会问一些关于代码本身设计的问题。获得一段可以执行的代码是微不足道的,向开发人员询问 strtolowerstr2lower 是否是函数的正确名称也是无伤大雅的(记录下来,是 strtolower)。知道类和对象之间的区别并不能让你成为一个有能力的开发人员;例如,一个更好的面试问题是,如何将子类型多态性应用于实际的软件开发挑战。如果不能评估软件设计技能,就会降低面试的效率,导致无法区分哪些人擅长,哪些人不擅长。这些高级主题将在本书中讨论,通过学习这些策略,你将更好地理解在讨论软件架构时应该问哪些正确的问题。

莫克西-马林斯派克(Moxie Marlinspike)曾在推特上发表过如下言论:

作为一名软件开发人员,我羡慕作家、音乐家和电影制作人。与软件不同的是,当他们创造出某种东西时,它就真的完成了,永远完成了。
— Moxie Marlinspike

在开发软件时,我们不能忘记自己是作者,不仅是机器指令的作者,而且我们还在编写日后期望他人扩展的东西。因此,我们的代码不仅要针对机器,还要针对人类。代码不仅仅是机器的诗歌,它也应该是人类的诗歌。

当然,这说起来容易做起来难。在 PHP 中,由于 PHP 为开发人员提供了架构和结构代码的自由,这一点可能尤其困难。就自由的本质而言,它既可能被利用,也可能被滥用,PHP 提供的自由也是如此。

因此,开发人员必须了解正确的软件设计实践,以确保他们的代码具有长期的可维护性,这一点越来越重要。事实上,另一项关键技能在于 重构代码,即改进现有代码的设计,使其更易于长期扩展。

我发现,技术债务(不良系统设计的最终后果)是 PHP 开发人员职业生涯中不可避免的问题。无论是处理提供高级功能的系统还是简单的网站,对我来说都是如此。出现这种情况通常是因为开发人员出于各种原因选择实施了糟糕的设计;这可能是在现有代码库中添加功能时,也可能是在软件的初始构建过程中做出了糟糕的设计决策。重构可以帮助我们解决这些问题。

SensioLabs(Symfony 框架的创建者)有一个名为 Insight 的工具,允许开发人员计算自己代码中的技术债务。2011 年,他们使用该工具对不同项目中的技术债务进行了评估;不出所料,他们发现 WordPress 4.1 在所有评估平台中名列榜首,他们声称需要 20.1 年才能解决该项目中的技术债务问题。

熟悉 WordPress 内核的人可能不会对此感到惊讶,但这个问题当然不仅仅与 WordPress 有关。在我的 PHP 工作生涯中,从安全关键的密码学系统到任务关键的嵌入式系统,处理技术债务都是工作的一部分。对于 PHP 开发人员来说,处理技术债务并不是一件羞耻的事,事实上,有些人可能会认为这是一种勇气。处理技术债务并非易事,尤其是面对要求越来越高的用户群、客户或项目经理时;他们不断要求增加功能,却不了解项目的相关技术债务。

最近,我给 PHP Internals 小组发了一封电子邮件,询问他们是否应该考虑废弃错误抑制运算符 @。当任何 PHP 函数的前缀是 @ 符号时,该函数将抑制其返回的错误。这可能是非常残酷的,尤其是当该函数返回一个致命错误,导致脚本停止执行时,调试工作就会变得非常艰难。如果错误被抑制,脚本可能会执行失败,而开发人员却无法解释原因。在某些情况下,使用该操作符可能会被视为一种反模式,我们将在第 4 章 "结构设计模式 "中介绍这一点。

尽管没有人反对有比滥用错误抑制操作符更好的处理错误的方法(try/catch、适当的验证),而且废除错误抑制操作符应该是 PHP 的最终目标,但事实是,有些函数即使已经有了成功/失败值,仍然返回不必要的警告。这就意味着,由于 PHP 内核本身的技术缺陷,在完成大量其他先决工作之前,这个运算符还不能被废弃。在此期间,开发人员将自行决定处理错误的最佳方法。在不必要的错误报告这一固有问题得到解决之前,该操作符不能被弃用。因此,开发人员应了解处理错误的正确方法,而不是一味地使用 @ 符号。

从根本上说,技术债务会减慢项目的开发速度,并经常导致代码在部署时被破坏,因为开发人员试图在一个脆弱的项目上开展工作。

在开始一个新项目时,永远不要害怕讨论架构,因为架构会议对于开发人员的协作至关重要;正如我合作过的一位 Scrum 主讲人在面对 "会议是工作的最佳替代品" 的批评时所说,他说:"会议就是工作…​…​如果没有会议,你还能做多少工作?

在本章的其余部分,我们将讨论以下几点:

  • 编码风格 – PSR 标准

  • 修改面向对象编程

  • 使用 Composer 设置环境

  • 四人帮是谁?