The Rails Doctrine - Rails 信条

19 条评论 , 54 次修正,78647 次阅读,最后更新于 2020年10月09日

本文翻译自 The Rails Doctrine - 作者是 DHH,原始由 @juanito 翻译成 繁体中文,再由 Ruby China 组织成简体中文。 如你发现本文有错别字或翻译不准确的地方,请访问 GitHub 提交 Pull Request。 下文将提到的我,表示 DHH 自己。

Ruby on Rails 惊人的活跃度主要是因为本身采用了新颖的技术和好的时机。但技术优势随着时间的推移而减弱;纵然有好的时机,时间久了影响也会逐渐减少。Rails 为何不仅能继续存在,还依然具有影响力并带领社区继续前进呢?需要更进一步地解释。我提议以下这篇内容,这是我们的基本信条,也是饱受争议的信条。

这篇信条,在过去 10 年里不断演进,是 Rails 主要的支柱,同时也是基本的支柱。我不自诩自己是这些想法的原创者。Rails 的主要成就是整理和培养出一套编程与程序员本身的思想集合。

废话不多说,以下是由我所认为,Rails 中最重要的 9 个基本信条:

  1. 程序员的幸福最大化
  2. 约定优于配置
  3. 主厨精选
  4. 多元化的设计模式
  5. 推崇优美的代码
  6. 提供实用工具
  7. 重视整合系统
  8. 进步比稳定更重要
  9. 包容并重

程序员的幸福最大化

是 Ruby 造就了 Rails,所以第一条信条便是从创造 Ruby 的核心理念所提炼出來。

早期 Ruby 的极端邪说就是把程序员的幸福度放到第一位。还把追求幸福置于驱动编程语言与生态圈前进的考量之上。

当 Python 对『用一种方法,最好只有一种方法来完成一件事』感到自豪时,Ruby 却喜欢自身表现力与巧妙;当 Java 正在为保证开发者不犯任何错误而努力时,Ruby 却敢在开发者的工具库中放一个可以用来『上吊』的绳子。当 Smalltalk 专注于消息传递的纯粹性时,Ruby 却贪婪地累积着关键字和复杂的语法构造。

看得出,Ruby 如此与众不同。原因很简单,Ruby 考量的东西不一样。上述这些考量,都是为了满足和追求软件工程师的幸福。这些追求导致了与其他编程语言的辩论,也打开了主流文化对于究竟什么是软件工程师,以及应该如何应对软件工程师的认知。

Ruby 不仅仅认可,并直接从语言设计上满足开发人员的编程体验。不管这些想法是不充分的、奇思妙想的,还是令人喜悦的。Matz 跨越了惊人难度的实践门槛,让机器面有喜色,且富有人性。Ruby 满满是视觉上的错觉,在我们看起来 Ruby 很简单,清晰,也很优美,背后其实是杂技般的错综复杂。这些选择不是没有代价(问问 JRuby 那些试着要对 Ruby 逆向工程的人看看!),这也是为什么,这是很值得赞扬的一件事。

这是对软件开发另一种愿景的致敬,也决定了我对 Ruby 的钟爱。这不止是简单易用,不仅是美学的元素,也不是单一的技术成就。而是一种愿景,是反文化。Ruby 是一个不适应呆板专业软件开发的人,而是专属于爱好之士的乐土。

我过去谈过,发现 Ruby 像是找到完全适合我的魔法手套。比我想象中的任何手套都来得合用。这是我从“写程序只是因为我需要程序”到“写程序是因为热衷于其中的心智表达与练习”的一次转变。是找到无我之境,且能够随意开放的入口。对于任何熟悉 Csikszentmihalyi 作品的人来说,我真的一点也不夸张。

当我说 Ruby 改变了我,我真的不夸张,Ruby 决定了我人生的努力目标。如此深刻的启示。Ruby 感染了我,呼唤我对 Matz 的产物做出宣教的工作。传播这深刻的语言与恩赐。

我想你们现在大概都感到疑惑地摇摇头。我不怪你们,假如我还处于“编程只不过是工具”的阶段,有人跟我说上面的经历,我也会摇头。接着我还可能会对这宗教般的语言发笑。但说实在的,这也是最真诚的理由,即便这可能使某些人,甚至是多数的人感到不愉快。

