SOA,Service Oriented Architecture,顾名思义是面向服务的架构,整个系统要借助服务的设计来完成建模,因此服务的设计是整个系统中很重要的一环。服务的设计牵涉到两个重要的概念,一个是粒度,一个是耦合。
粒度表示的是一个服务的大小,它可以理解为服务操作的范围,粗粒度的服务,操作的内容广而且杂;细粒度的服务,操作的内容细而且简单。粗粒度的服务设计,可以减小服务之间的耦合性,但付出的代价就是增加服务的复杂性,服务具备了太多的功能,增加了设计的复杂性和维护的难度;细粒度的服务,可以让服务的实现变得简单,但这样会增加服务的数量,服务过细过多,这样必然有一些服务需要组合才能实现一定的功能,那样就增加了服务之间的耦合度,只要其中一个服务发生了变动,势必牵一发而动全身。
耦合代表的是服务与服务之间的关系。SOA的初衷就是为了降低系统各个部分之间的耦合性,使得服务可以重用。但很显然,耦合性是受到服务粒度很大的影响,而且从某种程度上讲,粒度的选择就决定了系统内部的耦合性。
那么应该以什么为准则来确定一个服务的粒度呢?遗憾的是,网上搜索了各种SOA的介绍和各个厂商的文档,似乎找不到一个统一的标准,因为服务粒度往往要根据需求来确定。SOA提倡服务要粗粒度,但这样的说法太笼统,系统必然会有细粒度的服务存在,很多粗粒度的服务不过是一些细粒度服务的组合。所以我的看法是,粗中有细。
我的想法是,把服务分解为三种类型,一种是基本服务,一种是组合服务,一种是合成服务。
基本服务。基本服务即是系统提供的最小粒度的服务,或者说是原子服务。这类服务考虑的是利用它们的可重用性,它们是组成一些较大粒度的服务的基础。基本服务可以说是原有系统跟业务需求细分的中间结合点,它既是原有系统能够提供的最细粒度的服务,同时也是要设计的系统最细粒度的服务。
合成服务。合成服务是基本服务简单的组合,只是为了把具有相同功能但操作不同的业务对象的基本服务组合到一起,形成一个对外提供相同功能的服务。它类似设计模式里面的工厂模式,只要告诉服务接口传进来的是哪一个业务对象,那么服务就能自动识别应该调用哪一个基本服务。
组合服务。组合服务是系统里面最复杂的部分,它不是基本服务的简单堆积到一块,它是最大粒度的服务,里面各个基本服务的关系受到工作流程的控制。它是基本服务与工作流程的结合。
基于上面的理解,我们的服务设计遵循这样的设计思路:先从功能模块分离出基本服务,各个功能模块可以看成是合成服务,由功能模块分离出来的就是基本服务;然后在基本服务的基础上设计组件和业务对象;设计完组件和业务对象之后再来设计组合服务。这样不管组合服务需要多少,组合服务多复杂,都可以通过基本服务和工作流程进行各种形式组合起来。而且组合服务经常需要变动,这样的设计能够保证这些变动不会引起太大的改动。它们的组合关系可以用下面的图来表示。
这样的设计思路也体现了SOA的自顶向下的设计方法:功能模块->服务->组件和业务对象。服务不是凭空想象出来的,它必须要满足客户的需求,而客户需求的体现就是系统要提供的功能,所以功能模块的设计是服务设计的前提。以我们团队这次IBM大赛的方案为例子,我们在理解大赛组委会给出的业务需求外,自己也设想了一些需求,对应这些需求,我们设计了系统的功能模块。不同的业务角色有不同的业务需求,所以功能模块对应不同的角色也就有所不同。下面的图列举的是财务人员所需要的功能模块:
系统功能模块是系统提供的各类服务的编排和合成。在设计完系统的功能模块后,在这个基础上把各个功能模块的服务提取出来,一个功能模块可能由一个服务组成,也可能由多个服务组成。
服务的基础是组件,一些重要的组件能够单独封装成服务。基础服务其实就是一个业务组件,它是基于商务对象的原子操作。它是封装好的组件,它只关心定义好的组件接口,和需要传递的对象,而不关心实现这个操作是如何用代码来实现。业务组件包含两个重要的含义,一个是“操作”,一个是“操作的对象”。组件的设计是基于面向对象的,可以说,它就是一个类,但它只能是一个抽象类,只有定义,没有实现。
基础服务跟合成服务、组合服务之间的关系可以用下面的图来举个例子:
订单处理服务(Order Service)是各种基本服务的组合,基本服务包括产品类别服务(ProdClass Service)、产品库存服务(ProdStorage Service)、客户信息服务(Cust Service)、消息服务(Msg Service)等等。基本服务针对一个特定的业务操作对象,比如客户信息服务处理的是客户信息,它操作的对象就是客户信息,操作就包括新增、修改、删除、查找等等基本操作。订单处理服务包括了各种基本服务,但它不是同时调用这些基本服务,而是必须按照一定的工作流程,比如先新增客户信息,然后再查找产品类别、产品库存,然后再发送消息,这些顺序由工作流引擎来控制。
同步服务(Synchronize Service)是各种基本服务的合成,基本服务包括产品类别服务(ProdClass Service)、产品库存服务(ProdStorage Service)、客户信息服务(Cust Service)等等。相比订单处理它就简单不少,它只需要根据请求调用相应的服务完成操作就可以,没有顺序的要求。
虽然本文描述的只是一种业务场景下的服务粒度的选择,但我想从我们团队的设计经历,可以总结出一种对服务粒度选择的方法,那就是自顶向下,由粗到细,然后再从基础到合成、组合。