微信号:infoqchina

介绍:有内容的技术社区媒体

采访Service Stack的项目领导Demis Bellot——第1部分

2013-11-21 18:49 InfoQ

ServiceStack是一个开源的、支持.NET与Mono平台的REST Web Services框架。InfoQ有幸与Demis Bellot深入地讨论了这个项目。在这篇两部分报道的第1部分中,我们主要谈论了ServiceStack项目建立的原动力,以及项目中的各种设计方案选择。


InfoQ: 你是否认为微软对服务的实现方式有什么问题?ServiceStack又是怎样解决这些问题的呢?


Demis: 有一些问题是由于微软一直以来自认为良好的框架设计的方式所造成的常见问题,另一些问题的根源是由于微软的设计总是倾向于满足设计器优先的工具,并且试图为使用设计器作为向导的开发者提供一套熟悉的API,而这种设计倾向造成了一些副作用:

  • 在服务API设计时提倡用C#进行远程过程调用(RPC)的方法调用,这导致了非常细粒度(chatty)的设计,并且产生了许多特定于客户端的API。

  • 企图将脆弱的、臃肿的、低效并且过于复杂的SOAP以及WS-*序列化格式进行标准化。

  • 试图通过繁重的人为抽象、UI设计器以及各种大型工具达到简化终端用户开发的目的。

  • 为了尝试给开发者展现一个人为定制的服务端对象模型,创建了繁重的抽象API。

  • 试图通过一个共享的抽象对象模型将所有网络终结点(endpoint)统一起来。

  • 过度使用XML配置与代码生成。

  • 没有预先考虑可测试性与性能。


RPC方法签名

由于微软过于追求为开发者提供一套熟悉的RPC API,并在VS.NET中提供丰富的UI工具(例如“添加服务引用”对话框)以保证上手的简易性,其代价就是推广了远程服务中的各种反模式,从长期来看将导致不必要的不协调与脆弱性。不幸的是,微软长期以来在其发布的每个web service框架中都持续使用这种设计方式,这种方式提倡创建RPC服务API的设计方式,造成了开发者在意识中将远程服务也当作本地方法一样调用。这种结果的害处是多方面的,远程服务意味着它包装了一个外部依赖,对它的调用要比本地方法慢上几百万倍,并且更容易受外界的影响而发生错误。将隐式的服务契约与服务端RPC方法签名绑定在一起,就意味着你的API服务契约和服务端的实现紧密耦合在一起了。由于没有规定一个定义良好的边界,导致了糟糕的关注分离,并且出现了将繁重的ORM数据模型通过网络返回给客户端的糟糕实践。从定义上来说,这种数据模型的关系型结构与循环式关系对于数据迁移对象(DTO)来说并非一种好的选择,它使调用可能偶尔会失败。这种方式还将隐式的服务契约与你的底层关系型数据库(RDBMS)数据模型耦合在一起,这样在进行修改时就会产生额外的冲突。而且远程API与调用它们的服务端网站是无连接的,而这些调用的方法在客户端代理部署后也会不断地演化。理想的框架应该能够提倡可演化的、灵活的API设计,以避免在服务端改变时产生运行时错误。


这些有一张关于WCF提倡的细粒度的RPC API方式与ServiceStack所鼓励的基于消息的API方式的不同之处的对比图。此外,这个用ServiceStack重写Web API的入门教程的示例则展示了基于消息的API如何减少细粒度调用,增加了服务的可重用性。


ServiceStack采用了Martin Fowler所推荐的远程服务最佳实践,因此避免了之前困扰着.NET web service开发者的很多潜在问题:


远程门面

远程门面提倡使用基于消息的、粗粒度的批量调用接口。它能够将通信次数减至最低,并促进了创建更少但是可用性更好、并且支持版本化的服务接口。ServiceStack采取了基于消息的设计确保开发者始终创建粗粒度的API设计。


数据迁移对象(MSDN)

数据迁移对象要求使用特定用途的POCO以创建web service响应的数据格式。ServiceStack一直鼓励使用DTO,它本身与它的实现完全解耦,并且存在于一个没有外部依赖也不需要具体实现的程序集中。这种策略允许将定义服务端的服务类型共享给所有.NET客户端,因而提供了一个端到端的类型化API,并且无需使用代码生成。


网关(Gateway)(MSDN)

网关的作用是将所有服务端通信包装起来,隐藏在一个显式定义并且可重用的客户端网关之后。这种最佳实践和代码生成的代理(例如WCF)有所不同,后者将代码生成的类型与底层的服务客户端揉合在一起,使得生成结果难以模拟(mock)、测试以及替换为不同的实现,也经常导致对现有服务的改变会造成客户端代码的编译错误。这一点对ServiceStack来说很少会成为问题,因为它能够重用通用的服务客户端,因此在接口方面唯一需要改变的东西仅限于类型本身而已。并且由于基于消息的设计的优势,无论新增或移除任何功能都不会影响到现有的客户端。


ServiceStack在它的通用并且可重用的类型化.NET服务客户端采用了网关模式。我们同时支持Silverlight、JavaScript、Dart甚至是MQ(消息队列)的客户端。让所有.NET服务客户端都共享相同的接口,这使测试(通过注入或者写日志方式)变得简单,而且能够方便地在JSON、XML、JSV、MessagePack以及ProtoBuf等现有的客户端之间进行切换,而无需改动应用程序的代码。这就允许你在开发时使用类似于JSON这样便于调试的文本格式,随后在部署构建时切换为使用.NET上速度最快的二进制格式,例如Message Pack或ProtoBuf,以降低数据传输量并实现最高的性能。


更多精彩内容,请阅读原文。

***********************************

本文来自InfoQ微信公众账号:infoqchina

1、回复“今日新闻”,查看今天更新的新闻;

2、回复“今日英文”,查看今天英文站的更新;

3、回复“文章 +关键词”,搜索关键词相关内容;

4、回复“QCon”,了解QCon大会相关信息;

5、回复“活动”,了解最近InfoQ组织的线下沙龙;

6、回复“架构师”,获取《架构师》下载地址;

7、回复“投稿”,了解投稿和加入编辑团队的流程。

***********************************

 
InfoQ 更多文章 Facebook如何实现PB级别数据库自动化备份 学术派Google软件工程师Matt Welsh谈移动开发趋势 Spotify为什么要使用一些“无聊”的技术? 妹纸们放假了,汉纸们做啥? 大多数重构可以避免
猜您喜欢 2014年最值得关注的开源项目排行 Visual Studio 2015的Web扩展包 java程序员面试交流秘籍 阿里聚安全受邀参加2016中国网络与信息安全大会,分享互联网业务下的新安全体系构建 Android设计模式之单例模式