无论如何,究竟这对 Rails 意味着什么?这个理念为什么持续引导 Rails 演进?要回答这个问题,我想用另一个启发性的理念来说明,一个早期常用来描述 Ruby 的概念:最小惊讶原则(The Principle of Least Surprise)。Ruby 应该要如你预期般地运行。可以用下面这个对比于 Python 的例子来解释:

$ irb
irb(main):001:0> exit
$ irb
irb(main):001:0> quit


$ python
>>> exit
Use exit() or Ctrl-D (i.e. EOF) to exit

Ruby 可以用 exitquit,来回应程序员的需求,也就是想离开终端交互界面。而 Python 则迂腐地告诉程序员如何做该做的事,即便它已经知道程序员想干嘛了(却只显示错误信息)。这是非常清晰的、微小的、最小惊讶原则的例子。

不过最小惊讶原则最终在 Ruby 社区失宠的原因非常直观。最小惊讶原则,惊讶谁?那当然是 Matz 了,以及那些跟 Matz 一样对同样事物感到惊讶的人。Ruby 社区成长茁壮的同时,人们对不同的事情感到惊讶与 Matz 成长过程中感到惊讶的事情不一样,这主要咎于失败的邮件列表讨论。为了要避免更多甲男对乙物是否感到吃惊的争论没完没了,所以这个理念从此退居幕后。

再一次,这跟 Rails 到底有什么关系?嗯,Rails 就是按照相似的理念,尽量不惊讶(Matz)而设计,以及(DHH 的)璀璨微笑理念,这理念就是:框架的接口设计是着重考量,怎样可以让人用起来能会心一笑。写下此句时,即便是我自己,也会觉得这在第一次听到时会感到非常的滑稽与自恋。

但创作出 Ruby 或 Rails 这样的成果,本身就是深度自恋的努力成果。Ruby 与 Rails 都是诞生于单一创造者。但也许我只是在这把我的动机投射在 Matz 身上,所以让我缩小我宣言的范畴:我发明 Rails 只是为了我自己。从最初开始就是为了让我自己微笑。Rails 的许多工具,很多方面看来,它们的用途都是为了让我更加享受人生。充实那些每天为需求所争论不休的生活,以及用来打造 Web 应用程序。

和 Matz 一样,我有时候为了实现我的理念也会做出一些蠢事。一个例子便是 Inflector,一个可以对英文做不规则转化的类,譬如 Person 类对应到 People 表、Analysis 对应到 Analyses,Comment 对应到 Comments 等。这个东西现在已经是 Rails 不可分割的元素了,但早期争议的怒火延烧到今日,伤口仍未愈合,由此可见其重要性。

另一个例子仅用了些许代码实现,却几乎引发了惊愕的程度。Array#second#fifth(以及挑衅意味的 #forty_two)。这些别名的存取器,非常严重地冒犯了常发表意见的支持者,他们说:这简直太过度设计了(几乎是编程时代的结束),这些写成 Array#[1]Array#[2](以及 Array[41])不就可以了嘛。

但时至今日,主要的抉择还是,让我自己开心。我喜欢在终端或测试里编写 people.third。不,这不合理,也不高效。可能我有病吧,但这仍能让我发自内心地微笑,满足了这个理念,也丰富了我的人生,帮我在过了 12 年之后,还仍继续参与 Rails。

不像性能优化有明确的指标,幸福优化很难衡量。这使得幸福优化变成了不科学的无谓努力,某些人要不是彻底失望,可能就是觉得这并不怎么重要。程序员被教导要争执并征服实际的东西,也就是可以明确指出,为什么 A 比 B 好的东西。

但追求幸福,是很难从微观的角度来衡量,但从宏观的角度来看便很清楚。许多人留在 Ruby on Rails 社区便是这个原因。他们自豪于能更好、更圆满地工作生活。而正是因为这些情感因素,胜利是很清楚的。

总结,追求幸福可能是形成 Ruby on Rails 的关键因素。而这个因素将会跟着 Rails 一直走下去。

约定优于配置

早期 Rails 的生产力座右铭是:“你不是独一无二的,大家都一样”。只要放下了自负的个人喜好,便可以跳过无谓的世俗决定,专注在最重要的地方下更快的决定。

有人在乎你的数据库主键命名用什么格式吗?用 idpostIDposts_idpid 真的有差别吗?这真的是值得反复讨论的吗?不!

