异军突起的钻石小鸟

2009 年前后,国内有一家卖钻石的网站很火,叫“钻石小鸟”。

那时候网上买书、买衣服已经不算新鲜,但钻石不一样。几千甚至几万元一颗的东西,消费者看不到实物,真的敢在网上买吗?这件事当时让我很意外。

钻石小鸟的做法,是把线上和线下结合起来。用户可以先在网站上了解钻石、挑选裸钻,再到线下体验店试戴和成交。它当时把这种模式叫作“鼠标+水泥”。放在当年的电商环境里,这种做法相当大胆,也确实跑出了声量。

互联网行业有个很典型的现象:只要一个模式被证明能跑通,很快就会有人跟进。2009 年的钻石电商也一样,各种类似的网站开始冒出来。

于是,也有人找到了我。需求很简单:

“给我做一个钻石小鸟。”

明星框架 Ruby on Rails

“给我做一个和 XX 一样的平台”,这种需求通常还有一个很有意思的地方:客户并不会觉得这件事有多复杂。在他们看来,无非就是照着已有的东西做一遍,给出的预算往往还觉得已经很有诚意了。这个项目也是一样,预算低到基本已经不能用“赚不赚钱”来衡量。当然,国内软件行业一直有个神奇之处:无论什么价格,最后似乎总有人敢接。

我也接了,不过有另外一个目的。我一直希望能在真实项目里尝试一些自己感兴趣的新技术。Demo 写得再漂亮,终究只是 Demo;真正放到项目里跑一遍,很多东西才知道到底好不好用。

当时,一个叫 Ruby on Rails 的 Web 框架正在迅速走红。Rails 在 2004 年开源,创始人 David Heinemeier Hansson 因为 Rails 在 2005 年获得 Google 和 O’Reilly 的 Hacker of the Year;Basecamp、Twitter 等产品的使用,也让它很快在开发者圈里出了名。到 2009 年,这个诞生不过几年的框架已经发展到 Rails 2.3。

我也因此开始关注它,而真正让我觉得有意思的,是 Rails 的开发哲学。

几乎不用配置的 ActiveRecord

当时 Rails 里最让我印象深刻的一个东西,是 ActiveRecord。

ORM 当然并不是什么新概念。那时候不少语言和框架都已经在做对象和数据库之间的映射,但很多方案用起来并不轻松。为了少写 SQL,往往要先写一堆 XML、mapping 或其他元数据,告诉框架这个类对应哪张表、这个字段对应哪一列、主键是什么、对象之间又是什么关系。某种程度上,就是为了少写一种代码,先多写另外一种代码。

ActiveRecord 的感觉完全不一样。一个 User 类,默认就对应 users 表;主键默认就是 id;看到 user_id,它也知道这通常意味着一层关联。只要按照 Rails 的习惯来,很多原本需要显式声明的映射关系都可以直接省掉。当然,这些默认规则并不是不能改,只是在大多数情况下,你根本不需要为它们写额外配置。

它还有一些当时很有“魔法感”的功能。比如 find_by_email 这个方法,你既不需要事先声明,也不需要写具体实现,只要数据库里有 email 这个字段,就可以直接调用。对象关系也类似,通过 has_many、belongs_to 这样简单的声明就能建立起来,不需要再写一大堆映射配置。很多在其他 ORM 里需要显式描述、甚至自己实现的东西,到了 ActiveRecord 里都被省掉了。

这种体验对我冲击很大。以前使用很多框架,我首先要做的是告诉框架:“我的系统是什么样的。” ActiveRecord 却像是先默认了一套答案,只要你的项目没有故意跟它唱反调,它就可以替你省掉大量工作。

为什么很多别人需要配置的东西,到了 Rails 这里却不需要了?

约定优于配置

答案就是 Rails 最著名的理念之一:Convention over Configuration,约定优于配置。

