这个图很好地说明了 Rails 应用在架构设计上的不足。
“Or you can rely on tools. You can start using tools with modularity ideas built in, like Lotus or ROM. Of course, there is a less radical way. You don't always have the luxury of starting from scratch, but you can tweak Rails to provide some complexity management. Some of of the tools that may help you:
Rails 的架构在几年前还是不错的,但是现在时代变了,整个架构思想和团队组织也变了.以及不适合 Rails 这种全包的架构了. 没有可伸缩性. 但是作为独立开发者,还是 One.
如果觉得 Rails 笨重,Sinatra+ActiveRecord 也是一个很好的选择,参见拙作:Sinatra + ActiveRecord = Really Lean Startup?
没有觉得 Rails 跟图上画的一样,跟业务逻辑交织在一起,完全就是个错误的论断。
刚看了下他的一些文字,,他连 Convention over Configuration 都可以站出来反对,说这会“增加耦合”,实在是无语。估计这位同学是 J2EE 的卫道士——不依赖任何外部库,所有东西都手写,方法都是静态的,最符合其要求。
有点意思,我觉得 ActiveRecord 特别是其中的 callback, 还有 controller 里各种 filter 已经成为了我的噩梦了,这些东西把我虐的不要不要的
大致看了几点,作者想法就是写了个文章刷下存在感无它。
软件中任何的观点要结合适宜场景去做就好,不做会乱过度也会乱,遵循 Rails 的原则也是这样的。
我没理解错他意义的话:比如讨论 DRY 他的观点就在疑惑于何时做这事,没有一个合理,再一个减少重复时可能引入抽象等导致代码 复杂度上升。实际中的话应当是这样,当你发现一直重复类似方法时先抽方法,有业务需要再抽象,怎么弄就看具体需要,实际也容易搞出恶心一笔,当把一个共用的东西搞得太恶心,显然就应该拆分开。
天下合久分,分久必合,我觉得这个做法是最好处理 DRY 的困惑。
#6 楼 @Xenofex 他是先肯定了 CoC 的,只是说过度使用的问题。Rails 学习难度比较大也是这个原因,有很多隐含的设定。类似于所谓的潜规则,长期来说还是明规则比较好。
Conventions over configurations What could be wrong with conventions? We should praise Rails for giving us naming convention about database stuff, that makes sense.
But some developers take it too literally and go mad with it. They introduce their own extra conventions. And they are usually implemented with hardly readable metaprogramming code.
The bad thing about conventions is that they are implicit. So if there's too many of them, it can be hard to remember why everything is done in a way it is done.
Even default conventions might become too tight for you when your app grows. So just remember that the price of convention is flexibility.
我很乐意承认 Rails 可能会存在一些问题,不过这个作者的论点有点断章取义了
比如 DRY
因为 DRY = Abstraction
并且 Duplication > Wrong Abstraction
所以 Duplication > DRY
丝毫不考虑Right Abstraction
的情况
再说 KISS 他说的一大堆如果建立在 Rails 经常出现莫名其妙不可调试的错误,且 Rails core team 水平不高的情况下,不过我认为这不符合现实。
再看这个网站的首页 slogan
The goal of this project is to help developers stop suffering while they are working with Ruby on Rails
如果把他的反对 Rails 的地方都去掉然后再来用 Rails,嗯,大家可以想象一下。
我虽然也不太喜欢 Rails,但这文章把所有的锅都推给 Rails 背,也觉得太冤了,其中很有一部分是因为作者的理解不全导致的概念偷换。下面逐条分析一下:
DRY 只是一种被推崇的原则,但不代表必须无时无刻的严格执行。作者把它理解成“无论什么时候 你看到一个重复的概念,你都 应该马上 去把它抽象成一个方法或类”太狭隘和绝对了。古人还说“事不过三”,生活中估计也没人能严格做到这一点。
关于代码重复和耦合的问题,作者的论据显然来自 Sandi Metz 说的“重复比错误的抽象要廉价的多”,但这其实不是 DRY 的问题,而是错误的抽象的问题。而错误的抽象往往来自于对一些概念缺乏全局理解。拿构建领域模型举例,对一个概念的完全理解往往需要反复不断的尝试和探索,这是需要花时间的,而不是了解了一点概念就 应该马上 去设计的。所以我想应该是作者对 DRY 的片面理解和执行导致了错误的抽象,从而认为 DRY 会导致代码耦合。其实这两者一点关系都没有。
这个其实是吐槽 AR 而不是吐槽 KISS 的。关于 KISS 各人有各人的理解。作者把 KISS 跟 AR 联系在一起是因为 AR 是 用简单的接口隐藏复杂的实现 。其实更应该吐槽的是 AR 混合了太多的关注点,与这点有关联的原则应该是 Single Responsibility Principle。我也觉得 AR 操心的事情太多了,它的设计在现在来看已经过于复杂了。正因为功能强大,才导致了之后 Fat model 这种理念的兴起。
最后我还是比较赞同这句的:Rails is not simple, it is convenient。
我一直觉得一个 Convention 好不好得取决于两点,一是大众对这个 Convention 的接受程度,二是这个 Convention 符不符合直觉思考。Rails 在这两点上做的都没问题。作者主要吐槽的是 Rails 提出的 CoC 理念把很多第三方开发者都影响了,让他们制造了很多诡异的 Conventions 和滥用元编程写 DSL。但这仍然不是 Rails 的问题,也不能证明 CoC 是不好的。
是否 CoC 从广义上看是 implicit 和 explicit 孰优孰劣的问题。我觉得把符合直觉的配置变成 Conventions 能简化很多事情,其他部分不妨用 Configurations。
这确实不是个好事。但 Rails 社区也早就不这么干了,现在几乎找不到 Fat model 的文章了,反 Fat model 的文章倒是不少。
说到 Fat model 这个话题,我抛一个不成熟的观点,我觉得 Rails 对开发的简化很大程度上来自于 对抽象层级的压缩 。这点在 AR 上体现得尤其明显。这种设计在做简单的功能时会非常省事,在 model 里写几行 validation 和 callback 就把数据库事务,表单验证,业务逻辑前后的副作用(比如发送邮件)全部搞定了。但如果复杂的场景下还沿用这种开发方式就会导致 model 臃肿,业务逻辑互相缠绕等问题。究其原因,还是抽象层次的压缩导致了代码缠成一团。
但从另一个角度看,Rails 也并没有阻止开发者去加自己的抽象层。validation 和 callback 这些功能也被设计成很容易加到其他 class 里面。所以 Rails 还是蛮灵活的。只是开发者必须意识到对简单问题的处理思路(很多人理解的 Rails way)基本不可能沿用到复杂问题领域,而这点认识往往是在被坑过之后才知道的。
这部分提到的业务逻辑和 Rails 框架混杂,本质上还是没有对业务逻辑做足够的抽象,或者说对 OO 缺乏足够的理解才导致把 Rails 当做英语考试的完形填空去做。但现实中的业务逻辑是千变万化的,没有一个框架能完美地抽象出公共的模式。
其实一个引申的问题更值得思考,那就是框架到底应不应该提供架构决策?我目前的想法是框架也是系统架构的一部分,但不能完全代表整个系统的设计。这个话题也许会让人联想到 Domain-Driven Design 和 Uncle Bob 说的 Hexagonal Architecture,或者 DCI 等模式。有任何想法欢迎探讨。
这一段的论点是 Rails 默认给你了太多的东西,但这就是所有全栈框架的思路,拿这点吐槽 Rails 也是不客观的。关于全栈框架和微框架的讨论已经很多了,就不多说了。
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"
最后说点总结的话,作为一个靠 Rails 混碗饭吃多年的开发者,我对 Rails 的感情是比较复杂的。它是有一些设计缺陷,但也确实带来了一批新的理念,也许现在看起来都是老生常谈,但在 07 年那个时候却是一种颠覆。另外,框架只是工具,开发者仍然应该学习一些设计能力和原则,它们跟框架理念有可能有冲突,但更多是互补的。
最后,还是推荐各位 Railser 都去看看这篇文章。有时候从反对者中也能学到不少知识,毕竟没有什么东西是完美的。太喜欢或者太讨厌都是狭隘的表现,最狂热的爱好者更容易变成最冷酷的反对者。