国漫手机壁纸

聊聊 Ruby on Rails

,一个语言的问世,它是为一个特定场景设计的,一定有它最实用的场景。所以我们心知肚明在有 些应用中 Ruby 是有它的绝对优势的。另外,语言也是一个工具,它的性能能发挥到什么程度,和使用者的技术水平也是有很大关系的。我不想说喜欢吐槽 Ruby 的人都是 Ruby 写的不好的。

NetSmell 出品

程序员装逼语录二则:

“ Php 是世界上最好的语言。 ”

“ Ruby 写出来的程序就是一坨。”

先不跟你争论着两条语录有多少人真的理解,又有多少人相信。先和大家分享一条我很喜欢的挪威的格言:

“There’s no such thing as bad weather, only bad clothing.”

翻译过来就是:“不要抱怨天气不好,只是你没穿对衣服。”

当 然,这句话也是有槽点的,看官请三缄其口。想表达的一个意思是,一个语言的问世,它是为一个特定场景设计的,一定有它最实用的场景。所以我们心知肚明在有 些应用中 Ruby 是有它的绝对优势的。另外,语言也是一个工具,它的性能能发挥到什么程度,和使用者的技术水平也是有很大关系的。我不想说喜欢吐槽 Ruby 的人都是 Ruby 写的不好的。因为 Ruby 确实有很多局限性,我们后面会聊。但是作为一门语言,我觉得 Ruby 还是很值得掌握和学习的。

先说说学好 Ruby 有什么好处吧。

Ruby on Rails 的最大优势我觉得有四个:

  1. 语言灵巧轻便,适合快速开发和部署。
  2. 各种本身自带的 “magic” 以及可以通过 gem 或者 vendor code 加载的 magic。让代码美观简洁。
  3. 很容易与各种前端 JS 框架集成(包括Backbone,Ember,React等等)
  4. 有一个 Rails console 可以让 test 和 debug 变得异常轻松。

如 果你到湾区的各个中小公司走走看看,很大一部分最原始的第一个代码库都是基于 Ruby on Rails 的。尽管后期会有各种拆分和重写,对原来的 Ruby 代码能够很好的把握也是一项极为重要的技能。我早年是写 C++ 和 Python 的,最近三年多,却是有百分之六七十的时间写的是 Ruby,偶尔写写 Java 和 Scala,但是 Ruby 依然是我写的最顺手的语言,没有之一。因为 Square 和 Airbnb 两家公司 Ruby 都用的很多,所以对 Ruby 熟练也成为我在工作上的一个小小的优势。

虽然很喜欢 Ruby,但是却除了上面四点不想写太多废话来解释 Ruby 为什么好。不如说点有用的,了解并如何尽可能的避免 Ruby on Rails 里面的坑。

Ruby on Rails 最大的问题可能就是这个语言写代码开发起来快,维护起来却很困难。什么原因呢?怎么避免呢?

首先,Ruby 是动态类型的。什么意思大家都懂,就是一个变量没有类型声明,run time 的时候给它什么值它就是什么类型。语言的官方说法叫做 duck typing:

“ If an object walks like a duck and talks like a duck, then the Ruby interpreter is happy to treat it as if it were a duck. ”

“ 如果一个对象和鸭子一样走路一样说话,那么Ruby就很欣然地认为这就是一只鸭子。”

没 有类型申明的代码写起来简洁方便,尤其是不同对象间有可继承重用的关系的时候,如果换了 Java 这样的强类型语言就必须使用 interface 或者 abstracted class 来严格按照 design pattern 来处理。而在 Ruby 里面,你只要心中想要给一个变量什么值,那么只要后面赋值正确,这个变量就可以有什么值。这就必然引来两个麻烦:

  1. 不小心赋错值,Ruby 依然将计就计,也不抱怨。只不过在实际运行中让你找不着北,得到一个完全出乎意料的结果。
  2. 需 要 refactor 代码,也就是代码重构的时候。这几乎可以说是一场灾难。试想下你有一百把钥匙一百把锁,有类型申明的语言可能对于不同型号的钥匙和锁有所区分,而无类型申 明的语言所有的钥匙和锁几乎都长的一样。代码重构就好像把所有配对打乱,又要以新的形式组合。最后结果就是看着重构后利索无比的新代码,一不小心就给你 exception 了。

一个很有效的解决办法是,对一些重要的,尤其是 API 的参数类型进行强制类型检查和断言。比如在 Airbnb,我们会用一个 validation gem 对所有需要的变量去用代码来检测其类型,类似于 “validate count is_a Integer” 这样的断言。

