2007 年 4 月 24 日
ruby on rails 开发和 java™ 开发有着本质的不同。在跨越边界 系列的最后一期中,bruce tate 将概述使用 rails 从头开发一个复杂、可伸缩的 web 站点时所发现的二者的主要差异。
rails 开发人员常常把 java 开发人员看作是沉闷而劳碌的老古董。而 java 崇拜者则常常认为 ruby on rails 只是一个玩具,根本不能用于任何严肃的软件开发。作为一名对这两种技术都有着广泛使用经验的顾问,我认为真实的情形介于这两种观点之间。由于跨越边界 系列文章即将结束,因此我打算对它们再作一次比较。本文并非考察某种特殊的技术或语言,而是主要介绍我当前正在从事的项目,并将它与我以前从事的 java 项目进行比较。另外,我建议您阅读“跨越边界”系列的前几期文章,对相关主题作更深入的了解。这种直接的说明可让您在二者之间权衡利弊,并可能使您在数据库 web 应用程序 green-field 的开发中通过使用 rails 获益。
业务问题
rails 原理的下一个主要部分是动态编程语言。java 工具往往可以有效地使用 java 类型模型提供的额外信息。工具可以识别错误和有效地重构代码。rails 还可有效地利用编程语言的优点。ruby 是一种构建特定于域的语言(dsl)的理想语言。rails 集中使用 dsl 来完成从构建模型对象之间的关系到指定自定义组件(如状态机器或可上传的图像)的所有工作。动态语言常常更加简洁,因此 rails 项目比 java 项目要简练得多,可让用户更简练地表达代码和配置。在 changingthepresent.org 项目中,我们发现技术顶尖的程序员可达到更高的生产力,但是我们确实需要招募经验更丰富的开发人员。我对这种妥协非常满意。
传统的 java 程序员对 ide 有着近乎虔诚的热爱,造成这一现象有充分的理由。ide 提供了语法的完整性检查、修正了小错误并提供了增量编译以便更快地完成编码、编译、部署和测试这样的周期。最近几年来,开发环境开始更好地利用编译循环和静态类型提供的信息。ide 现在编辑抽象语法树(ast),而不是(或者同时)编辑代码的文本表示。这一策略允许使用强大的代码重构工具,而使用静态类型语言的同样方法来实现此功能则困难得多。
静态类型确实能更好地使用工具,但是也存在缺点。强制使用静态类型通常需要编译器,而编译步骤必然会降低生产力。使用 rails,我可以更改一行代码并重新加载浏览器,就可立即看到更改的结果。与 java 开发人员相比,大多数 ruby 开发人员只使用一种很好的编辑器。textmate 是最流行的 ruby on rails 编辑器,它提供了语法突出显示、代码完整性检查,以及一些频繁使用的结构的良好的模板支持。而当发现可将所有简单的基于 ruby 的脚本(用作基本的 rails 工具包)放入编辑器中时,您会更加喜出望外。与纯粹的调试器不同的是,我可以使用断点脚本,该脚本可停止特定的应用程序,进入一个 ruby 解释程序,我可在其中调用方法、检查变量的值,以及甚至在恢复执行之间修改代码。
简单的架构
传统的 web 端 java 架构包括:一个用于域对象和数据访问对象的层、一个提供业务级 api 的外观层、一个控制器层和一个视图层。此架构比典型的 “模型-视图-控制器” 架构(使用 smalltalk 语言最早创建)稍微复杂一些。相比之下,ruby on rails 包括一个使用 activerecord 设计模式的模型层、一个控制器层和一个视图层。我们喜欢易于获得的 rails 方法。它更加简练并且带来额外的复杂性和错误的机会更小。
惯例优先原则
java 框架通常可以自由地使用 xml 配置,而 rails 主要使用惯例来避免可能的配置。在程序员必须指定配置的位置,rails 通常依赖 ruby(常常以 dsl 形式)来提供配置。对于 green-field 开发,我发现惯例优先于配置是很有意义的。该策略为我省去了很多行代码,更简化了必须编写的代码。估计我们所需的配置只有传统 java 应用程序中所指定的十分之一。我们有时会损失一点灵活性,但这并不足以抵消使用此策略带来的节省。
总而言之,rails 框架的原理适合解决 changingthepresent.org 项目中的问题。集成的各种工具让我可以利用框架实现更多的功能而无需自己进行过多的集成。“惯例优先原则” 为我节省了配置站点的时间。动态语言为经验丰富的开发人员提供了更多的能力和灵活性,同时也使他们能够利用更少的代码表达更强大的思想。该框架适合于我们团队的能力和要解决的业务问题。
持久性
java 和 ruby 语言的最流行的持久性框架可以比任何其他特性更好地阐明 java 和 ruby 经验之间的区别,java 开发人员通常使用 hibernate,它是一种对象关系映射框架。通过 hibernate,您可获取现有的模型和模式并使用注释或 xml 表达二者之间的映射。hibernate 类是简单传统 java 对象(pojo),它的每个对象派生自一个通用的基类。大多数配置是显式的,使用注释、xml 或二者的某种结合。
而 activerecord 是一种包装的框架,就是说每个类都是现有类的包装器。activerecord 根据关联表的内容(如表中每列的一个属性)自动地向模型对象添加特性。所有的类都从一个通用的基类继承。activerecord 主要利用通用约定来推断配置。例如:
- activerecord 利用类名的复数形式来推出表名。
- 主键的名称为
id。 - 列表的排序顺序由
position字段决定。
对象关系映射是使用遗留模式(可能定义时没有考虑对象模型)时的最佳解决方案。但是当您能为应用程序显式地设计数据库模式时,您通常不需要映射框架了。我们将 activerecord 看作我们的一个巨大优点。我们可以包含关系数据库,需要时转入 sql 并在适当的时候退出。
迁移
rails 迁移使我们能够用代码表示模式的两个版本之间的差别,和它们所包含的数据之间的差别。对每个迁移都进行了命名和编号。可在任何时候恢复到任何版本。迁移有以下一些确切的优点:
- 产生错误代码时可恢复到一个旧版本的模式。
- 用代码而不是 sql 来表达模式,更便于我们使用。
- 在最大程度上与数据库独立。
但是迁移也有一些限制。如果两个开发人员同时创建迁移,则编号会出现混乱,所以我们必须手动处理。我们通过有效的通信来使这些问题最小化:团队成员构建需使用迁移的新模型时发出通知。但是这个模型依赖于团队的开发人员较少或迁移进展较慢的情况。
activerecord 还有其他的限制,其中一些是故意作出的。rails 的创建者认为:数据库的约束和组成应归入应用程序而不是数据库,这种思想带来了一些副作用。activerecord 使用视图的情况不是很好:构建过程(克隆模式、复制测试数据并运行测试)并不能正确地进行复制。activerecord 在使用参考完整性约束的某些场合也会出现问题,因为某些类型的关联可能连接到多个数据库表。跨越复杂模型进行预先加载很复杂,通常在连接多行时需要使用 sql。继承也受到限制:使用 activerecord 时,我被迫使用单表继承 映射策略,而该策略并不总是最佳选择。
所有的持久性策略都充满了妥协。我认为 activerecord 实现了一组有效的妥协,常常选择了简单性。总而言之,activerecord 和迁移是我们的积极推动。我们可以快速地构建解决方案,我们拥有足够的 sql 访问权可在需要时改进系统性能。但是当 activerecord 并不总能应对挑战时,最好将 rails 应用于使用老旧模式的项目。一些替代的持久性模型正在出现,包括 rbatis,一种 ibatis java 框架的端口。现在讨论 rbatis 的有效性还为时过早。
结束语
对于我的团队和项目来说,ruby on rails 被证明相当有效。我还不知道这个项目的最终规模如何,因为撰写本文时该系统才运行 3 个月。现在只是开始增加通信量。但是我们对生产力却很了解。我知道团队的预算比竞争公司(这些公司常常使用 java 解决方案)的要低得多。我对我们的生产力也很有信心。
通过跨越边界 系列,我向您介绍了 java 领域以外的语言和解决方案。但程序员毕竟是技术人员。每个高明的技术人员的工具包中都应包含适用于每个解决方案的广泛的工具集。除工具外,本系列中介绍的观点也为您展示了一些其他思路。现在一些框架设计者甚至将 seaside、rails 中的技术甚至 javascript 应用于 java 框架中。找机会进行同样的应用,继续 “跨越边界”。
关于作者
bruce tate 是位父亲、山地车手、皮艇手,住在德克萨斯州的奥斯汀。他是三本最畅销 java 图书的作者,包括获得 jolt 奖的 better, faster, lighter java。他最近推出了 from java to ruby 和 rails: up and running。他在 ibm 工作了 13 年,而后创立了 rapidred 顾问公司,在那里他专攻基于 ruby 的轻量级开发策略和体系结构及 ruby on rails 框架。现在他是 wellgood llc 的 cto ,该公司致力于为非盈利组织和福利机构开辟市场。
闽公网安备 35060202000074号