论坛首页 编程语言技术论坛

关于REST的一点想法,欢迎大家讨论。

浏览 70986 次
该帖已经被评为精华帖
作者 正文
   发表时间:2007-04-11  
这阵子正打算用Rails做个东东,所以开始系统地学习起了Rails。巧合的是,大概两周前,dlee邀请我加入Fielding博士关于REST的那篇论文的翻译团队。可以说Rails和REST这两个最热门的词汇几乎同时挤入了我的生活。随着我对Rails的学习和对[Fielding]的翻译,我也开始对REST产生了一些不太成熟的想法,写在这里与大家分享,同时也起到抛砖引玉的作用,欢迎大家讨论。

先复习一下REST的基本思想。[Fielding]把REST形式化地定义为一种架构风格(architecture style),它有架构元素(element)和架构约束(constraint)组成。这些概念比较晦涩难懂,而且我们做工程的往往并不需要形而上的理解。我们只知道,REST是一种针对网络应用的设计和开发方式,可以降低开发的复杂性,提高系统的可伸缩性。REST提出了一些设计概念和准则:
  1. 网络上的所有事物都被抽象为资源(resource);
  2. 每个资源对应一个唯一的资源标识(resource identifier);
  3. 通过通用的连接器接口(generic connector interface)对资源进行操作;
  4. 对资源的各种操作不会改变资源标识;
  5. 所有的操作都是无状态的(stateless)。
对于当今最常见的网络应用来说,resource identifier是url,generic connector interface是HTTP,第4条准则就是我们常说的url不变性。这些概念中的resouce最容易使人产生误解。resouce所指的并不是数据,而是数据+特定的表现形式(representation),这也是为什么REST的全名是Representational State Transfer的原因。举个例子来说,“本月卖得最好的10本书”和“你最喜欢的10本书”在数据上可能有重叠(有一本书即卖得好,你又喜欢),甚至完全相同。但是它们的representation不同,因此是不同的resource。

REST之所以能够简化开发,是因为其引入的架构约束,比如Rails 1.2中对REST的实现默认把controller中的方法限制在7个:index、show、new、edit、create、update和destory,这实际上就是对CURD的实现。更进一步讲,Rails(也是当今大部分网络应用)使用HTTP作为generic connector interface,HTTP则把对一个url的操作限制在了4个之内:GET、POST、PUT和DELETE。

REST之所以能够提高系统的可伸缩性,是因为它强制所有操作都是stateless的,这样就没有context的约束,如果要做分布式、做集群,就不需要考虑context的问题了。同时,它令系统可以有效地使用pool。REST对性能的另一个提升来自其对client和server任务的分配:server只负责提供resource以及操作resource的服务,而client要根据resource中的data和representation自己做render。这就减少了服务器的开销。

既然REST有这样的好处,那我们应该义无反顾地拥抱它啊!目前一些大牛(像DHH)都已经开始投入到了REST的世界,那我们这些人应该做什么或者说思考写什么你呢?我觉得我们应该思考两个问题:
  1. 如何使用REST;
  2. REST和MVC的关系。
第一个问题假设REST是我们应该采用的架构,然后讨论如何使用;第二个问题则要说明REST和当前最普遍应用的MVC是什么关系,互补还是取代?

我们先来谈谈第一个问题,如何使用REST。我感觉,REST除了给我们带来了一个崭新的架构以外,还有一个重要的贡献是在开发系统过程中的一种新的思维方式:通过url来设计系统的结构。根据REST,每个url都代表一个resource,而整个系统就是由这些resource组成的。因此,如果url是设计良好的,那么系统的结构就也应该是设计良好的。对于非高手级的开发人员来说,考虑一个系统如何架构总是一个很抽象的问题。敏捷开发所提倡的Test Driven Development,其好处之一(我觉得是最大的好处)就是可以通过testcase直观地设计系统的接口。比如在还没有创建一个class的时候就编写一个testcase,虽然设置不能通过编译,但是testcase中的方法调用可以很好地从class使用者的角度反映出需要的接口,从而为class的设计提供了直观的表现。这与在REST架构中通过url设计系统结构非常类似。虽然我们连一个功能都没有实现,但是我们可以先设计出我们认为合理的url,这些url甚至不能连接到任何page或action,但是它们直观地告诉我们:系统对用户的访问接口就应该是这样。根据这些url,我们可以很方便地设计系统的结构。

让我在这里重申一遍:REST允许我们通过url设计系统,就像Test Driven Development允许我们使用testcase设计class接口一样。

OK,既然url有这样的好处,那我们就着重讨论一下如何设计url。网络应用通常都是有hierarchy的,像棵大树。我们通常希望url也能反映出资源的层次性。比如对于一个blog应用:/articles表示所有的文章,/articles/1表示id为1的文章,这都比较直观。遗憾的是,网络应用的资源结构永远不会如此简单。因此人们常常会问这样一个问题:RESTful的url能覆盖所有的用户请求吗?比如,login如何RESTful?search如何RESTful?

