服务设计原则

1. 标准化服务合约

1.1 服务合约

  • 建立了与服务交互有关的术语
  • 提供了技术限制和需求,及服务的拥有者希望对外公布的所有语义信息

服务合约

1.2 标准化服务合约

  • 使用形式化或者标准化的合约
  1. 服务功能描述的标准化
  2. 服务数据表示的标准化
  • 提倡尽量保持不同服务之间、在数据总体模型和特定数据类型之间的一致性
  1. 非标准化的服务数据表示将导致频繁的数据转换
  2. Schema 被单独设计和实现,与使用它的服务操作分离
  3. 采用“Schema 集中化”的设计模式,倡导对每个信息集合定义一个“官方”的 Schema
  4. 可以将一个企业划分为多个分离的领域,每个领域都可以被独立地进行标准化和治理
  • 除集中式的 Schema 外,也常常需要提供特定服务相关类型的额外的 Schema
  1. 服务策略的标准化
  • WS-Policy 定义为服务合约添加了一个单独的潜在抽象层次
  • 使得逻辑能以单独的策略断言的形式存在于物理上独立的策略定义文档中
  • 多层次的标准化
  1. 专用的断言词汇
  2. 参数和嵌套策略
  3. 策略的模块化和集中化
  4. 结构化标准
  • 其他的设计原则也会直接影响到合约的定位、设计以及最终的使用

2.3 合约与服务设计

  • 数据表示标准化和转换的避免

在对服务记性集成时,统一的数据结构减少转换环节

  • 标准化与粒度
  1. 标准化带来合适的粒度
  2. 服务级别的粒度通常受到服务模型的选择的影响
  3. 设计标准引入或改变服务操作的粒度
  4. 设计标准引入或改变数据的粒度
  • 标准化服务合约与服务模型
  1. 以不同的标准适应不同的服务模型
  2. 通用类型模板
  • 以实体为核心的服务
  • 应用服务
  • 以任务为核心的服务
  1. 为同一种服务模型应用同一组设计标准和命名惯例
  • 服务合约设计的相关风险
  1. 版本化(服务合约的演化)
  • 服务实施后,就可能建立起与服务消费者之间的依赖关系
  • 底层逻辑越是可复用,那些需要消费它的程度的数量和消费频率就会越大
  • 可扩展可能引入“破坏”既定合约的重大变化,从而导致发布新的服务版本的要求
  1. 技术依赖
  • 不同的编程语言和开发平台来实现
  1. 使用基于构件的系统并通过增强的 RPC 技术以支持面向服务
  2. Web Service 平台以及它的非专用通信框架
  • 操作性系统层的技术性变化导致服务合约变化
  1. 开发工具缺陷
  • 使用开发工具自动生成合约可能产生非标准化的服务合约

2. 服务松散耦合

2.1 服务耦合(服务内及消费者依赖)

  • 关注服务耦合在哪里发生
  • 关注一个服务组合中的各部分之间以及服务内部的各部分之间以及服务内部的各部分之间应该耦合到什么程度

2.2 服务松散耦合原则

服务的生命周期是一直要大于某个服务系统的生命周期。

服务与消费者间的耦合关系

