Ruby 的对象关系映射器(ORM) DataMapper 将要在近期发布里程碑式的 1.0 版本。这个消息是在 RailsConf 2010 上宣布的,而且 Dirkjan Bussink 也在这次大会上做了相关的演讲。
作为一个社区共同参与的项目,DataMapper(DM)在过去的几年中已经完全成熟。它供了优异的 ORM 特性,不仅性能优异,能够确保线程安全,而且特性丰富。InfoQ 有幸采访到了 DataMapper 项目的首席开发工程师 Dan Kubb。
正式发布的时候,DataMapper 的版本号将是 1.0,这个版本号相比之前的最新版本号 0.10 是一个重大飞跃。Dan 就这个里程碑式的版本发表了一些深入的见解:
将版本号直接提升至 1.0 是非常艰难的选择。一方面你希望 1.0 是一个尽善尽美的版本,但是你又意识到没有任何软件可以尽善尽美,于是你又不得不使用其他的标准来帮助你做出决定。之所以这样做,是因为我们认为 1.0 这个版本号意味着 API 已经趋于稳定。也就是说,用户使用的公共 API 和插件作者使用的“半公共”的 API 都不会做出任何修改。虽然 2.0 的 API 可能会加入一些新功能,但是使用 1.0 的 API 的代码应该只需要在 2.0 发布的时候做一些细微的修改。当 DM 还是一个新兴项目的时候(大概两年以前),API 一直在不断变化,但在最近的 6 到 12 个月,API 已经趋于稳定,我们对此感到非常高兴。
当 DataMapper 1.0 发布的时候,大多数 Ruby 开源项目都已经到了 2.0 或者 3.0 版本。但是,在 DM 背后有一个异常活跃的社区在支持着它,数以千计的开发者贡献了大概 150 个 DM 相关的 gems。并且有大概 40 个适配器能够帮助 DM 使用不同的存储引擎来持久地存储数据。我们已经开发了你所期望的 RDBMS 适配器,不仅如此,我们还能支持 NoSQL 系统以及一些类似于 Salesforce 的 web 服务。
DataMapper 的设计能够允许开发者将对存储的大量关注和交互的前端 API 分离开。它能够在对象匹配上做一些基本的猜测,适配器的开发者可以很自由地全部或者部分实现和存储引擎的交互。大部分官方的 DM 插件都是通用的,并没有针对某个存储引擎做特别的开发。
DataMapper 的实现方法和其他的 ORM(例如 ActiveRecord)不尽相同,尽管后者是 Rails 的默认 ORM。当我们问到相比其他 ORM,DM 有什么特性能够让 Ruby 开发者关注的时候,他说:
我想开发者们会发现很多激动人心的特性,但是,我想从大多数只有 ActiveRecord 经验的人关注的事情开始介绍,而且这也是 DM 如何自然表达的地方。在 DM 中,每一个属性和关系都是在模型中声明,然后作为可信的来源使用,而不是需要将这些属性关系存储到数据库中。你需要指定某处的一些限制和行为,而且所有的东西都是从模型中反映,然后在迁移、验证或者其他的行为的时候使用。下面是一个简单的例子:
class Contact
include DataMapper::Resource
property :id, Serial
property :name, String, :length => 1…30, :required => true, :unique => true
end假设你在使用一个 RDBMS,当你调用 DataMapper.auto_migrate! 的时候,将会创建一张叫做“contacts”的表,这张表有两列。“id”列将会被设置为主键,并且自增。“name”列的类型是 CHAR(30),不允许为空,而且根据此列建立了一个索引。不仅如此,开发者还需要验证 id 和 name 都存在,而且 id 是整数,name 是字符串,长度在 1 到 30 个字节长,非空且唯一。
在 ActiveRecord 中,则要求你在不同的文件中切换,而且要牢记让数据在 DB 和验证器中保持同步。但是,很多情况下,开发者不仅仅厌烦了各种类型验证,而且还认为他们的 DB 只是一个“愚蠢的”数据存储设备,而 DM 能够减轻开发者的痛苦。我们鼓励开发者利用好底层数据存储的优势,而不要将其认为只是数据的倾倒场所。
我曾经在转到 DM 之前使用过 AR,结果我都几乎忘掉了在我的 DB 中有哪些字段,所以我不得不运行例如 annotate_models 来在我的模型顶部添加注释,写明当前的 DB Schema。实际上我使用都是和 DM 差不多的功能,除了没有享受到 DM 能够提供的那些优点。我仍然需要写明所有的验证器和初始迁移。
Ruby on Rails 2.x 的流行以及完全重写的 Rails 3 发布的近在咫尺,于是我们将 DM 和 Rails 项目的集成也提上了日程。任何开发者在考虑不走寻常路之前,需要仔细地衡量一下从 ActiveRecord 迁移的好处以及实现的难度。我们讨论了将 DM 和 Rails 集成使用,而且,试验的结果非常积极和高效:
将 DM 和 Rails2/3 在一起使用的开发者并不多,但是它的确能够工作得很好。Rails 2.x 有一个叫做 rails_datamapper 的 gem,Rails 3 则有一个叫做 dm-rails 的 gem。由于 Rails 3 的快速开发,我们决定将插件合二为一,这样我们就能够即时地和它同步。一些 DM 开发者能够跟随 Rails 的脚步对 gem 进行修改,确保 dm-rails 能够完美地工作在 Rails 3 下。
现在我们主要关注是让 DM 1.0 能够和 Rails 3 一起工作,就像它之前和 ActiveRecord 那样。rails-core 团队已经在使 Rails 3 ORM 的可剥离上做了大量工作,并且和 DataMapper 核心团队合作,保证我们能够使每件事情都能够正常工作。过去,为了能够正常和 Rails 2 一起工作,我们不得不做了很多深入 Rails 核心的研究,以期能够紧密地集成在一起,不过,现在已经不需要这样做了。
我们非常高兴地看到 dm-rails 是如何顺利发展的,而且,在未来它的一些核心将会被提取出来,放置到一个 gem 中间,这样的话我们可以能够在所有的 Web 框架上都保持一致的 rake task,模型(重新)加载等功能。此特点允许 DM 能够更简单深入地和其他框架一起工作。
决定在 Rails 项目中使用 DM 而不是 ActiveRecord 会产生一些疑问,例如对于开发者来说,适应另外一种 ORM 的难度如何呢?我们希望能够知道 DM 是否能够完全在 Rails 项目中替代 ActiveRecord,而不仅仅是一个替代品:
是的,没错。使用 DM,你需要在你现有的类中引入一个 module。大多数 AR finder 都可以在 DM 中找到对应的存在,而且有些时候这些 finder 甚至要比 AR 中的简单。我们同样也支持所有的验证器,而且有大概 150 个 DM 相关的 gem 可用。虽然在某些情况下,语法有点差异,但是,我非常自信地说,DM 能够做 AR 所有能够满足需要的事情,而且不需要插件的帮助。
DM 中一个非常有意思的特性是所有的属性和关系都是在模型中声明的。这样的话,看起来将不再需要 Rails 的迁移,但是,很快 Dan 就意识到迁移必不可少:
只是部分情况下不需要迁移,一旦你需要将你的程序投入生产应用中去,那么迁移是仍然需要的,因为你已经告诉 DB 如何修改以保存信息。而且,会有这样一些情况,例如 auto-migrations 会是毁灭性的,因为它们会卸载所有的表,然后重新按照声明的模型创建这些表,auto-upgrading 添加新的表、列和索引,但是它不够聪明,能够做一些例如重命名,删除列以及将列分解成多列的操作。我并不完全相信它能够非常聪明地完成这些事情,除非你能够显示地说明在迁移中你需要的事情。但是,如果需要将 auto-upgrading 加入到你的迁移过程,用它来处理额外的修改,以及使用显示的迁移脚本来处理可能会出现崩溃或者引起歧义的问题的话,那么我认为迁移的过程确实应该被简化。
即便如此,我们仍需要考虑生成能够简化过程的迁移脚本。它应该能够分清模型之间的差异,最后能够自动运行修改的迁移脚本。开发者应该检查迁移脚本是否做了你希望做的事情,然后部署即可,但是编写迁移脚本并不是表示你可以做个甩手掌柜,我们必须很清楚有一些额外情况需要处理,例如可能会出现崩溃或者引起歧义的问题。
DM 介绍了 automigrations,这个工具能够帮助开发者进行典型的 Rails 迁移:
对快速开发而言,这无疑是一个巨大的胜利。具有 TDD 的能力和只需要在模型和规范之间快速切换来增加新的属性,比在模型、迁移脚本和规范之间不断地切换要简单很多,而且后者还会打断你的迁移过程以及数据库存储。
这个项目中有很多吸引开发者的功能,其中之一是大量增强 DM 功能的插件。这些插件包括访问存取各种数据库,例如 CouchDB、REST 存储和 Google AppEngine。使用 DM 存取 Google AppEngine 特别有意思,它能够允许开发者创建能够和基于 Google 架构的 JRuby 运行的应用程序。当问到关于这个功能的时候,他说:
我曾经做过一些 dm-appengine-adapter 的外围工作,所以我可能不能提供太多的详细信息。我曾经在一些关于 adapter 的会议上和 John Woodell 讨论过,他在 Google 的 App Engine 项目组工作,他的一些建议影响了 DM adapter API 的开发。
据我所知,它工作得非常好,而且支持大多数 DM 查询系统。从 Google 的角度看,这是一个为 App Engine 开发自有对象映射器的重大胜利,我曾经知道有一个叫做 Bumble 的项目,但迄今为止还没有取得任何实质性的进展。DM 背后有着一个庞大的开发社区以及大量的插件,而且现在唯一的挑战就是开发初始适配器,不过从我所知道的情况来看,并不是非常困难。我非常肯定为特定的存储引擎开发 DM 适配器只需要花费一些时间来编写一个完整的对象映射器。
这让我能够感受到 DM 没有人谈论过的一个优点。每一种存储引擎被加入到 DM 之后,就会有信息被反馈到 DM 的核心开发团队,最后将会反映在下一个版本的适配器 API 中。所以每一个适配器的创建,都意味着未来将能够更容易地加入更多的适配器,从而添加更多功能。例如,有一个在 MongoDB 适配器的项目,它有一些功能不被 DM 支持,但是会影响未来 DM 的开发。这个插件的开发者便帮助 DM 添加了对这些功能的支持。在 Mongo 中内嵌资源等能够使用内嵌值之类的来实现,而且能够和现存的适配器工作的很好。
DataMapper 并不应是仅仅被 Rails 开发者使用,我们还希望能够知道 DM 的目标是哪些类型的开发者:
DM 的目标用户是这样的开发者,尽管也许有的时候 RDBMS 并不是那么适合,但是他们能够意识到,未来大多数应用程序将会和存储结构数据的关系数据库,以及存储非结构化或者可变数据的 NoSQL 数据库绑定在一起。现在关于 RDBMS 和 NoSQL 孰优孰劣的争论是非常愚蠢的。只有在某种特定的应用中才能知道哪个更好,而且大多数的应用程序都需要二者的结合;这不是一个或此或彼的命题。
更多关于 DataMapper 的信息可以参见项目的网站以及其学习手册。
查看英文原文: DataMapper Reaches 1.0 Milestone
评论