Rails 的部分使命就是,帮助开发者在日渐复杂庞大的 Web 应用程序决策丛林中劈荆斩棘。几千个无谓的决定只需要做一次,而若是别人帮你做这些决定,那就更好了。

约定优于配置,可以将我们从各种小的决定中解放出来,也提供一个繁茂的草原,让我们孕育更深层的抽象。如果我们可以依赖 Person 类对应到 people 表,我们也可以用同样的词形变化,从 has_many :people 推导出类名是 Person。优良约定的力量是广泛使用才能获得许多好处。

不仅专家的生产力提升了,约定也降低了新手的门槛。Rails 里有非常多的约定,新手无须知道,但却能实实在在地从中获益。他们不需要了解每一件事情为什么是这样,也可以打造出伟大的应用。

但框架要仅是厚重的教科书就不可能了,新的应用好比一张白纸。单纯要理解到从那开始,如何起步,就需要花费巨大的努力。一半的时间都花在纠结,纠结该拉那一条线才是正确的。

同样的道理也可以套用在当你了解了所有组件是如何一起工作时。每当一个改变的下一步非常明确时,我们可以快速地游走在应用相似或于其它应用相同的组件之间。一个包含了所有东西的地方,所有东西都在一个地方。即便是最有能的人,也可以从约束中解放出来。

世间万物,有好有坏,约定的力量不是没有危险。当 Rails 这么简单就可以做这么多事情的时候,很容易就会这么想,应用的每个部分,都可以用一个预先准备的模版来解决。

但多数值得做的应用,总有某种程度上独一无二的部分,它们可能是 5% 或是 1%,不管多少,但总是会有的。

最困难的部分就是何时应该打破约定?什么时候才要偏离正轨?我主张多数的行动其实都没什么不同的,也没好好认真想过,而偏离 Rails 的代价被低估了,其实是有代价的,需要你引以深刻的反思。

主厨精选

在餐厅不知道什么好吃该怎么点菜?若你交给主厨挑选,可能可以在了解为何“好”之前,就吃上一顿好菜。这就是 Omakase。无需成为美食专家或乱点菜碰运气,就可以吃到好东西的方法。

对软件开发来说,主厨精选这个实践的好处是技术栈交给别人帮你组合,跟我们从约定优于配置所得出的论点相似,但它更上一层。CoC (约定优于配置) 考量如何用好单一的工具,而 Omakase 则考量该用什么框架,以及框架之间该如何协作。

有这么一说,软件开发的优良传统便是把可用的工具交给使用者自己去选择,决定权(还是负担?)交给程序员。

你一定听过这句话,也在心里面点头赞同:“用最好的工具来解决问题”。这听起来很基本,但能够选择“最好的工具”需要明确的定义出什么是“最好”。这其实比想象中要难的多。

这个问题跟在餐厅要吃什么相似。像是挑选八道菜的每一道,选择每一个三方库或框架,这不是独立的决定。选择需要根据今晚的状况来考虑,挑选三方库则要考虑整个系统。

所以 Rails 我们根据大局考虑,把选择减少到一套好的工具,让每个工程师可以从中挑选:一套为了大家好的工具。好处如下:

  1. 分散风险:当大家都用预设的方式来使用 Rails,我们有共同的体验。这个共同基础让我们可以容易指导和帮助新人,大家有讨论的共同基础。就好比大家昨晚七点都看了某个节目,所以明天大家都有共同话题可以谈论。进而培养出更有凝聚力的社区。
  2. 大家熟练使用相同的工具:身为一个全栈的框架,Rails 有很多可以移动的组件,这些组件之间如何协调工作?如何独立工作?两者同样重要。多数的软件开发者的痛苦不是来自于独立的组件,而是组件之间的互通。当我们用同样的方式来使用这些组件,相同的配置便可以得出相同的错误,则大家受的苦便减少了。
  3. 有必要的时候也可以换掉:Rails 是主厨精选的技术栈,某些子框架或类库你仍然有选择的权利。只是不一定你要换掉它们,这些决策可以之后再做,在你开发出一个明确的、需要不一样的个性化应用的时候再来考虑吧。

因为多数使用 Rails 且有经验的软件工程师,并不是都讨厌菜单上的每一道菜(讨厌的话就不会继续使用 Rails 了)。他们努力挑选想要的替代方案,而其它则享受和大家一样的工具。