从REST的概念上来看,所有可以被抽象为资源的东东都可以使用RESTful的url。因此对于上面的两个问题,如果login和search可以被抽象为资源,那么就可以使用RESTful的url。search比较简单,因为它会返回搜索结果,因此可以被抽象为资源,并且只实现index方法就可以了(只需要显示搜索结果,没有create、destory之类的东西)。然而这里面也有一个问题:search的关键字如何传给server?index方法显然应该使用HTTP GET,这会把关键字加到url后面,当然不符合REST的风格。要解决这个问题,可以把每次search看作一个资源,因此要创建create和index方法,create用来在用户点击“搜索”按钮是通过HTTP POST把关键字传给server,然后index则用来显示搜索结果。这样一来,我们还可以记录用户的搜索历史。使用同样的方法,我们也可以对login应用REST,即每次login动作是一个资源。

现在,我们来复杂一些的东东。如何用url表达“category为ruby的article”?一开始可能想到的是/category/ruby/articles,这种想法很直观。但是我觉得里面的category是不需要的,我们可以直接把“/ruby”理解为“category是ruby”,也就是说“ruby”出现的位置说明了它指的就是category。OK,/ruby/articles,单单从这个url上看,我们能获得多少关于category的信息呢?显然category隐藏在了url后面,这样做到底好不好,应该是仁者见仁,智者见智了。对于如何表达category这样的东西,我还没想出很好的方式,大家有什么好idea,可以一起讨论。

另外还有一种url形式,它对应到程序中的继承关系。比如product是一个父类,book和computer是其子类。那么所有产品的url应该是/products,所有书籍的url应该是/books,所有电脑的url应该是/computers。这一想法就比较直观了,而且再次验证了url可以帮助我们进行设计的论点。

让我再说明一下我的想法:如果每个用户需求都可以抽象为资源,那么就可以完全使用REST。

由此看来,使用REST的关键是如何抽象资源,抽象得越精确,对REST的应用就越好。因此,如何改变我们目前根深蒂固的基于action的思想是最重要的。

有了对第一个问题的讨论,第二个问题就容易讨论多了。REST会取代MVC吗?还是彼此是互补关系(就像AOP对于OOP)?答案是It depends!如果我们可以把所有的用户需求都可以抽象为资源,那么MVC就可以推出历史的舞台了。如果情况相反,那么我们就需要混合使用REST和MVC。

当然,这是非常理想的论断。可能我们无法找到一种方法可以把所有的用户需求都抽象为资源,因为保证这种抽象的完整性(即真的是所有需求都可以)需要形式化的证明。而且即使被证明出来了,由于开发人员的能力和喜好不同,MVC肯定也会成为不少人的首选。但是对于希望拥抱REST的人来说,这些都没有关系。只要你开发的系统所设计的问题域可以被合理地抽象为资源,那么REST就会成为你的开发利器。

所以,所有希望拥抱REST的朋友们,赶快训练自己如何带上资源的眼镜看世界吧,这才是REST的核心所在。
   发表时间:2007-04-11  
通过URL来设计系统,这绝对是一个令人感到新鲜有趣的话题,很棒的分析,我很喜欢。

目前RoR的REST实现实际上就是REST和MVC混合方式,从实际开发角度来说,正如作者所言,很多情况难以进行资源的抽象。不过,即便如此,已经足够有革命性的意义了。
0 请登录后投票
   发表时间:2007-04-12  
REST与Ajax的结合也是个很吸引人的话题,试想由RESTful的服务端API与客户端的ajax技术的相互调用,能够产生什么样的场景?很想听听大牛的看法。
0 请登录后投票
   发表时间:2007-04-12  
robbin以前说过REST能让代码减少到很少的程度(具体到多少忘了)。现在看来似乎有点言过其实。REST远没有想像中的那么强大。在我看来,如果采用纯REST架构的话,所谓的resource就是经过阉割的OO模型,只有属性,没有行为。为了表现这些被切掉的行为,我必须凭空再造出一个个所谓的resource来,切掉的行为越多,要造的就越多。这样的话,代码不可能有数量级的减少。再想一下,仅仅为了漂亮的URL,放弃自然和符合人类思维习惯的OO模型,这样真的值吗。套用T1同学的话来说:辛辛苦苦几十年,一夜回到了解放前。
所以我认为,REST只是在异构系统之间的webservice通讯上有优势,其他时候,还是该匝地匝地比较好。
0 请登录后投票
   发表时间:2007-04-12  