2.3 服务合约耦合的类型

  • “逻辑-合约”耦合(正面的、积极的耦合关系)
  1. 服务逻辑到服务合约的耦合
  2. 合约优先
  • 首先设计合约,然后再设计底层的方案逻辑
  • 允许对底层逻辑进行微调以支持服务合约
  • 底层逻辑的微调能够优化运行效率和增强服务的健壮性
  1. “合约优先”的过程会造成服务逻辑对服务合约的紧密耦合
  2. 服务合约对服务逻辑无耦合,在相同的服务合约下,可以替换服务逻辑
  • “合约-逻辑”耦合(负面的耦合,反模式,应尽可能避免)
  1. 服务合约到服务逻辑的耦合
  2. 从现有的方案逻辑当中生成 Web Service
  • 合约设计中 WSDL 定义根据组件接口的定义自动生成
  • XML Schema 从数据库表和其他数据模型中自动生成
  1. 往往会增加技术、功能和实现的耦合级别
  2. 作为一种“反模式”,缩短服务合约生命周期,并限制服务的长期演化
  • “合约-技术”耦合(不好的耦合)
  1. 服务合约到其底层技术的耦合
  2. 有的时候服务是作为传统专用组件存在的,这就需要服务合约与服务相关的通信技术紧密地耦合
  3. 所产生的“合约-技术”耦合会限制潜在的消费者
  • “合约-实现”耦合(不好的耦合)
  1. 服务合约到其实现环境的耦合
  2. 任何一个物理上发布的服务都会包含或者需要包含除了核心服务逻辑之外的一系列实现技术和产品,比如:
  • 物理数据库和相关的物理数据模型
  • 遗留系统 API
  • 用户和群组账户以及相关的物理目录结构
  • 物理服务器环境和相关的域名
  • 文件名和网络路径
  1. 实现相关的特性和细节可能会在服务合约的内容中体现出来,导致“合约-实现”耦合
  • “合约-功能”耦合
  1. 服务合约到其外部逻辑的耦合
  2. 当由一个服务(更确切地说是一个服务操作)所封装的逻辑被专门设计为支持服务边界之外的功能体的时候,就可能产生“合约-功能”耦合’
  3. 该耦合会导致服务的复用性较差
  4. 常见的“合约-功能”耦合包括
  • 上层进程耦合
  • “服务-消费者”耦合
  • 任务服务(特意的功能耦合)

2.4 服务消费者耦合的类型

  • “消费者-实现”耦合(不好的耦合)
  1. 绕过服务合约,直接使用其他入口访问服务
  • “消费者-合约”耦合
  1. 本质上形成松散耦合跨服务关系的基础
  2. 由于合约与其他因素的耦合关系而产生消费者与其他因素的直接和间接的耦合关系

2.5 服务松散耦合与服务设计

  • 耦合与面向服务:“积极耦合” vs. “消极耦合”
  • 服务松散耦合与粒度:粗粒度 vs. 细粒度
  1. 过粗操作粒度,不必要的额外处理;过细操作粒度,过多服务往返开销。
  2. 过粗数据粒度,接受无用的额外信息;过细数据粒度,没有足够信息,需要额外调用。
  • 耦合与服务模型:实体服务、应用服务、任务服务、编排服务
  1. 实体服务
  • 解耦的服务合约
  • 与业务实体本身高度耦合
  1. 应用服务
  • 往往是高度耦合的(实现耦合)
  • 通过标准化服务合约,避免“消费者-实现”的间接耦合
  1. 任务服务
  • 有时是在功能上耦合的
  • 有时构成“服务-消费者”耦合
  1. 编排服务
  • 避免技术耦合
  • 无法避免“合约-实现”耦合

2.6 服务松散耦合的相关风险

  • “逻辑-合约”耦合的限制
  1. 统一底层逻辑对应两个或者多个合约,从而建立多个入口,每一入口向不同类型的消费者暴露不同的服务能力
  • 数据类型耦合太“松散”
  1. 为了强调服务的兼容性演化能力,通过过分简化合约,追求减少消费者依赖,仅确定了一些非常通用的数据类型(弱类型)
  2. 验证并处理弱类型,增加服务所需的性能要求
  3. 服务合约发布的信息越少,消费者程序就需要知道越多关于服务实现逻辑的信息,从而产生消极耦合

3. 服务抽象(信息隐藏与元抽象类型)

  • 服务发布的信息传达了它的目的和能力,并给潜在用户提供了关于该服务应该如何通过程序进行调用和使用的详细信息
  • 没有发布的服务信息用来保护它和未来用户之间形成的耦合关系的完整新,从而保障服务在合约的前提下进行演化的能力
  • 服务抽象原则就是为了获得信息隐藏的正确平衡点

3.1 服务抽象原则

  • 服务合约中发布的信息越多,随后的“消费者-合约”耦合就会越深
  • 向负责设计服务消费程序的人呈现的信息越多,他们所知的底层逻辑、平台和服务相关的细节就会越多,导致事实上的“消费者-实现”耦合

