一、一个名字,把我带回了过去
这个系列,起于一次很偶然的阅读。
我在一篇公众号文章里,重新看到了 Ruby 这个名字。
它已经有些年没有这样占据我的注意力了。我原本只是随手浏览,却在看到它时停了一下。过去的记忆忽然涌了上来,连同初入这一行时,那种面对许多陌生名字的心情。
那时,编程世界很大。许多技术,我知道它们存在,也隐约听说过它们的好,却还没有足够的经验,理解那些赞叹究竟从何而来。
Ruby 就是其中之一。
后来,我沿着自己的路往前走。Java 成了日常工作的主要语言,C、Python、前端,以及曾经接触过的 Scala,也逐渐构成了我理解程序的不同视角。至于 Ruby,它一直留在记忆里,并未真正走近。
直到这次重逢,我才发现:我还记得这个名字,却几乎没有认真认识过它。
这件事忽然让我有些在意。
二、为什么偏偏是今天
如果只从眼前的实用性出发,此刻专门花时间了解 Ruby,似乎并不是最紧迫的选择。
至少在我日常接触的技术话题里,它已经不像当年那样频繁地处于聚光灯下。我也没有一个非用 Ruby 不可的项目,更没有打算因此放下已经熟悉的技术栈。
这也许确实有一点心血来潮。
不过,技术热度决定的是一个名字被多少人谈论,并不能替我们回答:它究竟有什么值得理解。
一门语言曾经让许多程序员认真地谈论“优雅”“表达力”和“编程的快乐”,这些感受究竟来自哪里?当人们说 Ruby 很漂亮时,他们欣赏的,只是少写几行代码吗?还是它曾经让他们发现,程序原来还可以这样组织,框架原来还可以这样设计?
这些问题,不会因为它不再大热,就失去意义。
甚至在热闹稍稍退去之后,我反而更愿意慢下来,暂时放下排行榜、招聘需求和技术阵营,看看语言本身。
我想了解的,是 Ruby 的灵魂。
所谓灵魂,并不是什么玄妙的东西。它藏在一个个具体选择里:为什么对象可以这样协作,为什么行为可以这样传递,为什么框架能写得像一门小语言,以及为了这些自由,程序员又需要承担什么。
三、走过一些路以后,再回头看
这些年,一个很深的感受是:同样的技术,在不同阶段回头看,会呈现出不同的面貌。
早些时候学 C,注意力更多放在指针、数组、结构体,以及内存究竟应该怎样申请和释放。后来 Java 写得更深了一些,再回头看 C,那些熟悉的语法背后,开始出现新的问题。
引用和对象到底是什么关系?GC 替我承担了什么?一个看似普通的方法调用,经过运行时,最终怎样落到机器上?
C 没有变,变的是我终于带着问题回来了。
这让我意识到,有些理解需要时间。第一次遇见时,我们拥有的经验还不足以接住它;等走过一些路,再回来,原本平淡的一句话、习以为常的一种设计,才忽然显出分量。
如今再看 Ruby,大概也是这样的心情。
如果当年就打开一份 Ruby 教程,我或许会把它当作又一套需要记忆的语法。今天,我更容易看见它与 Java 的分歧,也能借助 Python 和 JavaScript 的经验,理解它的动态性、闭包和行为传递;接触 Scala 时对表达力与理解成本的感受,也会成为另一种参照。
我依然是 Ruby 的初学者,只是这一次,不再空手而来。
四、顺便,走近那道尚未熟悉的 C++
重新打量自己的技术经历时,我还发现了一处空白:我有 C 和 Java 的背景,却一直没有系统地走近 C++。
它像是这两段经历之间,一条看得见、但没有真正走过的岔路。
当然,语言学习并不存在一条必须依次经过 C、C++、Java 的路线。我也不认为技术栈一定要补成某种完整形状。只是这一次,我恰好有了兴趣:既然已经从 C 看过一些底层问题,也从 Java 体会过运行时和工程约束,不妨再看看 C++ 怎样处理抽象、所有权与对象生命周期。
而把它放在 Ruby 旁边,恰好能形成一种很有意思的对照。
Ruby 让我留意人的表达:怎样把意图写得自然,怎样让常见的事情不必反复铺陈。
C++ 则会提醒我关注另一面:一个对象怎样存在,一份资源由谁拥有,高级抽象最终付出了多少机器成本。
它们当然不能被这几句话概括,但这种差异足以成为一个入口。借着两端的对照,我也希望重新看清自己最熟悉的 Java:它替我挡住了什么,又为什么保留了那些有时显得啰嗦的规则。
C++ 会是这段旅程里的同行者,Ruby 仍然是主角。
五、把这次回望,写成一组文章
所以,我想把这次学习整理成一个系列。
它不会是一份面面俱到的 Ruby 手册,也不是站在熟练使用者的位置上,给出一套不容置疑的评价。它更接近一名有些工程经验、对 Ruby 尚陌生的程序员,带着已有经验去认识另一种设计思想的笔记。
我们会从对象与消息开始,进入鸭子类型,走过 Block、Proc、Lambda 和 yield,再看看 Module、元编程、DSL,以及 Rails 的那些“魔法”从何而来。
我希望留住的不只是惊艳,也包括惊艳之后的追问:省掉的声明去了哪里?动态性怎样获得可靠性?漂亮的抽象什么时候会变得难以排查?语言给予的自由,需要怎样的工程克制?
Java、C、Python、JavaScript 和 Scala,会作为理解 Ruby 的参照。C++ 则在适当的地方出现,让我们看一看另一种成本模型。
贯穿这些文章的,其实是同一个问题:
一门语言选择替程序员隐藏什么,又选择让程序员承担什么?
如果你也有一门熟悉的主力语言,也曾在忙碌中搁置过对某项技术的好奇,那么,这个系列或许适合慢慢读。不必急着判断以后用不用得上,可以先看看:另一些程序员,是怎样理解我们每天都在解决的问题的。
回望并不一定意味着留恋过去。旧的设计里,有已经兑现的承诺,也有付出过的代价;理解它们,或许能让我们在面对下一种新语言、新框架时,多一点判断,少一点盲从。
这大概就是我此刻所想的:往事可鉴,来者可追。
至于这份突然而来的好奇,我也想认真对待一次。
做技术久了,我们很擅长判断一件事是否紧急、是否有用、是否值得投入。但偶尔,一个名字从旧日里浮出来,让人愿意重新做一会儿学生,这本身就是一件值得珍惜的事。
那个曾让我停下来的名字,现在又出现在眼前。
这一次,我想多停一会儿。
系列目录
阅读建议
第一遍可以像看小说一样浏览,只抓住每篇的中心问题,不必运行每段代码。
第二遍再停下来做横向翻译:看到 Ruby 代码,先在脑中映射成 Java、Python 或 JavaScript;然后问自己,Ruby 为什么偏偏选择这种表达?
第三遍才适合动手。每篇末尾都有几道“不是为了考语法”的思考题。它们真正想训练的是语言设计视角。