yuxie 写道
robbin以前说过REST能让代码减少到很少的程度(具体到多少忘了)。现在看来似乎有点言过其实。REST远没有想像中的那么强大。在我看来,如果采用纯REST架构的话,所谓的resource就是经过阉割的OO模型,只有属性,没有行为。为了表现这些被切掉的行为,我必须凭空再造出一个个所谓的resource来,切掉的行为越多,要造的就越多。这样的话,代码不可能有数量级的减少。再想一下,仅仅为了漂亮的URL,放弃自然和符合人类思维习惯的OO模型,这样真的值吗。套用T1同学的话来说:辛辛苦苦几十年,一夜回到了解放前。
所以我认为,REST只是在异构系统之间的webservice通讯上有优势,其他时候,还是该匝地匝地比较好。
OO与REST之间是存在思想层面的冲突的。

意识到这一点之后,我更欣赏REST了。
1 请登录后投票
   发表时间:2007-04-12  
设计理念比较新,
但是把这么很多复杂的标识都交给URL来完成,是不是有点儿赶鸭子上架的感觉。

0 请登录后投票
   发表时间:2007-04-12  
庄表伟 写道
yuxie 写道
robbin以前说过REST能让代码减少到很少的程度(具体到多少忘了)。现在看来似乎有点言过其实。REST远没有想像中的那么强大。在我看来,如果采用纯REST架构的话,所谓的resource就是经过阉割的OO模型,只有属性,没有行为。为了表现这些被切掉的行为,我必须凭空再造出一个个所谓的resource来,切掉的行为越多,要造的就越多。这样的话,代码不可能有数量级的减少。再想一下,仅仅为了漂亮的URL,放弃自然和符合人类思维习惯的OO模型,这样真的值吗。套用T1同学的话来说:辛辛苦苦几十年,一夜回到了解放前。
所以我认为,REST只是在异构系统之间的webservice通讯上有优势,其他时候,还是该匝地匝地比较好。
OO与REST之间是存在思想层面的冲突的。

意识到这一点之后,我更欣赏REST了。


愿闻其详。。。
难道在Web层,单独造出一种非OO的东东反而更好?那样的话,web层跟业务层是否要再加一个 resource-object Mapping?
0 请登录后投票
   发表时间:2007-04-12  
但是我觉得REST有点类似于把数据库table直接暴露出来的意思,而把应用逻辑编程任务交给了调用者。灵活是灵活,但实际上只是转移了代码的位置,而不是把它们封装在下面。一个(或一组)应用是否合适使用REST,还是要看具体情况。

我说得不对的地方,还请指正。
0 请登录后投票
   发表时间:2007-04-12  
robbin 写道

通过URL来设计系统,这绝对是一个令人感到新鲜有趣的话题,很棒的分析,我很喜欢。

谢谢夸奖。
robbin 写道

目前RoR的REST实现实际上就是REST和MVC混合方式,从实际开发角度来说,正如作者所言,很多情况难以进行资源的抽象。不过,即便如此,已经足够有革命性的意义了。

我觉得Rails采用REST混合MVC来实现REST是目前的必然选择。我们大家都已经熟悉了OO和MVC,对于REST这样一个新鲜事物,肯定会带着以前的眼镜去看。随着时间的推移,REST的思想和应用会逐步成熟,人们对其理解也会越来越深刻。到那时才能真正看出REST能不能、如何完全走出MVC。

我们在使用UP开发方法时,往往需要识别系统的model和use case。有些书中教我们把用户需求中的名词抽象为use  case,而动词则是use case。现在对REST建模有着同样的问题:我们可以很直观地把名词抽象为resource,但是很难处理动词。而MVC恰恰适合于处理动词。这也许就应了一个老生长谈的思想,没有什么技术是可以覆盖所有方面的,只有适当地混合使用各种技术、扬长避短,才会获得最好的效果。
0 请登录后投票
   发表时间:2007-04-12  
dennis_zane 写道

REST与Ajax的结合也是个很吸引人的话题,试想由RESTful的服务端API与客户端的ajax技术的相互调用,能够产生什么样的场景?很想听听大牛的看法。

目前我还想想不出REST加Ajax会产生什么样令人震撼的场景。REST的核心是resource,而我觉得对resource的操作最后肯定是通过传统HTTP请求发送到server端的。比如写一篇blog文章,无论如何利用Ajax,最后应该用传统的HTTP POST请求发送到server以便保存。

REST和Ajax的一个比较有趣的关系是,Ajax也许可以帮助我们解决resource难以建模的问题。就像我说过的那样,对名词的抽象很直观,但是动词就比较难办。而Ajax正好可以用来处理这些动词,同时保证url不变。当然,如何使用Ajax处理这些动词也是一个可以讨论的话题,我这里只是说有这个可能性。不过话说回来,即便使用Ajax处理动词的话,如何设计Ajax请求所发送到的url仍然是一个问题。目前来看,最可能的设计还是MVC形式的。所以一个可能的测量是:对所有名词使用REST架构,对动词尽量使用Ajax实现的MVC。这样至少可以保证url看起来是RESTful的。
0 请登录后投票
论坛首页 编程语言技术版

跳转论坛:
Global site tag (gtag.js) - Google Analytics