多元化的设计模式

大家对中央集权的概念有很强烈的情感,而根据最终得出的理性结论来作为架构基础。这个理念存在某种纯粹性,这也是为什么软件工程师会被中央集权所吸引。

Rails 不是这样,Rails 不是一件裁剪完美的衣服,Rails 是一件棉被。一个用很多概念,甚至是设计模式组成的棉被。这些概念和设计模式看起来可能有抵触、自相矛盾或互相矛盾。但这不是我们要做的事,这不是靠有更优越的点子就可以胜出的总冠军赛,不是一定要选出一个赢家。

看看 Rails MVC 里用来打造 View 的模版。在默认情况下,这些 Helper 允许我们从 View 抽取出代码,抽出来不过是一堆函数!这些函数甚至存在于同一个 Namespace 下面。噢,惊讶了吗?感到恐惧了吗?正是像 PHP 那样呢!

但我认为 PHP 在单一函数之间,很少需要互动这点上是对的,就像 View 有着许多的抽象一样。根据这个目的,单一的 Namespace,一堆的方法,这不只是个合理的决定,还是很棒的决定。

这不代表我们不会偶尔想要用“面向对象”的方式来打造 View。Presenter 的概念,把彼此之间独立的方法以及要呈现的资料包在一起;这可能是方法混在一起最好的解药。但这很少见。

相比之下,我们通常把 MVC 的 Model 看成是“面向对象”精华的主要堡垒(需要改善翻译!)。选择正确的名称,增加一致性,减少耦合,这是 Model 好玩的地方。这跟 View 是很不一样的,所以我们采用了和 View 不同的做法。

但即便我们不采纳单一设计模式的教条。Rails 的 concerns,Ruby mixin 的特例,通常用来扩展 Model。这跟 Active Record 的模式完美结合,给予每个方法有直接存取、存储正在交互资料的权力。

即使 Active Record 框架的根本侵犯了某些纯粹主义者。我们把跟数据库打交道的逻辑和业务逻辑混合了在一起。合并了边界!没错,因为这才是做出 Web 应用贴切的实际方法,Web 应用通常就需要跟数据库打交道,也需要存储某些业务逻辑的状态。

有如此理想的弹性,正是为什么 Rails 可以解决许多不同的问题。多数单一的流派解决单一的问题很厉害,但超出舒适圈就变得非常尴尬死板,需要使用许多交错的设计模式。而我们旁敲侧击,在后面把关,最终整合出来的框架更强大,也是比单一模式能做更多事情。

现在,这种与许多程序设计流派结合的多重关系,是概念上的负担。仅了解面向对象程序设计是不足以用好 Rails 的。还需要有面向过程编程和函数式编程的经验。

这也可以应用到许多 Rails 的子语言。我们不试图剥夺你学习的机会,比如你可以在 View 里写 JavaScript,或者用 SQL 来写复杂的查询。这些都是允许的。

降低学习曲线的方法,真的只是想办法让大家更容易上手,在了解框架的每一个组件之前,做一些有实际价值的东西(更有意义)。这也是框架为何要尽快示范出 Hello World。告诉你桌子已经准备好了,前菜也上了。

这其中的思想就是:尽早给出有实际价值的东西。我们鼓励 Rails 的实践家快速学习,接受学习的过程是一种喜悦,而不是障碍。

推崇优美的代码

我们写程序,不只是要让计算机和其他人理解,而是要沐浴在优美的夕阳余晖里。看起来漂亮的代码,本身就有价值的,要尽力追寻。但这不代表优美的代码就应该胜于一切的考量,而是要把优美纳入优先考量。

什么是优美的代码?在 Ruby 里面通常穿插于 Ruby 本身的惯用式和自定义的 DSL 威力之间。这是一条模糊的分界线,但非常值得一试。

以下是一个取自 Active Record 的简单例子:

class Project < ApplicationRecord
  belongs_to :account
  has_many :participants, class_name: 'Person'
  validates_presence_of :name
end

这看起来像是 DSL,但这只是一个类 (Class) 定义,其中有三句类方法 (Class Method) 调用,方法调用接收 Symbol 以及 Hash 参数。没有什么特别的,但这很漂亮。这也很简单。只需几行声明,便赋予我们巨大的能力与弹性。

