TL;DR
这篇文章来自于 Ruby China 上一个很有意思的 讨论 。原文是一篇国外开发者的吐槽 Rails Hurts 。你看的没错,他还特意注册了一个域名 :)
看完后我觉得作者有些断章取义和偷换概念,因此有了这篇文章。主要是想探讨一下,Rails 真的 Hurts 吗?下面我们根据原文的结构一条一条来分析(吐槽)。
看这篇文章之前,我建议看看作者的原文。不管是否赞同他的想法,都会有些收获。
DRY – Don’t repeat yourself
DRY 只是一种被推崇的原则,但不代表必须无时无刻的严格执行。作者把它理解成 “无论什么时候 你看到一个重复的概念,你都 应该马上 去把它抽象成一个方法或类” 太狭隘和绝对了。我们老祖宗也说过 “事不过三”,生活中估计也没人能严格做到这一点。
关于代码重复和耦合的问题,作者的论据显然来自 Sandi Metz 说的 “重复比错误的抽象要廉价的多”,但这其实不是 DRY 的问题,而是错误的抽象的问题。而错误的抽象往往来自于对一些概念缺乏全局理解。拿构建领域模型举例,对一个概念的完全理解往往需要反复不断的尝试和探索,这是需要花时间的,而不是了解了一点概念就 应该马上 去设计的。所以我想应该是作者对 DRY 的片面理解和执行导致了错误的抽象,从而认为 DRY 会导致代码耦合。其实这两者一点关系都没有。
KISS – Keep it simple, and stupid
这个其实是吐槽 AR 而不是吐槽 KISS 的。关于 KISS 各人有各人的理解。作者把 KISS 跟 AR 联系在一起是因为 AR 是 用简单的接口隐藏复杂的实现 。其实更应该吐槽的是 AR 混合了太多的关注点,与这点有关联的原则应该是 Single Responsibility Principle 。我也觉得 AR 操心的事情太多了,它的设计在现在来看已经过于复杂了。正因为功能强大,才导致了之后 Fat model 这种理念的兴起。
最后我还是比较赞同这句的:Rails is not simple, it is convenient 。
Conventions over Configurations
我一直觉得一个 Convention 好不好得取决于两点,一是大众对这个 Convention 的接受程度,二是这个 Convention 符不符合直觉思考。Rails 在这两点上做的都没问题。作者主要吐槽的是 Rails 提出的 CoC 理念把很多第三方开发者都影响了,让他们制造了很多诡异的 Conventions 和滥用元编程写 DSL 。但这仍然不是 Rails 的问题,也不能证明 CoC 是不好的。
是否 CoC 从广义上看是 implicit 和 explicit 孰优孰劣的问题。我觉得把符合直觉的配置变成 Conventions 能简化很多事情,其他部分不妨用 Configurations 。
Fat model, skinny controller
这确实不是个好事。但 Rails 社区也早就不这么干了,现在几乎找不到 Fat model 的文章了,反 Fat model 的文章倒是不少。
说到 Fat model 这个话题,我抛一个不成熟的观点,我觉得 Rails 对开发的简化很大程度上来自于 对抽象层级的压缩 。这点在 AR 上体现得尤其明显。这种设计在做简单的功能时会非常省事,在 model 里写几行 validation 和 callback 就把数据库事务,表单验证,业务逻辑前后的副作用(比如发送邮件)全部搞定了。但如果复杂的场景下还沿用这种开发方式就会导致 model 臃肿,业务逻辑互相缠绕等问题。究其原因,还是抽象层次的压缩导致了代码缠成一团。
但从另一个角度看,Rails 也并没有阻止开发者去加自己的抽象层。validation 和 callback 这些功能也被设计成很容易加到其他 class 里面。所以 Rails 还是蛮灵活的。只是开发者必须意识到对简单问题的处理思路(很多人理解的 Rails way)基本不可能沿用到复杂问题领域,而这点认识往往是在被坑过之后才知道的。
Rails is not your application
这部分提到的业务逻辑和 Rails 框架混杂,本质上还是没有对业务逻辑做足够的抽象,或者说对 OO 缺乏足够的理解才导致把 Rails 当做英语考试的完形填空去做。但现实中的业务逻辑是千变万化的,没有一个框架能完美地抽象出公共的模式。
其实一个引申的问题更值得思考,那就是框架到底应不应该提供架构决策?我目前的想法是框架也是系统架构的一部分,但不能完全代表整个系统的设计。这个话题也许会让人联想到 Domain-Driven Design 和 Uncle Bob 说的 Hexagonal Architecture ,或者 DCI 等模式。有任何想法欢迎探讨。
YAGNI – You aren’t gonna need it
这一段的论点是 Rails 默认给你了太多的东西,但这就是所有全栈框架的思路,拿这点吐槽 Rails 也是不客观的。关于全栈框架和微框架的讨论已经很多了,就不多说了。
Prefer composition over inheritance
Ruby 的 mixin 到底算不算 composition 这点真不好说。我赞同作者文章下面的评论说的,这是 composition 本身定义太模糊了。Sandi Metz 在 Practical Object-Oriented Design in Ruby 里定义的概念更清晰:
I think maybe what we’re getting at here is “composition at the object graph level” rather than “composition at the object level”
总结
作为一个干了 8 年的开发者,这些年也用过不少框架。我发现但凡红极一时的框架或类库,都有这么两个特性:
优点足够明显,能在当时的世界引发一些新的思考,指引一些新的方向。
并非完美无缺,只是缺点都能通过一些方法来解决或绕过,换句话说,没有无法解决的致命缺陷。
Rails ,AngularJS ,React 莫不如此。Rails 是有一些设计缺陷甚至架构上的误导,但也确实带来了一批新的理念,也许现在看起来都是老生常谈,但在 07 年那个时候却是一种颠覆。
另外,再先进的框架也无法取代架构设计,开发者仍然应该学习一些设计能力和原则,虽然有时候它们跟框架理念会有冲突,但更多是互补的。
So, does Rails hurt? 看到这里,我想你自己心里应该有了答案。