Node.js哲学

每个编程平台都有自己的理念,一套被社区普遍接受的原则和指导方针,或者说是一种做事的意识形态,它影响着平台的发展以及应用程序的开发和设计方式。其中一些原则源于技术本身,一些则由其生态系统促成,一些只是社区中的趋势,还有一些是从其他平台借鉴的意识形态演变而来。在 Node.js 中,其中一些原则直接来自于它的创建者—​Ryan Dahl,而另一些则来自于为内核做出贡献的人员或社区中的魅力人物,最后还有一些则是从更广泛的 JavaScript 运动中继承下来的。

这些规则都不是强加于人的,在应用时应始终遵循常识;不过,当我们在设计软件时寻找灵感来源时,这些规则会被证明是非常有用的。

您可以在 Wikipedia 的 nodejsdp.link/dev-philosophies 上找到详细的软件开发哲学列表。

小核心

Node.js 内核(可理解为 Node.js 运行时和内置模块)的基础建立在几个原则之上。其中一个原则是尽可能减少功能集,而将其余功能留给所谓的用户区域(或用户空间),也就是核心之外的模块生态系统。这一原则对 Node.js 文化产生了巨大的影响,因为它为社区提供了自由,让他们可以在用户领域模块的范围内对更广泛的解决方案进行实验和快速迭代,而不是将一个缓慢发展的解决方案构建到控制更严格、更稳定的内核中。因此,将核心功能保持在最低限度不仅在可维护性方面非常方便,而且还能为整个生态系统的发展带来积极的文化影响。

小模块

Node.js 使用模块概念作为构建程序代码的基本方法。它是创建应用程序和可重用库的构件。在 Node.js 中,最受欢迎的原则之一是设计小模块(和包),这不仅体现在原始代码的大小上,更重要的是体现在范围上。

这一原则源于 Unix 哲学,尤其是其中的两条戒律,具体如下:

  • 小即是美。

  • 让每个程序做好一件事。

Node.js 将这些概念提升到了一个全新的高度。在模块管理器的帮助下(其中 npm 和 yarn 最受欢迎),Node.js 通过确保依赖于同一软件包不同版本的两个(或更多)软件包使用各自安装的软件包来避免冲突,从而帮助解决依赖地狱问题。这样,软件包就可以依赖大量小而精的依赖关系,而不会有产生冲突的风险。在其他平台上,这种做法可能被认为不切实际,甚至完全不可行,但在 Node.js 中,这种做法却是一种规范。这使得可重用性达到了极致;事实上,这种可重用性是如此之高,以至于有时我们会发现软件包只由包含几行代码的单一模块组成,例如,用于匹配电子邮件的正则表达式(如 nodejsdp.link/email-regex)。

除了可重用性方面的明显优势外,小模块还具有以下优点:

  • 更易于理解和使用

  • 更易于测试和维护

  • 体积小,非常适合在浏览器中使用

拥有更小、更集中的模块可以让每个人共享或重用最小的代码片段;这是在全新水平上应用 "不要重复自己"(DRY)原则。

最小的功能集

Node.js 模块除了体积小、范围小之外,还有一个理想的特点,那就是只向外界公开最小的功能集。这样做的效果是,API 的使用更清晰,不易出现错误使用。事实上,在大多数情况下,组件的用户只对非常有限和集中的功能感兴趣,而不需要扩展其功能或挖掘更高级的方面。

在 Node.js 中,定义模块的一种非常常见的模式是只公开一种功能,如函数或类,原因很简单,它提供了一个单一、明确无误的入口点。

许多 Node.js 模块的另一个特点是,它们是为使用而创建的,而不是为扩展而创建的。通过禁止任何扩展的可能性来锁定模块的内部结构可能听起来不够灵活,但它实际上具有减少用例、简化实现、方便维护和提高可用性的优势。在实践中,这意味着更倾向于公开函数而不是类,并注意不要向外界公开任何内部结构。

简单实用

你听说过 "保持简单,避免愚蠢"(Keep It Simple, Stupid,KISS)原则吗?著名计算机科学家理查德-加布里埃尔(Richard P. Gabriel)创造了 "简单即好" 这个术语,用来描述功能越少越好的软件设计模式。他在《"简单即好" 的兴起》一文中写道:

"设计必须简单,无论是实现还是界面。实现简单比界面简单更重要。简单是设计中最重要的考虑因素"。

设计简单而非完美、功能齐全的软件是一种很好的做法,原因有以下几点:实施起来更省力,可以用更少的资源更快地运行,更容易适应,最后,更容易维护和理解。这些因素的积极影响鼓励了社区的贡献,并使软件本身不断成长和完善。

在 Node.js 中,JavaScript 作为一种非常实用的语言也促进了这一原则的采用。事实上,简单的类、函数和闭包取代复杂的类层次结构是很常见的。纯粹的面向对象设计往往试图用计算机系统的数学术语来复制现实世界,而不考虑现实世界本身的不完美和复杂性。相反,事实是我们的软件总是现实的近似值,我们可能会更成功地尝试以合理的复杂度尽快实现某些功能,而不是试图创建近乎完美的软件,付出巨大的努力和维护大量的代码。

在本书中,你将多次看到这一原则的应用。例如,相当多的传统设计模式,如 Singleton 或 Decorator,都可以有一个琐碎的、甚至有时并非无懈可击的实现,你将看到一个不复杂的、实用的方法是如何(在大多数情况下)优于一个纯粹的、无懈可击的设计的。

接下来,我们将深入了解 Node.js 内核,揭示其内部模式和事件驱动架构。