这几条语句部分的美丽,来自于履行先前的理念,像是约定优于配置。当我们使用 belongs_to :account 时,我们假设 projects 表有一个叫做 account_id 的外键存在。当我们把 participants 的关联类用 class_name 指定为 Person 时,我们只需要定义 Person 类就可以了。这条语句便可推导出外键以及其它需要的设定。

以下是取自数据 Migration 的另一个例子:

class CreateAccounts < ActiveRecord::Migration
  def change
    create_table :accounts do |t|
      t.integer :queenbee_id
      t.timestamps
    end
  end
end

这是框架威力的精华所在。软件工程师按照某种约定来声明一个类,像是继承自 ActiveRecord::Migration 并实现 #change 方法,剩下的就交给框架来处理,该去哪里,该调用哪个方法。

这样软件工程师只需编写很少的代码。以 Migration 的例子来说,这样一个文件加上 rails db:migrate 命令,就可以创建一张新表;反过来也可以用另一条命令来删除一张表。这跟软件工程师自己使用背后的函数去修改,搞定所有细节很不一样。

有时候优美的代码反而更玄乎。不是要追求写得多短多短,或是多厉害,而是读起来要有节奏感。

以下两条语句是等价的:

if people.include? person
...      
if person.in? people

但它们的执行流程与关注的地方有着微妙的不同。第一个语句,关注的是群体里是否有特定的人。第二条语句则是人是否属于群体。两条语句都差不多,但我主张第二条语句更美,能让我在想这个条件的时候更容易有种会心一笑的感觉。

提供实用工具

Ruby 本身就有许多实用的工具,不是碰巧,设计正是如此。最出名的就是 Monkey Patching - 一种可以修改类与方法的能力。

但这个能力很快被嘲讽说,一般的软件工程师掌控不了。而限制性较为严格的语言阵营的人们认为,Ruby 这个功能盲目地信任软件工程师,Ruby 注定是要失败的。

什么都可以改变的话,又怎么能阻止你把 String#capitalize 从原来处理 "something bold".capitalize 改成 "Something Bold" 而不是原来的 "Something bold" 呢?这里你自己的应用上可能没问题,但这就把其它依赖 String#capitalize 的库搞坏了。

有人说禁止使用才是答案。在 Ruby 里面,只要有好的理由,没有什么可以阻止你使用 Monkey Patching。我们通过约定、推广、教育来宣导好的观念,而不是禁止使用厨房的菜刀或者规定每个人只能用汤勺来切番茄。

但 Monkey Patching 的另一面是能够做成 2.days.ago(算出从现在计算两天前的时间)这样的美技。你可能会觉得,哦,这交易真不划算。也就是你宁可不要 2.days.ago 也不想修改语言的标准库,你若这么想的话,那 Ruby 可能不适合你。

但有些人出自于安全性的考虑,不得已只好放弃修改 Ruby 的标准库。但反过来说,语言活跃的原因,正是因为给软件工程师提供了激进的观点:同时也相信可以放心的把工具交给软件工程师使用。

不只是相信,语言本身也有多种方法来教导我们使用这些有用的工具。如此一来我们可以把整个产业向上提升,透过假设多数的软件工程师都想要进步,大家都能使用好的工具,而不是伤害到自己。这真是一个鼓舞人心的想法啊,但这有悖于大部分软件工程师对其他同事的想法。

在决定实用工具的价值时,总得以大家为出发点来讨论。我尚未听到任何一个软件工程师说,“我无法相信这股力量,请把它拿走!”。常常听到则是“我想其他的软件工程师会滥用这个”。但我从来就不喜欢这个家长式的作风。

这正是 Rails 要提供实用工具的原因。框架所提供的工具不仅和语言所提供的工具同样实用,也很锐利。我们不为提供这些工具而感动抱歉。事实上我们自豪,我们有足够的信心启发下一代的软件工程师,并且有勇气相信他们。

许多 Rails 的功能常常饱受这样的争议:“太过自由”。但我现在想到的一个例子是 Concern。这个基于 Ruby 内建功能 Module 之上的一层,薄薄的语法糖。为了单一类打造,可以用来封装多个相关却又独立理解的“关系”(也正是 Concern 名字的由来)。