3.2 服务元信息

  • 元信息类型
  1. 技术信息:描述底层服务逻辑的技术实现
  • 隐藏构建软件程序的技术细节是有益的,从而可以自由地进行技术上的变化而不影响现有的用户
  • 发布
  1. 调用程序需要的技术
  2. 与程序交互需要的技术
  • 隐藏
  1. 写程序使用的编程语言
  2. 程序使用的系统资源
  1. 功能信息:描述服务可以做什么
  • 功能抽象决定了程序的哪些能力通过技术合约是可见的
  1. 程序逻辑信息:描述服务如何实现这些能力
  • 程序逻辑抽象(简称逻辑抽象)故意对外界隐藏程序的内部细节
  1. 服务质量信息:描述服务的行为、限制和交互需求
  • 服务质量数据被用来描述一个服务的行为性的、基于规则的、和可靠性等相关的元信息
  • 比如:
  1. 确保服务及时响应的并发访问阈值
  2. 可用性限制
  3. 决定服务对不同类型输入数据的处理和响应的业务规则
  • 使用策略或 SLA 等文档加以描述
  • 不同类型的元数据可以不同的方法加以抽象,并使用不同的方式来描述和归档

3.3 服务抽象度量

  • 合约内容的抽象级别(有效程度)
  1. 详细的合约(暴露所有信息)
  2. 简明的合约
  3. 优化的合约
  4. 混合的详细合约(服务能力位于不同的抽象级别)
  • 访问控制级别(源代码和设计规格)
  1. 开放访问
  2. 受控访问
  3. 不可访问
  • 抽象级别与服务质量元信息
    服务质量元信息也能够适用于抽象级别和访问控制级别

3.4 服务抽象 VS. 服务封装

  • 封装是指服务边界内部的逻辑、资源和信息(服务由合约及其所封装的东西组成)
  • 抽象是指服务所封装的内容中,暴露给服务便捷之外的消费者程序的部分以及对他们隐藏的部分。抽象决定了封装逻辑中有多少是公开的
  • 在良好抽象的服务中,可以改变所封装的内容,而不会影响已经在使用该服务的消费者程序

服务封装与抽象

  • 封装遗留系统的服务
  1. 抽象的程度可能需要依靠底层服务适配器和相应的遗留 API 来决定
  2. 访问控制可能会很难实现
  • 封装定制组件的服务
  1. 拥有定制的能力使得内容和访问抽象级别能够较好的定义
  • 封装服务的服务
  1. 除了服务本身外,所封装的子服务也对内容和访问抽象级别有所影响

3.4 服务抽象与非技术合约文档

  • 除技术服务合约内容、源代码和设计规格的访问以外,还需讨论对非技术合约文档的抽象

  • 非技术的服务描述(如 SLA)为技术合约增加了额外的规则、约束、策略、保证和担保等,这些文档由服务拥有者建立,并应当被服务消费者程序设计人员所知晓

  • 如非技术的服务描述过于详细(依赖于当前实现),也为影响到服务的演化

3.5 服务抽象与粒度

  • 服务抽象鼓励发布尽可能少的细节,以便在服务随时间而演化的过程中给服务的拥有者最大的自由度,这可能导致粗粒度的约束级别

  • 在使用策略时,可能导致暴露服务底层的逻辑、行为和参数选择的细节

  • 其他的面向服务原则(如服务松散耦合和服务自治)也提倡在服务合约中减少约束

3.6 服务抽象与服务模型

  • 实体服务与应用服务
    抽象程度往往和所封装的定制逻辑
    遗留 API 等密切相关;需要严格的访问控制,以确保服务合约的寿命和底层逻辑的可复用性

  • 任务服务与编排服务
    无法达成过高的抽象级别

3.7 服务抽象的相关风险

  • 多消费者耦合的要求
  1. 不同消费者可能需要不同的技术接口细节,所需的抽象级别也不尽相同
  2. 使用合约反规范化,提供不同界别的抽象级别
  • 认为误判
  1. 过于抽象的服务合约导致曲解或不同充分理解一个服务,从而丧失潜在的复用机会
  2. 过于具体的服务合约导致对服务的行为做出与服务相关的假设,从而导致实现偶合
  • 安全和隐私的考虑
  1. 服务合约可能暴露私有或者敏感信息
  • 不同的使用环境(组织内部 vs. 组织外部)
  • 并发和冗余的服务合约内容已解决这一问题

4. 服务可复用性

5. 服务自治

6. 服务无状态性

7. 服务可发现性

8. 服务可组合性