第二,很多人对 Ruby on Rails 的 ActiveRecord 一知半解。ActiveRecord 可能是 Rails 里最强大的 magic 之一(或者没有之一)了。ActiveRecord 是对代码中数据库访问和业务逻辑访问的一个混合体。如果写的好,可以事半功倍,写出 DB 访问效率高且干净利落的数据库访问相关的代码,比如它的 scope 和 association 的运用。然而,如果对于 ActiveRecord 怎么实现似懂非懂,加上对 MySQL 的 execution plan 一知半解,很可能写出的代码一到 production 就会各种崩溃。举三个常见的例子:

  1. 老实说,我觉得不知道 N+1 Query 是啥的程序员都应该好好去了解下。N+1 Query 几乎是我见过的引发 production 问题的最常见的错误之一(也许没有之一)了。
  2. Rails 的association。最便利的 wrap 对象间 1对1、1对多、多对多等关联的 magic。很多别的语言应该都没有这个概念。Rails 的官方文档上有,强烈推荐深入了解。这也是平常见到的被错用最多的 magic 之一了。
  3. Rails 中的一些 job 需要在数据库中找到满足某些条件的 records 并进行处理。Rails 常用的有 find、find each、find in batch 等等,虽然不一样的查询语句都能给你一样的结果,但是因着他们对应的 SQL 语句的转化不一样,很多的时候效率天差地别。这也是 Ruby 代码中可以看出一个程序员对 Rails 的了解的一个常见的点。

例子还很多,坐下来可以慢慢写,这里也只是顺手写几个最先想到的。所以我们也不用一边写着低效的 Ruby 代码一边骂 Ruby 这不好那不好了。我琢磨 Ruby 可能觉得更怨。

第三,因着 Rails 中这样那样的 magic,写好 Ruby 的 RSpec 测试例可能是一件比写好 Ruby 代码还难的事了。写好 RSpec 其实有很多的技巧,最常用的:

  1. 各种 stubbing,包括对 FactoryGirl 和 Fixture 等的应用,好的 Rspec 其实可以帮助避免很多 Rails 里面的坑。怎么写好 Rspec,这个也不是一篇能说清的,有兴趣的可以留言,以后我如果有好的资料可以分享给大家。
  2. 这一条也适用于所有的程序语言的测试例的编写。是自上而下还是自下而上,怎么保证覆盖率,先写代码还是先写 test,很多好书。别的语言的写 test 的思想到这里也是适用的。

老实说我学写 RSpec 可能当初花的时间和写 Rails 代码本身花的时间一样多。即使是现在,我也不敢说我能把 RSpec 写到很好,只能说我愿意花时间精力努力把 spec 写好罢了。

第四,Rails 本身已经是一门语法极其精炼的语言了,没有必要为了把代码变得更紧凑而使用一些很炫的偏僻的语法。记 得我刚开始写 Ruby 的时候,喜欢干的一件事就是把整个函数我用一行 Ruby 各种技巧就写出来了。然后呢?不仅可读性差,有的时候时间长了,自己都忘了是怎么玩的了。后来越写越老实,怎么容易懂就怎么写。有一个写程序的原则我觉得 实用所有的语言:好的程序是不应该需要太多注释的。这包括结构的清晰和最合适的命名。这个原则对 Ruby 尤其重要,因为 Rails 本身已经各种 magic,很容易把代码写的出神入化,然后可读性极差。尤其是即使如 RubyMine 这样的 IDE 在跳转到函数定义或函数应用的这一功能上也不可能做到准确,因此可读性差的代码几乎注定早晚就成了个坑。所以当你写了一段 Ruby 代码你觉得有必要加一段注释来说明你想干什么的时候,可能应该先想想是不是应该重写这一段代码了。

其实还有第五第六第七……, 因为一门语言可以聊的东西太多了。记得以前 Square 的时候每周都有 Rails 的专门的研讨班,每周聊都聊不完,何况一篇文章?Square 两年于我最大的收获也是学会写 Ruby,记得我还曾半开玩笑的和朋友说过:“工作做的越久,越是什么技能都不敢往简历上写了,因为不断见到真的牛人。以后我找工作,简历上只写我会写一 点 Ruby 代码吧。” 因为很喜欢 Ruby,我的微信号都取了在 Mac 上写 Ruby 代码的含义。当然,Java 和 Scala 我也很喜欢。

显示余下内容
相关文章:
  1. Ruby On Rails 5.0发布
  2. 如何提高 Ruby On Rails 性能
 

发表回复

您的电子邮箱地址不会被公开。