领域驱动设计 - 战略设计 - 1/2限界上下文

风流不在谈锋胜,袖手无言味最长。这篇文章主要讲述领域驱动设计 - 战略设计 - 1/2限界上下文相关的知识,希望能为你提供帮助。

DDD理论,笔者感觉最牛的一点就是原作者没有用一行代码但把架构设计理论描述的非常清楚。整套理论并不聚集在技术层面,想要落地DDD实践还需要掌握原作者字里行间对企业文化、组织架构以及协作等方面的理解,同时也需要很长的一段路去试错去探索。这套理论也是笔者读过的N多牛人的著作中唯一当做人文图书来理解的一本技术书籍。
本章的战略设计,是对组织架构与软件架构相互Match的一种落地指导。
在《快速开始》章节笔者对战略设计的解释是这样的:DDD中的战略主体是业务,并不是由公司经营者制定的以运营或管理为目的的那种战略规划。详细来讲是指以业务为核心,合理的设计模型(领域)、划分(限界上下文),再综合组织架构、实现技术等因素辅以相应的集成策略(上下文映射)。
笔者在本节再精简一下,DDD中的战略设计就是指限界上下文,其设计围绕组织间合作模式和应用间所采用的交互技术展开,前者的核心是组织间关系和利益,后者的核心是应用的SLA协议,这两者相互影响与制约,需要在组织架构调整、业务变更时适时演进。但无论怎么变化都要定义清晰边界和契约并可控(这里先不参杂核心域的概念)。
制定战略有时也会分为对外和对外两种策略,在本节中笔者试着从内外两种视角来描述DDD战略的落地精要,其中对外包含限界上下文集成策略、对内包含核心域精炼、大比例设计。可以从两方面来设计战略:规划阶段可理解为是问题空间(尽可能的提出问题,侧重目标和风险),实践阶段会转变为解决方案空间(侧重上下文间的映射和内核的设计,通过源代码和测试代码来表述)。
战略设计原则必须把模型的重点放在系统的概念核心上,着眼于远景,并且在完成目标时又不能为项目带来麻烦。尤其是在DDD应用的探索阶段,务必以团队中多数人的认知水平为基准,切不可加入所谓的政治以及不切实际的KPI目标。
术语
  • 上下文映射:目的是保持模型的完整性,不同系统的模型间很难保持一致,也无法约束采用同一种设计思想。要统一这种差异,最好为每个模型显式定义一个限界上下文,然后相互间的关系,避免模型与模型的耦合与边界不清;
  • 核心域精炼:目的是为核心模型减负,保持大模型的清晰的作用,解决复杂性,减少混乱 ,指导团队注意力聚集到正确的地方,保持大模型的清晰;
  • 大比例设计:目的是保持整个系统设计的一致性,它是一个指标思想,在概念层次上保证方向的一致性,引导团队一直行驶在正确的车道上;
设计要点DDD的战略设计虽然没有企业战略制定过程严苛,但为了更好的软件交付也是需要讲究一些方式方法的,下面是一些经验的总结:
  • 设计是自顶向下的,与组织架构、工作流程相辅,专注业务复杂性而非技术复杂性;
  • 决策必须传达给整个团队,包括但不局限于业、产、研同学;
  • 决策过程必须收集反馈意见,事前可采用脑暴的方式、事后可以通过技术人员轮职后效果分析以及数据分析;
  • 遵守简约和谦逊的原则;战略是一个指导思想,越简约超容易理解;
  • 必须允许演变,软件开发是一个高度动态的过程,要适时制定和删减规则;
  • 没有必要把所有最好的人吸收进来;
  • 负责设计的架构师一定要了解业务同时要下沉到开发团队中去,否则可能会使架构师专注于自己的职责迷失方向,产生过度的设计为开发人员制造障碍;
  • 落地过程中,架构师与开发同学需要转换角色,比如开发人员需要处理架构,架构师也要写应用代码,这种无序有时很容易造就高效率的输出;
限界上下文集成        任务一个大型项目都会存在多个模型,而当不同模型的代码被组合到一起后,就会出现bug进而使软件变得不可靠和难以理解,因此明确地定义模型所应用的上下文。根据团队的组织 、软件系统的各个部分的用法及物理表现来设置模型的过界。在这些边界中严格保持模型的一致性,而不要受到边界之外问题的干扰会变的格外重要。
持续集成      
    宏观来讲持续集成由模型概念集成和实现集成两部分组成,前者为实现集成扫清了道路,后都验证了模型的有效性和一致性。
上下文粒度
    当多人在同一个限界上下文中工作时,通常会把大的上下文进行拆分,伴随着也会带来模型的分裂、重复功能等风险,同时团队担心会破坏现有功能不敢去改动。所以建议在划分上下文时一定要先同时制定持续沟通机制以及自动化测试方案。
