2007年2月23日星期五

Code is Configuration

Ruby on Rails强调Convention over Configuration,也就是习惯优于配置,这对我来说是一个很有吸引力的特性。.NET是配置优先的(据说Java也是),最好什么都不是硬编码而是可配置的,开发出来的产品最终可以在部署时根据实际情况配置,或者再被调用时按照调用者的需求配置。为什么RoR可以是习惯优于配置呢?如果什么都硬编码了,遇到需要改动的情况怎么办?按照我现在对RoR的理解,思考了一下,寻找到一种可能的解释——RoR的代码也就是配置!

在.NET里面,函数或者是指令,都是描述行为的。一组指令组成一个函数,代表着一组顺序执行的行为;之后一组函数组成一个类,代表着一类行为的聚合。而RoR指令给人的感觉却不是这样,RoR中有些指令完全可以认为是描述性的,就好像配置一样,而且是顺序无关的。

举个例子,创建数据表的migration,你可以认为它是ruby语法写的CREATE TABLE,而且它做的也就是CREATE TABLE,但实际上它是schema!它已经描述了数据表是怎样的了,而不仅仅是生成数据表,生成数据表仅仅是migration执行时瞬时的行为,生成数据表之后Rails自动提供ORM功能,不再需要另外的schema或者自动生成的code来重复描述schema。这正是其符合DRY原则的地方,在整个RoR应用当中,只有migration这一处描述了schema,其它地方均无再次描述schema的地方。然后再对比一下我们在ASP.NET中的做法,重复描述数据表schema的地方实在不少,无论使用哪种ORM工具都如此,希望以后大家都能用上DLinq从而避免这个问题。

再举个例子,model中可以直接用helper函数指定每一个属性要符合的业务逻辑,从而提供验证功能。还记得我们在ASP.NET中这有多麻烦吗?首先,根据决不信任客户端提交原则,在View中要验证数据,验证一方面要能抵御恶意编写的提交,另一方面要对不符合业务逻辑的提交给出反馈,这辛苦了Validator控件,而且我们自己也要写不少代码(如果部分输入设计复杂验证逻辑的话)。接着,业务逻辑层再来一次验证,这是为了业务逻辑层的完备性,在脱离原有表现层而被第三方调用时也能确保数据的合法性。然而在RoR中却不用那么麻烦,在model中一次声明规则就行了,view中输入的数据如果不符合model的规则自然会在view中得到反馈,这种逻辑既是声明性的,又符合DRY原则。

最后,说说ASP.NET可以从RoR学习的规则。首先,MVC分离是有必要的,仅仅垂直分3层是不够的。我之前也有想过,为什么要在表现层提供众多的Validator控件,而不是在业务逻辑层提供验证相关的Helper类呢?这些Helper类,加上业务逻辑层反馈到表现层的通道,就能够做到只需要实现一次验证。或许Validator控件,也是简化表现层设计的一个做法吧,为了吸引别人学习ASP.NET,MS做了很多东西让它看起来很容易用,却让人难以全局协调。其次,一个类象征现实中一类事物的隐语仅仅是针对model的一个说法,其它时候我们更需要函数,类就仅仅是用来聚合函数。例如一条验证规则,这是一条配置,同时也是一个函数调用,需要完成验证这一顺序操作的是函数,而不是类。如果你要用类去表示规则,例如config文件映射出各个ConfigurationSection那样,这就增加了处理步骤,因为最终你还不是把类里面的属性读取出来交给函数处理这条规则。

没有评论:

发表评论