它的意思并不复杂。很多系统之所以需要大量配置,并不是因为这些事情真的有很多种合理答案,而是因为框架把选择权全部留给了开发者。类叫什么、表叫什么、主键叫什么、文件放在哪里,理论上当然都可以自由决定,但如果大多数项目最后都会采用差不多的做法,那这些自由其实未必有多大价值。

Rails 的思路是,先给出一套大家都遵守的约定。你按照约定来,就不需要再解释;只有真的遇到特殊情况时,才额外配置。它并没有取消灵活性,只是把“什么都要配置”变成了“有需要才配置”。

这种思路在当时很有冲击力。程序员很容易把“灵活”当成一个天然的褒义词,最好什么都能改,什么都能换,什么地方都留一个扩展点。年轻时候看到一个系统有几十个配置文件,反而会觉得它考虑得很周全。Rails 却提供了另一种思路:如果一个选择大多数时候根本不重要,那最好的设计,也许不是把它做得更灵活,而是让开发者不用选。

从这个角度看,CoC 已经不只是减少几行 XML、少写几个 mapping 文件的问题。它实际上重新定义了框架和开发者之间的关系:框架不只是提供能力,也可以提供一套默认的判断。

ActiveRecord 最先让我感受到的是“省事”,但真正让我记住 Rails 的,是这种省事背后的开发哲学。

一场开发哲学的启蒙运动

Rails 后来的影响,我觉得可能比它今天的流行程度更值得讨论。

2004 年 Rails 出现时,Convention over Configuration 还是一个颇为激进的主张。少配置、少重复、少做那些没有价值的选择,本身已经和当时很多强调“高度可配置”的框架形成了鲜明对比。

几年之后,类似的思路开始陆续出现在其他技术栈里。2011 年,Spring Data JPA 发布正式版本,findByEmail、findByNameAndAge 这类根据方法名自动生成查询的写法,很容易让人想起 Rails ActiveRecord 更早就有的 Dynamic Finder。再后来是 Spring Boot,大量使用自动配置和默认约定,并明确强调 opinionated 的设计。

开发者社区里也普遍有人把 Rails 看作 Spring Boot 这类后来框架的重要启发来源,我也认同这个观点。

Rails 还有一句很有代表性的开发哲学:Optimize for programmer happiness。程序员用起来是否顺手、是否愉快,也应该成为框架设计时认真考虑的目标。今天我们讲 Developer Experience,讲合理默认值、自动配置、减少样板代码,这些已经越来越像基础要求,而不是某个框架独有的主张。

很多 Rails 当年显得颇为激进的想法,就这样慢慢变成了常识。所以直到今天,我依然认为 Ruby on Rails 是软件开发史上最有影响力的框架之一。它真正留下来的,不只是 Rails 本身,而是一套后来逐渐变成常识的开发哲学。

难以复制的成功

我把 Rails 里一些能借鉴的思路移植到了自己原来的 PHP 脚手架里,尤其是 ActiveRecord 和默认约定这套做法。当然,受限于 PHP 本身,有些 Rails 的特性并不好照搬,比如 Dynamic Finders。即便如此,这个项目还是让我第一次在真实系统里完整试了一遍这些想法,网站也顺利开发并上线。

网站上线

至于上线后的结果,我其实一开始就没有太乐观:几乎没有流量,也没有什么交易。毕竟从功能上看,“钻石小鸟”确实已经做出来了,但页面、功能和流程可以复制,一个产品为什么能成功,却不是把这些东西重新做一遍就能得到。

这个道理其实并不难懂,但行业里一直有很多人深陷其中,我也没有例外。等到自己创业时,我也曾经觉得:别人已经证明这个产品能成功,哪怕复制不了 100%,能有个 50%,似乎也已经很不错。

现实通常没这么客气,最后可能连 1% 都没有。

一个产品最后为什么会成功,远比我们当时看到的复杂得多。这件事,也是我自己创业以后才慢慢开始明白的。

我们可以复制一个成功产品的样子,却很难复制它的成功。