集成策略
受组织架构的影响,不同团队的边界通常由组织结构和利益来决定,理想的情况一般不会出现。能做的就是评估这些决策的代价,并反映给管理层,以便采取相应的解决方案来减少成本和风险。下面是归纳总结的一些团队间合作的集成策略:
共享内核shared kernel适用场景:当团队规模比较大时,迭代过程中有时会因为沟通不够导致模型概念不一致,最终需要在模型的转换上花费大量时间,有时受沟通成本的制约。会选择这种折衷的方案。其实笔者不建议用这种方式,即使是在同一个团队内部。
实施建议:从领域模型中选出两个团队都同意共享的一个子集,通过协商的方式缩小范围。这个子集通常是core domain或是generic subdomain。
共享方式通常有两种:.jar包共享或是.git代码库共享,以一方为主,通过流程的技术手段来代替契约方声进而把控质量,比如github的代码共享机制(请求、代码审查、发版公告)。采用共享代码或数据时格外谨慎如果,当多个系统的模型组合到一起有可能会引起重复的概念,即两个模型元素实际上表示同一个概念,最终导致一次变化修改多处或是同一个概念存在两个不同的版本。
注意事项:跨团队可能存在交叉影响,依赖高度的承诺,合作时注意时效性,因为长久的稳定合作关系很难维护;另外,这种关系往往是建立在人脉和利益的基础上。这也是笔者不建议这种集成策略的另一个原因。
供应商customer/supplier team适用场景:比较常见,单向依赖的上下游系统,两个团队之间必须建立一种明确的客户/供应商关系,双方高度协同。由供应商主导,在工作时一般会采用CDC方式即消费者驱动契约,即客户按自己的预期测试供应商的接口,辅助供应商升级。
实施建议:
  • 针对供应商:定期招开计划会议,根据下游团队的需求来协商需要执行的任务并为这些任务做预算,以便每个人都知道双方的约定和进度;
  • 针对消费方:开发自动化测试程序,用来验证预期的接口;如果能把这些测试添加到上游团队的测试套件中,作为其持续集成的一部分来运行就可以避免上游团队在做出修改所产生的副作用;
注意事项:供应商一般是通过协商来平衡下游团队的述求的,同一业务的供应商团队必须是同一个管理者;
跟随conformist       适用场景:这种模式的应用通常在两种情形下会出现:1、要集成的系统是一个相当成熟的模型;2、要集成的系统是一个相当烂的模型但部门权力非常大。
原因是,当两个团队从属不同的领导者时,如果上游团队没有动机来满足下游团队的需求,那么下游团队将无能为力。出于利他主义的考虑,上游开发人员可能会做出承诺,但不会履行。下游团队出于良好的意愿也会相信这些承诺,从而根据一些永远不会实现的特性来制定计划,但是下游的项目只能被搁置。直到团队学会利用现有条件自力更生为止,下游团队不会得到根据他们的需求而量身定做的接口,过程中下游团队只能选择跟随。
注意事项:这种策略是一把双刃剑,跟随者可以利用上游现有的资源达成自己的目的,但下游系统充其量只能做一些简单的增强,上游规则变化时也不会与自己协商,比较被动,比如app store和developer之间就是一种跟随;
分离模型separate way        集成多数情况下意味着折衷,会破坏原有自的专用性。在集成的代价与收益不对等时,如果二者可以完全分开,就没有必要进行集成了。
这个模式阐明的是价值产出,可基于相互之间互联是否有价值来评判,如果集成的价值不大就不如独立发展。在设计时需要明确这种关系,防止实施过程中由于监控不到位而发生耦合关系,前期做为战略的一种重点提醒。
防腐层 Anticorruption Layer      
        防御性集成,隔离外部不断变化的环境。它是转换层功能的一个增强,用于解决、兼容老系统或不同模型系统对接引起的模型不一致问题。防护层是在不同的模型和协议之间转换概念对象和操作的机制。通常是以一组service的形式出现,每个service履行单一职责。可以使用Facade或Adapter这两种设计模式。Facade适合在上游系统中采用,Adapter适合在下游系统中使用。然后把所有的转换委托给转换器来完成。
      条件允许的话,在应用间集成时都要加上防腐层,尤其是大型的分布式系统。甚至可以采用零信任模型来开发。
集成技术选型
相对于说在战略设计中讲技术实现可能略显不太合适,但从笔者的经验来看,在策略设计时是有必要对集成技术进行仔细考量的,参考下面场景:
pc端应用,为了操作方便方便通常会在列表(table)页每一行的最后列单元格中放置若干操作按钮,点击按钮执行特定的业务操作,然后刷新列表,这种设计很常见。如果列表数据对时性要求比较高,我们最好采用同步调用集成,如果上游只能提供mq这种集成方式,那么在集成时就必须考虑mq的延时特性是否能满足业务需求了;
分布式系统中,应用间交互常用的会有以下几种:Soap、Restful、Mq、PL,这四种技术方案在安全性、性能、可靠性等方面表现各不一样。设计者需要结合业务要求选择与之匹配的集成技术。每种技术的细节网上有很多更详细和专业的解释,本文中不再详细展开,笔者在最后稍解释下两个概念:
  • OHS:开放主机服务(open host service),soap、restful、mq都属于此类集成方案,选择此方案时服务方有必要提供必要的文档、友好的协议、以及版本的兼容性;
  • PL:已发布语言(publish language),可以理解为共享数据源,不同的业务方可基于共享数据进行翻译;

      如果说限界上下文侧重的是对外策略,那么下面所讲述的核心域精炼和大比例设计更多是针对内部团队而言,各自阐述了一些方法统一团队内部对设计过程中有可能遇到的一些开放性问题的收敛策略。
【领域驱动设计 - 战略设计 - 1/2限界上下文】END,后续章节会介绍下战略设计的核心域提炼和大比例模型相关的知识

    推荐阅读