Rails的让人不堪的噩梦
本文是从 Your Code is My Hell 这篇文章翻译而来。
我最近的作为一个Rails程序员的经历可能并不常见。
我经常被叫去维护一些已经做好的Ruby/Rails项目,在力所能及的地方进行改进和完善。这样,绝大部分我需要接手的项目在我出现前都已经开发完成了。事实上,在我的记忆里,我只参与了一个商业性质的格林菲尔德Ruby项目的开发。其它的,在我看来,都是“历史遗物“,相当多的程序代码在我之前都已经出品了。(不包括个人和内部项目)。
我知道,我的这种经历在Ruby和Rails程序员中并不常见。由于Ruby/Rails的高产和创业公司为主的用户环境,大多数Ruby爱好者都是在这样刚成立的公司里开发全新的项目。而我的工作更多的是基于最初的开发人员走后留下来的代码。
Rails的让人不堪的小秘密
在受雇写Ruby程序之前,我也接手过一些历史程序,它们有的历史达数十年之久,代码量数十万行之多。你很容易在这么多代码里找出写的很烂的东西;有时候,这种烂代码的数量多的让人惊讶。
但是,在Rails开发中,你会发现一个让人不堪忍受的小秘密;在我的职业生涯中,我见过的最乱的、最棘手的、最臭的代码,都是在Ruby on Rails项目里找到的。我所见过的那些Rails项目,它们两年下来积累的技术债务和废弃物,跟一个10年之久的C/C++程序相比,会让你觉得后者更干净和优雅。我说的并不是某个项目。我看到这种情况到处都是。
有时候我会想,这也显示了这种语言的强大之处。如果在一个Rails应用里有500个错误,你可以不停的往里面添加代码、再添加代码、点击“reload“,一直到它好用为止。从来都不需要写测试或重构代码。在很多语言和框架里,这种”补到它不漏为止“的开发方式显而易见是行不通的。但Ruby on Rails却提供了让你这样做的平台。
不幸的是,作为它的直接后果,众多我要处理的项目都可以被看作是一种应急产品。从某种角度来看,这种图省事的做法的后果还是由开发团队来承担,你这样做一天把它解决了,可引出的相关问题和不可预料的副作用,你花2周都解决不掉。
题外话:经常的,最初的开发人员会在完成开发后转移到新的项目上。同时会有新员工接手这些代码。管理部门会抱怨,为什么这新接手的团队修改问题时没有老团队迅速呢?而新团队遇到的问题是,在他们能给这些遗留的代码上添加新功能前,他们需要让这些代码具有更高的测试覆盖率,有可能还需要把它们分离成更小的模块;在商业层面,一个永久不变的声音是:测试和重构就是拖延工期。看来这原创团队都是比较明智的。
好了,牢骚发完了。
Rails的情况更为特殊!
Rails程序员有时候会显得很傲慢和固执。我不清楚这个判断的可信度;我并没有看到太多的人是这样,但也许我跟这个社区太接近了,也许我本身也是傲慢和固执的。
而我发现的却是一种“Rails例外主义“。还记得第一次互联网繁荣的时期吗,当时有几个经济学家跳出来说”不会的,这次不同,互联网改变了游戏规则,市场会一直走高、走高“,本质上我感觉很相似,有些人相信,Ruby on Rails开发是某种不同的东西,不需要跟其它类型的软件项目一样。
这有一些例子,让你明白我究竟在说什么:
◆ “设计模式是Java上的东西。Ruby里只管写你的代码就是了。“
◆ “Ruby里抛出的警告都是无聊的,禁止掉就行了。“
◆ “的确没有单元测试,而且对象隔离做起来很难,没有人这样做。“
◆ “到处打补丁对于其它语言来说是不赞成的,但Ruby没问题。目前还没有出现问题。”
◆ “像Demeter定律这样的东西在Ruby里并不是这么重要。“
◆ “把方法分成私有和公有,这是变态控制,Ruby里不需要这样做“
◆ “Java代码里才会有代码异味(code smell)。“
◆ “只有在大项目里才会有这样的问题“(暗示这个项目永远不会变大)
我还看到了很多项目和子系统例外主义者:“我知道一个类不应该搞的太大,但是对这个类是有意义的,它是为了把所有的东西放到一个地方“。
欢迎来到小人国
事实上,Ruby on Rails项目确实有一点很例外:都是小项目。上周在James Gray在Lone Star Ruby Conf大会上有个极好主题,他提到的“巨型“项目有4万多行代码。这让我微微一笑,因为我被雇来做的头两个项目分别有5万行和7万行。这看起来不少,但根据行业标准,它们很小。
造成这种现象的原因有不少。Ruby是一种比Java更富有表达性的语言,所以,从某种程度上说,Rails项目,在相同的情况下,总是比那些更讲究的语言显得更小。
而且,Rails程序员很喜欢接受把系统分割成很多很小的、相互联系的小应用。但是经验告诉我们,这种策略是有问题的。
不,我想这导致Rails应用体格较小的最大的原因是,显而易见的:这个框架还很年轻。这个领域里有大量不成熟的产品。一个Rails应用如果有3年的历史,那就可以算是古老了。
我可以很有信心的说,这种情况不会一直持续下去。我们会看到越来越大的程序项目。我不需要鼓起勇气就可以做下面的预言:很多项目将遭遇像Lisp, Smalltalk, C++, Java等语言曾经遭遇过的相同的架构瓶颈。
你并不特殊
《programming literature from the 80s》这个作品读起来非常的有趣。动态,面向对象的系统引导了从“小规模“到”中等规模“的过度。听起来耳熟,是吧?
每一次的革命都会坚称这次是与众不同的,不会造成上次革命后出现的政党纷争和官僚腐败。起初你很容易被这些宣传感染。每个人都很兴奋,热情的去帮助;这时出现的问题还比较小;然而这只是市场的大机器还没有注意到这场运动。
事实上,你要解决的问题也许并不是你想像的那样例外。你思想里的这种拜占庭模式只是远古时代那些使用跟Ruby类似语言的人留下来的遗产。
不要惊慌
放松。我这里要说的并不是告诉你过去的几年只是一场可爱的梦,Ruby实际上一直处在它应有的地位上。
Ruby仍然是一种奇妙的语言,它令人惊异的地方就是它在付出微小的约束代价下能轻松的接纳大型系统的设计模式。注入依赖?儿戏。对象委托和组合?小菜一碟。跟你的错觉正好相反,Ruby并不拒绝严谨的设计模式和SOLID编程原则;Ruby能做到的事是让它们更容易的表达出来。事实上,Ruby强大的富于表达的架构风格是让很多人第一眼就喜欢上它的原因。