对于 Concern 的指控是有了一组新的抽屉,让软件工程师很容易把物件都塞进去。这说得没错,Concern 的用途就像这样。

但谬论是不要提供像是 Concern 的功能,但凡让有点能力的人来使用 Concern,便可得出有说服力的概念分离,软件工程师可以从 Concern 获得先天上的架构优势。这么说吧,如果你不能保持 Concern 的整洁度,那你也不可能写出优雅的代码。

尚未学会使用这些实用工具的软件工程师,尝不到收获的果实。这里有一个重要的点:“尚未”。我相信每个软件工程师都有自己的一条道,最终都将变成有能力的 Ruby 与 Rails 软件工程师。有能力我是指足够的知识,知道自己应该在何时,以及该怎么根据实际场景来使用不同的工具,有时甚至使用危险工具。

这不是要把帮助他们成为厉害开发者的责任卸下。框架与语言应该是有耐心的导师,愿意帮助和指导任何人,让他们走上大师之路。同时认可不断犯错是唯一的道路:错用工具、一点教训、汗水,有时候还可能是泪水。是的,想要变强就是应该这样,没有捷径。

Ruby on Rails 是大厨的厨房,是想变成大厨的试炼场。你可能从洗盘子起步,但可以一步步努力往上爬,爬到掌管厨房。别让任何人告诉你,最好的工具不能放心的交给你使用,而是应该看作成长过程的一部分。

重视整合系统

Rails 可以在很多场景下使用,但最初是用来做整合系统的 Majestic Monolith!Majestic Monolith - 即用一个系统来解决所有的问题。这表示着 Rails 从需要做即时刷新的前端 JavaScript,到能让数据库在生产环境迁移到下一个版本等等各方面功能,都要纳入设计的考量。

我们已经谈过,这是多么广阔的眼界。但对于一人团队来说,不过就是现实的考量而已。Rails 特别寻找通才(全栈工程师,各方面都擅长的人)来打造整个系统。目的不是要把专家束之高阁,而是让通才和专家合力,打造出更具长远价值的系统。

为了让一个人可以做更多的事情,才想出了整合系统。而正是在整合系统里,我们可以拿掉许多不必要的抽象,减少抽象层之间的重复(像是服务端与前端可以共用 View 模版),以及避免系统在非必要的情况下分离。

系统开发的复杂度多半是引入了系统组件之间的界限,比如现在 A 组件该如何和 B 组件进行相互调用。本地组件之间的方法调用要远比 Microservices 之间的远程调用来得简单。Microservices 是另一个存在失败状态、延长问题,依赖更新周期的新场景(需要对比原文理顺,有点不太对),有许多潜在的问题等着尝试拆分的人去冒险。

当然有时候这种服务的拆分是必要的。若想建立让大家可以透过 HTTP 实用的 API,好吧,那你就得毫无怨言的处理许多的问题(虽然处理进来的请求比发出去请求要单一,但要是你的服务挂了,别人就会收到错误的状态了)。但这至少对你个人的开发体验伤害有限。

更糟糕的是,当系统过早解耦,或是过早拆成小服务,以及更糟糕地拆成 Microservices。这是现代网络应用的错误认知,你只会反复地重造系统:同样的功能在后端做一次,在前端再做一次,在 Native 手机端又再次实现一次等等。这不是自然规律,你也不需要这样。

若想在整个应用里共享大部分的功能,这完全是可行的。桌面应用和 Mobile App 可以用同样的 Controller 和 View。尽可能地把功能集中在 Majestic Monolith - 整合系统。集中在一起完全不需要牺牲构建速度,开发者体验,以及其它错让你以为要尽早拆分系统的因素。

这正是我们要追求的系统:包含所有功能,容易发布,简单理解的单一系统,整合系统。

进步比稳定更重要

当一个系统已经存在超过 10 年,比如 Rails,自然会慢慢僵化。每一处的修改,都有百万种理由可能会变成别人的困扰,或是有人仍需要旧的行为。这对他们来说都是合理的理由。

但若我们太仔细听取保守派的意见,我们将永远不知道另一边的声音是什么。我们需要勇敢地做出改变,打破陈规,然后才可以茁壮演化。正是这样的演变,才让 Rails 存活下来,并可能继续繁荣发展(数)十年。

