从DDD看企业级问题解决方案框架
共 4592字,需浏览 10分钟
·
2021-05-19 12:15
写在前面
最近在考虑如何用最新的一些技术理念,解决企业级业务的问题。怎么理解呢?简单的来说就是区分于原有的微服务、分布式、SOA这些东西,这些东西在企业级维度落地后,必定还是割裂的。我想做的这种企业级解决方案是真正可以站在BU或部门角度解决问题的,这些方案问题的解决是:部门--组织--技术小组的方式,技术所处简单的解决研发小组的技术问题,中间完全通过部门之间割裂了。我在想有没有一种方式可以变成:部门--框架--技术小组,这样可以进一步剥离组织与技术,边界更加清晰。
那企业或部门关注什么问题呢?简单来说三方面:
是否可以提升人效,降低整体成本
是否可以指导系统快速适应组织架构与业务架构的变化,就是技术架构与业务同频进化,保证技术与业务不脱节
是否可以促进产研融合,为业务的共同愿景发力
DDD可以解决吗?
之前的文章多次提到了DDD,DDD帮助理清模型边界,帮助业务更准确的定义和理解,进而实现架构的敏捷开发、持续发展。
当然DDD并不存在最佳实践,大家也不要花太多的功夫去找这个最佳实践,还是花时间了解自己的业务,掌握业务的本质及发展,以技术角度落地解决业务问题就ok。
这种适配包含两部分:
适配业务的迭代与发展,业务技术同频
适配组织的变化,边界清晰,协作高效
其实这两部分有一些相似之处,比如业务之所以发展的越来越难以理解,是因为我们对业务本质上缺少抽象,看到的都是型,型可能因为品类、场景、阶段有不同的变化,光看型就很难搞,再说型只是你看见的,不代表他就应该是这个样子。
组织变化一个道理,组织的变化可以理解为是一拨人去负责应新的业务,为什么会显得杂乱无章?因为人员变动,产研双方都需要重新理解业务、梳理业务,不能很快找到这个业务的技术脉络,找不到业务达成业务领域一致性的认知,看代码这个成本就巨大了。
怎么解决呢?
需要建立一种产研一致的愿景,共同设计与达成战略的习惯,结合事件风暴反复去做,慢慢落地。
同时可以借助工具:
事件风暴管理工具:将事件风暴的结果存储起来,保证结果可分多版本保存,提高了事件风暴的质量,提高DDD实践的成功率
API标准工具:通过领域重塑了业务,划定了业务边界,需要做的就是保证领域不被外部入侵,可以通过标准化的API方式,保证API对上下文边界的隔离性,防止被入侵
交付流程标准工具:光靠工具意义比较小,需要在协作方式上做标准控制,比如重视设计工作,细化设计流程,增加产研理解一致
DDD的开展
首先要看清业务,一般需要提供一个业务全景地图或是产品愿景和服务蓝图,画出产品的核心领域、支撑领域、通用领域。
可以参考运营操作大图、用户行为路径图、售前售中售后图等进行细分领域。再考虑下业务的目标,比如打造易用、灵活的xxx功能,结合以上两点就可以很清晰的看清业务的核心、支撑、通用了。
DDD包含战略设计、战术设计、技术实现三个部分。
战略设计侧重于高层次、宏观上去划分限界上下文,而战术设计则关注使用建模工具来细化上下文,通过领域模型来表达业务。技术实现主要通过分层架构来隔离领域模型代表的业务逻辑和技术细节。
一个整体过程大致包括:宏观划分各领域 → 领域内划分限界上下文,定义上下文之间的关系 → 上下文内分析业务,识别领域概念,定义合适的领域概念 → 通过分层架构实现编码,并验证领域模型的合理性,必要时重新回到前面步骤重构领域模型。
战略设计
战略设计是团队领导层或业务负责人关心的,该步骤需要针对产品愿景、业务要解决的问题域,规划核心域、通用域、支撑域,做合适的资源投入。
领域代表了特定的问题域集合,比如销售领域、营销领域。限界上下文是解决方案的显示边界,边界里面全是这个领域的相关概念,这些概念在限界之外不复存在。
这个领域归类有些像金字塔原理的MECE原则。当然还需要结合技术、业务、团队等情况,考虑相关性语义,团队粒度剪裁等。
战术设计
建模就是设计的过程,建模的过程就是梳理、走查业务逻辑,拆解为要解决的问题和涉及的业务场景、业务流程、业务概念,在这个过程中形成对应的领域概念。
如果团队对于业务比较陌生适合采用事件风暴方法进行梳理;如果团队对业务比较熟悉,如果业务流程相对简单,则可以采用四色建模法进行业务梳理。采用这些分析业务的方法可以保证产研团队对业务逻辑的理解在一个水平上。
为了解决业务逻辑衔接的问题引入了统一语言。每个业务名词的含义具有明确的定义,产品和研发都统一认识。没有统一语言的沟通严重缺乏效率。比如CRM线索的概念,没有统一语言的时候每个人的理解不一样,有的人理解为有过咨询记录的访客是线索,有的人理解为留下过联系方式的访客是线索,有的人理解为有购买意愿的访客是线索等等。
有了统一语言描述,每个概念就有了明确定义,可以节省非常大的沟通交流成本。并且这个概念也同样应用在相关的需求文档、设计文档、代码编写中。每个概念从引入到日常交流,从需求文档到代码实现都有了一致的表达,代码实现和需求描述的真实度高,可理解性和可维护性就变好了。
技术实现
分层架构
为了让代码实现围绕领域模型开展,尽量降低业务代码和纯技术选型代码的耦合,DDD引入了分层架构。确保了最核心的领域层不依赖其他层,反过来让领域之外的代码依赖领域代码,降低了技术升级带来的影响。
DDD框架
框架内定义不同领域概念需要实现的接口,比如实现了聚合根接口的实体类就成为了聚合的根实体。定义了异常管理规范,不同的分层应该抛出什么类型的异常。定义了数据访问的资源库接口等等。
领域事件
领域事件是对领域内发生的活动进行的建模,即聚合内的实体状态变化的一个载体。
基于事件风暴的结果,需要把领域名词和规则等划分到合适的限界上下文。
还需要看业务逻辑的复杂程度,还要结合团队规模大小。由于线索功能包含很多业务逻辑,线索归集和创建、线索的分配、线索的跟进等都可以成为一个独立的限界上下文。
定义好限界上下文后还需要定义不同限界上下文的协作关系。一般情况下如果业务允许的情况尽量选择通过领域事件来协作。根据《领域驱动设计》所述常见的协作关系还包括开放主机服务(即通过暴露接口)、共享内核、防腐层等9种。微服务架构下的限界上下文之间的关系比较常见的有领域事件、开放主机服务、防腐层等。
DDD提倡限界上下文间尽量解耦,尽可能使用发布订阅领域事件的协作模式进行上下游解耦。
更多细节在下面介绍。
落地过程
由于企业级业务本身也非常复杂,不适合直接开始做事件风暴。所以首先要做好顶层设计,从划分子域开始,确定好中台业务边界,然后开展事件风暴,再划定限界上下文,完成领域建模,是一个自上而下的过程。
DDD落地整体上有四个关键阶段:领域分解,领域建模,微服务设计,详细设计及技术实现。
领域分解
基于企业级业务域完成从领域到子域的分解,完成子域属性的定义,确定哪些子域是通用域,哪些是核心域。
领域建模
基于上一阶段产生的核心子域和通用子域,采用事件风暴工作方式,划分限定上下文,完成领域建模。这个过程关注于业务场景和问题,不考虑具体技术实现。
领域建模是为了可以结构化的拆解及表达业务逻辑。现实中的业务逻辑抽象起来可能是:元素、动作、流程等。
领域建模时,需要提取领域对象,确定限界上下文之间的依赖,建立领域内对象之间的依赖关系。
领域建模的关键步骤:
团队成员和领域专家聚集在一个开放的区域,借助墙、白板和贴纸等工具,采用头脑风暴形式,根据业务场景或用户旅程分析,列出所有领域事件,对每一个事件标注出导致该事件的命令,为每一个事件标注出命令的发起方。
从命令和领域事件中提取产生这些业务行为的对象,即实体或值对象。根据命令来提取服务或实体的方法。这个过程我们可以采用名词和动词分析法,比如根据名词提取实体,根据动词提取命令来设计实体的方法或者服务。
根据领域对象之间的依赖关系,构建聚合。首先,从众多实体中根据聚合根的特点找出聚合根,比如:是否有独立的生命周期?是否有全局唯一 ID?是否可以创建或修改其他对象?是否有专门的模块来管理这个实体?然后,根据业务内聚的原则,找出与聚合根关联的所有实体和值对象,构建出“高内聚,低耦合”的聚合。
划分限界上下文,构建领域模型,将多个聚合归类到同一个上下文语义环境,划定限界上下文边界,建立上下文映射,完成领域模型的构建。
领域建模过程是项目团队成员统一语言和建立通用语言的关键过程。
建议的建模过程是:
业务需求的分析过程自上而下,由业务流程,到用户用例,到领域模型。而设计过程是自下而上的。从领域元素设计开始,最后才是应用服务的编排。
建议设计优先级是先值对象 → 再实体 → 再聚合 → 再领域服务→ 最后是应用服务,优先考虑领域是否应该为值对象,其次是否为实体,划分出聚合。不属于实体或值对象中的领域行为放到领域服务,需要协调聚合的领域行为设计为领域服务或者应用服务。
任何业务代码逻辑优先映射到原子性的领域模型,比如值对象、实体、领域事件、资源库接口、外部适配接口,其次再映射到组合性领域模型,比如领域服务、应用服务。
微服务设计
将第二阶段的领域建模作为输入,完成服务维度的拆分,基于分层等技术确定服务边界。其他比较流行的分层架构有:DDD 四层架构、六边形架构和洋葱架构。
封装的本质还是在于让逻辑更内聚,对外界侵入有保护。聚合可以使得业务对象之间关联变少,事件驱动的背后逻辑还是在于解耦。
可以引入应用服务层,目的是对领域逻辑的封装与编排,提供原子接口供上层调用,一个应用服务就是一次编排,一次编排就是一个用户实例。
技术实现
最后一步就是具体的技术落地了,这一阶段需要关注于微服务的技术细节,比如API契约、数据模型设计,测试集成与部署。
以DDD分层架构落地来说,DDD 分层架构共包含四层,分别是用户接口层、应用层、领域层和基础设施层。
DDD分层架构图:
代码示例:
DDD背后的收益
全面实施DDD后产研团队目标更对齐,协作效率更高,收获了很多收益:
产研团队协同成本降低,领域知识得到积累和沉淀。统一语言的使用和维护极大提高了大家对齐的成本。
业务语义得到显性表达,业务逻辑内聚可复用程度提高,避免了很多散弹式修改和发散式修改。一个需求不用改多个地方,多个需求也不用几个研发集中改同一个地方。
限界上下文的划分从业务合理性出发,进而微服务的划分会更合理,减少了团队间的耦合和不必要的协同代价。
接口数量精简、可控。由于业务代码聚焦领域模型,逻辑内聚,复用性高,急剧减少了接口数量,降低接口维护成本。
通过预定义好的脚手架创建符合DDD规范的代码骨架,提高了新服务开发的效率。
代码可读性高,不是代码作者也能快速定位到代码位置,代码设计能够得到传承,可维护性也提高了。
新人熟悉新业务和新代码的速度极大提高,业务和技术知识的转移代价减低。
总结
DDD一方面使用分而治之的思想,引入划分领域、限界上下文、模块分层、划分聚合在不同层次、不同粒度来降低问题的复杂度。
另一方主张聚焦领域逻辑,通过不同手段来减少业务和技术的耦合。因此DDD只是大部分软件设计思想一种,软件设计的本质都是为了高内聚低耦合。