这些理论上都很简单,但实际做起来却很困难。特别是你的应用因为升级大版本的 Rails 时,因为有不兼容的变更而坏掉了。正是此时,我们珍重[进步比稳定更重要]的价值观,这个价值观给我们力量来搞定升级,搞清楚为什么并与时俱进。

但这不代表我们就可以加入不需要的功能,或是胡来把别人的应用搞坏了。Rails 2 升到 3 的迁移噩梦,仍在经历过的人身上阴魂不散。那真的是很艰难的决定。修改太大使得许多人停滞在 Rails 2.x 无法前进,有些人更是讨厌至极。可我们从大局来看,这件事仍然是值得的选择。

这些是需要一直做出的权衡。做了这个改变之后,Rails 能够在 5 年之内变得更好吗?Rails 可以采用某些问题的解决方案,比如异步任务队列或 WebSockets,这能让 Rails 在今后变得更好吗?如果这个答案是肯定的,那么就别说了,卷起袖子干活吧。

这些工作不只是 Rails 需要,广大的 Ruby 社区也需要。Rails 应该站在时代的前沿,通过引导大家快速升级新版本来推动 Ruby 演进。

这一点我们做得非常好。最早开始时,我们从 Ruby 1.6、1.7、1.8、1.9、2.0、2.1、2.2 一路升上 2.3。沿路历经多次的大版本更新,但 Ruby 总是有 Rails 当后盾,并帮助每个人的代码跑得更快。这是身为最流行的 Ruby 项目 Rails 的特权,同时也是义务。

这点也可以延伸到工具链的辅助工具。Bundler 曾是一个争议性的概念,但透过 Rails 的不懈努力,Bundler 成了未来的重要工具,今天理所当然已经是不可或缺的工具了。同样也可以应用到 Assets Pipeline 和 Spring (Rails 开发环境常驻的指令)。这三个一起出现,也仍然一起往前走,过程中可能造成了一些痛苦,但长远下来,这些工具提供的价值正是为什么我们要推广它们的原因。

最终进步的是人,以及人们乐意做出改变。这也是为什么,像 Rails Core 或 Rails Committers 这样的团队里没有终身职位。这两个团队是给活跃的,致力于带动框架进步的那群人而设定。对某些人来说,可能就几年,但我们永远感激他们做出的贡献,这些贡献可能将持续影响我们几十年。

而这也是为什么对我们来说,有一个能鼓舞社区新成员的友好环境非常重要。我们需要新血液、新概念,才可以激荡出更好的进步。

包容并重

正是归功于这么多争议性的概念才有 Rails。但若我们要求每个人完全遵从所有的信条,Rails 可能很快就变成孤芳自赏的小族群,所以我们不这么做!

我们需要反面意见。我们需要方言。我们需要多元的思想和群众。许多人用代码或是深思熟虑的论证来提供意见。正是在概念的熔炉里,我们才能提炼出这之中最好的让大家共享。

这篇基本信条描绘出一种理想状况,但日常生活中的实际情况却是更微妙的(也更有趣的),正因为 Rails 几乎从来不考验(? 不合理)每一个想法,它才能包容下这样庞大的社区

RSpec,一个我不喜欢的 Test DSL,RSpec 的持续成功是最完美的证据。虽然我可以说到脸红气喘,说为什么我不觉得它的方式是对的,但 RSpec 人可以繁荣绽放。这点才是最重要的!

同样的论点也适用在 Rails 做 API 的例子。虽然我个人关注也花心思的是带有 View 的整合系统;但对于一些想要做前后端分离的人来说,这当然是 Rails 可以改进的地方。我们应该要拥抱这一点,就是 Rails 不只是能做一件事情,当然也可以做 API。

包容并重并不代表把所有东西强加给所有人。这只是代表你欢迎人们带自己的饮料来参加你的 Party。我们要给别人加入我们的机会,却又不能失了我们的灵魂与价值观。因为我们从他们身上可以学到如何调一两杯新的饮料。

当然这是要付出代价的,需要努力让付出的贡献受欢迎。特别是我们目标不仅仅是要吸引住已经在社区的人,我们永远都要真正考虑如何降低起步门槛。

你永远不知道,改正文件错误拼写的人,可能就是下个大功能改进的黑马。无论是多小的贡献,都能笑着说感谢,这样贡献者就能一直持续下去。