我们的业务本质就是获取、处理、存储及传输数据,在传统架构中业务逻辑通常以事务脚本(TransactionScript)的形式实现:业务规则直接在开发者的大脑中转化为数据库的增删改查操作(这也是很多程序员调侃自己是CRUD工程师的原因),然后被写到代码里。这种模式在场景单一、需求简单的业务发展早期阶段可以快速实现功能,但是随着业务复杂度的提升,这种过于粗糙的设计思维所带来的问题就会逐渐显现出来:
图灵奖得主Frederick在其著作《TheMythicalMan-Month》中将软件系统的复杂度划分为本质复杂度(EssentialComplexity)和偶然复杂度(AccidentalComplexity),其中本质复杂度是问题本身所具有的复杂度,与求解方法无关,而偶然复杂度是求解方法引入的复杂度。本质复杂度无法避免,但是我们可以通过优化求解方法来尽可能降低系统的偶然复杂度。这给了我们很大的启发,业务天然就是复杂的,这是一个客观事实,架构设计的目标不是消除业务上的本质复杂度,而是应该引导和辅助开发者更好的拆解和分析业务带来的复杂度(是handle而不是eliminate)。同时,软件架构应该提供足够灵活的标准规约与框架工具,让所有开发者都能够按照统一的思想写出可理解、易拓展和好维护的代码,减少甚至是消除由于没有封装或封装不统一带来的偶然复杂度。在这一思想的指导之下,经过两年多的打磨,我们推出了PICASO框架。
PICASO是一套以领域驱动设计(Domain-DrivenDesign,DDD)作为思想内核,专门为集成式复杂业务系统设计的通用基础框架。它的命名来自“PICASOIsaContextualAbilitySeparateandOrchestrateFramework(PICASO是一种基于上下文的能力分解与编排框架)”的首字母缩写。有趣的是这个缩略词的发音恰好与西班牙现代派绘画大师毕加索(Picasso)的姓名读音相同,毕加索在画作中经常对人体部位进行解构和重组,在接下来的介绍中我们将发现这一点与PICASO框架所强调的能力拆分与编排思想有异曲同工之妙,而这也是我们最终采纳这个命名的原因。
PICASO框架的职责是引导开发者将复杂业务流程正交分解为多个简单子问题,然后将这些简单子问题的处理逻辑封装为边界明确的标准可执行实体,在PICASO框架中这些可执行实体被称为领域能力。完成能力拆解之后,开发者可以通过PICASO提供的能力编排框架将不同的领域能力的组合成一个完整的请求处理流程,这个处理流程所在的可执行实体就是一个领域服务。领域服务会为每次请求生成一个上下文对象,通过这个上下文对象可以在不同领域能力以及领域能力与领域服务之间进行数据传递与共享,进而避免重复及碎片化的IO操作。PICASO框架还提供了开箱即用的通用可执行实体发现与路由组件,开发者可以通过该组件按功能域对领域能力及领域服务进行分组和聚合,每个分组对外暴露统一的请求路由门面,从而向上层调用实体屏蔽分组内部的场景复杂度,进而实现复杂度降维。如果在领域能力或领域服务的路由维度之外还存在其他维度的细微逻辑差异,开发者可以通过PICASO提供的拓展点机制进一步实现差异点分离。同样的,拓展点依然可以接入通用可执行实体发现及路由组件,向上层实体屏蔽拓展点所在功能域内的场景复杂度。
上文对PICASO框架的整体架构进行了整体地介绍,接下来我们将从软件系统复杂度根源分析开始,循序渐进地详细阐述PICASO各个模块的设计动机及运行机制。
PICASO框架整体架构
软件设计的本质就是持续对抗软件本身产生的复杂度,早在最开始进行新架构探索的时候我们就意识到,构建整洁架构的前提是厘清系统复杂度的根源。
通过对复杂业务系统发展历程的分析,我们发现业务复杂度一般来自水平方向上的多维度拓展和垂直方向上的多模块集成。
从上面的论述中可以看出,系统偶然复杂度的高低在很大程度上取决于开发者能否分析处理好业务的本质复杂度,另外在多人协作开发场景中,软件架构的标准性和解决方案的一致性也是决定系统偶然复杂度的重要因素,这就是我们推出PICASO框架的根本原因。我们希望PICASO能够引导开发者对复杂业务流程进行模块化拆解,采用分治思想逐一击破,并通过标准的逻辑封装规约与框架来实现多维度逻辑拓展,让团队中每一位开发者都能够以统一的思想写出清晰、简洁、有序、可检索的代码。
软件架构的构成
一个完整的业务流程可以拆分为多个原子业务模块,每个原子业务模块还可以按照其内部的业务模式进行进一步细分
能力门面与能力实例的抽象实现了能力编排复杂度的降维
自下而上逐层屏蔽层级内部的业务场景复杂度
领域服务与领域能力的路由机制能够较好的应对系统多模块集成带来的复杂度,但是领域能力及领域服务必须严格遵守框架规约,继承标准业务执行器模版(后续章节会有详细讲解),定义出明确的数据交换协议及上下文对象,这些都是相对较重的操作。因此能力或服务路由的维度必须抓住最核心的业务差异,而不是把所有存在业务差异的维度都纳入到路由规则中,否则就会造成沙粒化拆分,反而增加系统的维护成本。因此我们还需要一种机制能够以更加轻量的方式承载除了领域服务或能力路由维度之外其他业务维度上的细微差异,这就是拓展点机制要解决的问题。
拓展点机制是通用可执行实体发现与路由机制在更细粒度上的延伸应用,本质上就是将存在差异化逻辑的环节抽象为一个接口从主流程中分离出去,然后将不同场景的差异化逻辑隔离在不同的拓展点接口实现中,这其实就是依赖倒转原则(DependenceInversionPrinciple,DIP)的应用。与领域服务和领域能力相比,拓展点的定义和实现成本都要低很多,框架对拓展点接口内的方法及方法参数都不会做过多的约束,定义一个拓展点仅需要继承框架提供的标准接口并指定路由标识的提取逻辑,而实现一个拓展点接口时也仅需要在实现拓展逻辑之外额外指定当前拓展点实例能适配哪些路由标识。拓展点可以嵌入到领域服务、领域能力以及资源库(Repository,下文中会详细阐述)中任何一处存在差异化逻辑的流程中。
拓展点机制的核心作用是作为能力及服务路由维度的补充,进一步实现差异点的分离
前面几个小节一直在论述如何对复杂逻辑进行拆解和分离,但是系统要想对外提供可用的功能,就必须再次把这些分离出来的能力及拓展点组合起来,构成一个完整的领域服务。最简单的组合方式就是直接硬编码依次调用各个能力门面的功能入口,手动实现前置方法调用结果与后置方法入参的属性映射和转换,但是这种组合方式会在业务主流程中插入大量的胶水代码,稀释代码的信息密度,将流程关键节点掩盖在大量繁琐无趣的`setter`、`gettter`方法调用中。为了解决这个问题,同时确保新架构设计思想能够精准落地,让规范和标准框架化,PICASO自建了能力编排框架,它为前文所述的各类思想落地提供了框架基础,将前文提到的各种实体、组件与设计思想有机结合到一起,自动实现模块串联,让开发者专注于业务逻辑本身,实现填空式开发,最终构建出一个完整的工程应用。
标准业务执行器模版立足于软件系统的内在本质定义了适用任何业务场景的基本处理流程,就像Object对象在JDK中的作用一样,标准业务执行器模版并不复杂,但它却是PICASO框架中所有组件功能得以实现的基础。从本质上看,所有的软件系统都在做三件事:数据的获取、处理与存储(或传输);从业务视角看,数据的处理又可细分为输入数据的合法性校验以及数据的计算与转换,而数据的合法性校验又可细分为对输入数据直接进行的校验以及需要结合系统内外部详情数据进行的校验。基于上述论述,PICASO框架定义的业务处理的基本流程为:
标准业务执行器模版本质上就是一个Executor模板类,上述基本业务流程也就是该模板类中主要的模板方法。在PICASO框架中,领域服务和领域能力都要继承标准业务执行器模板类,这样做的目的是引导和约束开发者对领域服务和领域能力的具体实现逻辑按照标准业务执行流程进行二次拆分,从而可以让框架对代码进行精细化地调用控制。标准业务执行模版是对所有业务处理流程进行的最顶层抽象,模版类中各个标准业务执行步骤API的制定让把不同业务模块的串联执行职责从开发者手中转义到框架手中成为可能,开发者不必手动实现不同模块和方法的串联调用,而是专注于业务逻辑,实现填空式开发,从而减少系统中的胶水代码,提高信息密度,这本质上就是依赖倒转原则(DependencyInversionPrinciple,DI)的应用。下面的代码片段给出了标准业务执行器模版的定义,出于突出呈现PICASO框架设计思想的目的,示例代码去除了框架功能的具体实现逻辑,仅保留了核心要素及模版方法的定义。
上下文机制与传统架构业务处理流程对比
需要注意的是上文中“领域能力优先使用领域服务上下文中的数据”并不意味着领域能力会直接访问外层领域服务的上下文对象,这是由于同一个领域能力可能会被不同的领域服务所复用,因此领域能力不可能与其中任何一个领域服务的上下文耦合到一起。为了解决这个问题,PICASO框架要求每个领域能力都要定义自己专有的上下文对象。在调用领域能力之前先将领域服务上下文中的数据传递到领域能力的上下文中,领域能力中的业务逻辑直接访问的依然是领域能力自己的上下文对象,在能力执行过程中构建的新实体或者对已有实体的修改也会直接保存到领域能力上下文中。而在完成能力调用之后,PICASO会将领域能力上下文中新生成或者发生变更的属性传递回领域服务上下文中,从而在保持领域能力与领域服务解耦的前提下实现领域服务与领域能力上下文数据的共享。因此在PICASO框架中上下文机制除了起到避免碎片化及重复读写数据的作用之外,还负责在不同领域能力以及领域服务与领域能力之间进行数据的传递和共享。
我们可以用一个例子来详细描述上述机制,如下图所示,领域服务内编排了三个领域能力:A、B、C,其中能力A和C分别依赖业务实体1和实体4,能力B依赖能力A生成的数据实体2,完成业务逻辑处理后框架需要把能力B和C构建的业务实体3和5以及能力C对实体4的修改保存到数据库中。当请求到来时PICASO框架会首先调用领域服务的上下文初始化标准步骤(initContext)完成实体1与实体4的查询,在调用能力A之前会将实体1从领域服务上下文拷贝到能力A上下文中,完成能力A的调用后会将其构建的实体2从能力A的上下文中拷贝回领域服务上下文,然后将领域服务的上下文作为两个能力之间数据共享和交换的通道,在调用能力B之前将实体2拷贝到能力B的上下文中......以此类推用相同的方式完成能力B和能力C的调用,最后PICASO框架会调用领域服务的聚合根持久化标准步骤(persistAggregate),集中将新生成的实体3和5以及由能力C修改后的实体4持久化到数据库中。
领域服务与领域能力上下文之间的数据传递关系
在上一小节的最后我们通过一个架空的例子论述了PICASO框架内部的数据传递流程,这些数据传递规则并不需要开发者手动实现,而是通过PICASO框架内置的标准业务模版执行引擎自动触发的。接下来我们就将详细阐述标准业务模版执行引擎是如何将领域服务及领域能力各个标准步骤串联到一起的。但是在此之前,我们有必要必再次明确领域服务和领域能力执行器的职责,这对理解标准业务模版执行引擎的设计动机十分重要。
在PICASO框架中,系统对外提供的服务都是由领域服务执行器承载的,作为整个业务流程的全局把控者,领域服务执行器的基本职责就是定义业务流程(编排组装领域能力)以及管理业务数据(上下文的初始化及持久化),而领域能力执行器则聚焦在完整业务流程中的某个特定模块,负责实现该模块内部具体的业务规则。如前文所述,领域服务是通过领域能力组合编排而成的,并且它们都继承了标准业务执行器模版,因此不难推导出领域服步骤其实就是通过各个领域能力的相应标准步骤组合而成的。但是这并不意味着业务流程中所有的业务逻辑都会下沉到领域能力中,比如领域服务上下文初始化操作就必须在领域服务执行器中直接定义。此外,考虑到领域能力聚焦于局部业务细节,无法独立对外提供服务,为了明确组件职责,避免给开发者带来困惑,领域能力执行器对标准业务执行器模版进行了二次拓展,隐藏了完整请求流程处理维度才需要的聚合根持久化(persisteAggregates)、构建并发布领域事件(publishAppEvent)以及组装请求响应数据(assembleResponse)标准步骤,因此这三个模版方法对应的业务逻辑也需要直接在领域服务执行器中定义。
标准业务模版执行引擎的重组执行流程
下面我们将结合着上图所示的能力标准步骤重组执行流程图逐步解析标准业务流程模版执行引擎的运行机制:
1.参数预校验
当请求到来时,PICASO框架会首先通过领域服务门面定位到具体的领域服务执行器实例,然后调用其参数预校验标准步骤(preValidate),在该方法中会首先执行领域服务执行器直接定义的参数预校验逻辑(当然也可以根据开发者的设计意图调整为先触发各个领域能力的参数预校验逻辑),然后再触发领域能力执行图中各个领域能力的参数预校验逻辑,需要注意的是由于领域能力执行器有自己专属的参数及上下文对象,因此在调用各个能力参数预校验方法之前,PICASO会自动将领域服务入参对象中的属性拷贝到领域能力入参对象中同名同类型的属性上(与Spring框架中BeanUtils.copyProperties的逻辑相同)。
2.上下文初始化
完成参数预校验逻辑之后,PICASO会开始执行领域服务的上下文初始化逻辑。我们鼓励开发者将各个领域能力所依赖的底层数据集中到领域服务的上下文初始化逻辑中批量查询好,因为领域服务作为整个业务流程的全局把控者,拥有最全面的数据视角,可以进行最彻底的性能优化。完成领域服务直接定义的上下文初始化逻辑之后,PICASO将调用能力执行图中各个领域能力的上下文初始化步骤,但是在此之前,与领域服务与领域能力之间的参数传递逻辑类似,PICASO框架会先将领域服务上下文对象中的属性拷贝到领域能力上下文对象中同名同类型的属性上。
3.上下文校验
4.业务逻辑处理
基于上下文的业务校验通过之后,PICASO框架会继续触发领域服务及能力执行图中各个领域能力的业务处理逻辑。需要注意的是由于领域能力的业务逻辑处理过程中可能会对上下文中已有的实体进行了修改,也可能会构建出新的业务实体对象,这些变更最终都需要被持久化到存储介质或者外部系统中。因此在默认情况下,PICASO会在能每一个领域能力的业务逻辑处理标准步骤执行完成之后执行一次领域能力上下文到领域服务上下文的数据回传操作,将领域能力上下文中的属性拷贝到领域服务上下文中同名同类型的属性上。这些数据将在领域服务的后续步骤中被持久化到存储介质中,或者被用于构造领域事件及请求响应结果。
6.聚合根持久化、发布领域事件、构造响应结果
由于标准业务执行器中的剩余的几个标准步骤承载的都是请求维度的逻辑,领域能力执行器标准模版中对这几个方法也做了屏蔽,因此在这几个标准步骤的执行流程中就不需要再调用领域能力执行图了。需要特别说明的是,当执行到聚合根持久化标准步骤时,定义在领域服务及领域能力中的业务规则对实体的变更以及构建出的新业务实体都已经写入到了上下文中,开发者可以充分利用领域服务对数据操作全局把控的职责定位,积极采用批量、异步、并行等手段进行极致地性能优化。
7.定制化执行流程
前五步内容介绍了领域服务及领域能力标准执行模版默认的串联执行逻辑,PICASO框架也遵循约定大于配置(conventionoverconfiguration)的基本原则,如果默认的执行逻辑能够满足开发者的诉求,开发者不需要实现过多的流程控制,但是要更灵活地适配各类业务场景,PICASO框架也支持开发者对上述标准串联执行逻辑进行定制化的修改:
在前一小节中我们介绍了PICASO框架内部各个原子模块与标准步骤的串联执行流程,PICASO框架通过内置的标准业务模版执行引擎将各个模块的串联执行职责从开发者手中转移到了框架内部,从而让开发者专注于业务规则设计,实现填空式开发。这里说的“业务规则”一方面是指领域服务与领域能力各个标准步骤内具体的业务逻辑,另一方面是要明确当前业务流程需要按照什么样的顺序执行哪些领域能力、能力执行的前置条件、对默认串联规则的定制化配置(包括参数传递规则、上下文传递规则、错误及异常处理逻辑等),这些信息将以领域能力执行图的形式提供给PICASO框架,之后框架就可以按照开发者的意图完成对各个领域能力的串联调用,而能力编排指的就是构建领域能力执行图的过程。
PICASO能力编排框架的核心职责有两个,首先是在编码阶段让开发者能够以易用、简洁、直白的方式快速定义出业务流程对应的领域能力执行图,其次是在请求处理阶段将能力执行图解析为可以被标准模版执行引擎理解的执行计划,让其能够根据开发者意图完成业务逻辑的处理。我们可以通过下图所示的框架内部实体关系图对上述两项职责进行详细阐述,图中蓝色线条标记的是领域能力执行图的构建过程,红色线条标记的是请求到来时领域能力执行图的执行流程。
PICASO能力编排框架内部实体关系图
在PICASO框架设计之初,我们也曾想直接引入一些开源的流程编排框架来实现领域能力之间的串联调用。但是正如本章节最开始论述的那样,现有的开源解决方案并没有满足我们的核心关切:以直白、简洁、轻量、易用的方式实现能力组装,解决为了应对业务本质复杂度而采取的各项实体拆分与路由机制带来的编码繁琐、模块组装逻辑复杂等副作用,减少胶水代码和开发者的编码负担,提高关键业务信息密度。图形化、配置化的流程编排框架虽然能够直观的呈现业务处理流程,但是也造成灵活度差、普适性低、开发流程割裂、业务知识分散、模块串联配置繁琐等问题,无法达成整体熵减的设计目标,而PICASO框架解决这些问题的方案则是自定义能力编排领域特定语言。
软件工程领域的大师MartinFowler将领域特定语言分为外部DSL(ExternalDSL)和内部DSL(InternalDSL)两大类。外部DSL往往拥有自定义语法、需要宿主应用的代码执行文本解析,基于该类DSL编写的业务规则通常以脚本或配置的形式存在于系统代码之外,典型的案例是正则表达式。而内部DSL是通用编程语言的子集,它对外提供一组特定的API,利用内部DSL编写的业务规则往往是一段合法的代码,典型的例子就是JDK8之后提供的JavaStreamAPI。与外部DSL相比,内部DSL不需要专门的语法解析器和开发平台,可以直接与宿主应用代码无缝衔接,也能直接复用普通IDE的代码提示与自动补全功能,也正因为此,为了向业务开发者提供集中、连贯的开发体验,我们最终选择为PICASO能力编排框架开发一套内部领域特定语言。
为了尽可能灵活地适配所有的业务流程构建场景,我们在PICASO框架的能力编排DSL中定义了顺序、条件和循环三套能力编排逻辑,分别对应顺序执行、if...else判断、循环三种流程控制方式。其中每一类能力编排节点的配置都遵循约定大于配置的原则,按照标准业务模版执行引擎的默认执行逻辑提供了全部缺省配置,同时开发者也可以通过能力编排API定制自定义的执行逻辑,如循环规则、分支判断条件、触发能力时的参数及上下文传递逻辑、失败及异常处理逻辑、能力节点解析步骤等。由于本文旨在介绍PICASO框架的设计思想和各模块的底层运行机制,因此我们不会对能力编排框架所有DSLAPI进行详细论述,这部分内容将在《PICASO框架最佳实践——能力编排》一文进行详细论述。本文仅通过一个实际的能力执行图构建案例让大家对能力编排DSL有一个具象的感知。
顺序及条件能力编排DSL示例
循环能力编排DSL示例
第一代能力编排框架依然存在一些问题
第二代子流程及能力编排框架示例
通过上面的几个例子我们能感受到,领域能力编排DSL能够以极高的信息密度描述业务流程的关键信息,通过构建领域能力/子流程执行图的方式定义业务流程的措施不仅能够减少胶水代码、降低开发负担,还可以协助开发者快速建立起对业务的全景认知,同时,领域能力/子流程执行图也能作为详细业务规则的目录或索引,在进行业务梳理或问题排查时让开发者可以按图索骥快速定位目标代码的大致位置,提升业务知识传承及问题定位的效率。
至此我们已经完成了对PICASO框架全部核心模块的介绍,此刻让我们再次回首PICASO框架的设次初衷——竭尽所能地提升团队的研发效率,这也是一线业务开发团队的核心价值所在。
如果说前文介绍的PICASO框架让新架构拥有了领域驱动设计之形,那么接下来将要介绍的聚合与资源库机制将让新架构真正具备领域驱动设计的灵魂。
聚合与资源库机制就是专门为解决上述问题而生的。
聚合与资源库的引入实现了数据模型与上层业务模型的分离
在上一个小节我们介绍了聚合和资源库的定义及实现准则,这其实有些本末倒置,因为聚合和资源库机制的关键不是如何实现聚合实体的查询或者持久化,而是如何设计一套有价值的聚合(当然,先了解聚合的实现准则对理解聚合的设计准则是有帮助的),而聚合的设计原则正是领域驱动设计思想核心理念的直接体现。
多层架构向六边形架构的演进历程
六边形架构本质上还是一个分层架构,只是在呈现方式上(注意不是实现方式)将用户接口层与基础设施层合二为一,让他们共同作为防腐层保护位于架构中心的领域模型不被调用方的请求协议以及底层数据库的特殊设计所污染。而人脑天然具备的找中心的特性能够让开发者将更多的注意力放到位于架构中心的领域模型上,暂时忘记底层数据库的存储规则,进而能够紧贴业务实际设计聚合中的各个实体及值对象,让代码直接表达业务规则,最后通过资源库实现聚合实体与底层存储介质PO对象之间的转化。
底层通用化存储结构(K-V模式)在资源库中通过模型管理拓展点被映射为领域模型中业务含义明确的实体对象
在框架实现层面六边形架构与分层架构其实并没有太多的差异,顶多就是在六边形中领域模型仅负责定义资源库接口,而将资源库的实现放到了基础设施层中。在使用了Spring等控制反转容器的项目中,一些宣称采用了分层架构的系统可能已经在无意间实现了六边形架构了。那么六边形架构的意义又是什么呢?我们在前文中曾引用了IEEE对“架构”的定义:组织、组件以及指导思想,然而很多时候我们都忽略了指导思想对软件开发行为的重要影响。一个好的架构一定是包涵人性的,架构思想直接决定了开发者分析业务的世界观和方法论。框架只是辅助工具,基于框架思想对业务进行抽象和设计而产出的代码才是一个软件系统的主要构成部分。即使采用相同的框架,在不同架构思想的引导之下,系统中的业务代码也可能会走向全然不同的迭代路线。而六边形架构与分层架构的差异正体现在二者对开发行为的指导思想上,六边形架构以领域模型为中心,引导开发者始终紧贴业务实际进行模型设计。它与PICASO框架相辅相成,让系统在应对高复杂度业务时依然能保持对业务规则的清晰表达。
下图给出了新架构思想落地时工程结构的最佳实践案例,工程中各module的职责以及与上文中业务分层架构图中各层的对应关系依次为:
rtbad-framework:框架包,承载架构标准规约及分层架构图中基础设施层中的各项基础组件。
rtbad-module/rtbad-support-module:模型包,对应的是分层架构图中的模型层,承载领域模型中各个聚合及聚合实体对象的定义,另外用于实现底层存储介质中持久化数据与领域模型中实体对象映射逻辑的资源库也定义在此类module中。其中support-module定义的是支撑域中的实体对象,该module下会按照业务子域进一步进行子module划分。
rtbad-composite/rtbad-support-compoaite:聚合服务包,对应分层架构中的领域能力及聚合服务层,承载领域能力及领域服务执行器的实现,其中support-Composite用于承载支撑域领域能力及领域服务执行器的实现,该module下会按照业务子域进一步进行子module划分。
rtbad-app:部署层,内部分为不同的子module,每一个子module对应一个部署应用,其实现逻辑就是根据应用职责组装底层各个子module,进而实现不同应用下能力及模型共享。
rtbad-api:对外接口SDK包,承载了对外提供的API接口定义。
以下内容以一次计划新建请求为例,通过从流量入口到数据落库的完整请求流程展示使用新架构实现业务需求的全部过程,我们希望通过这个例子让大家建立对新架构的直观感受。
领域服务统一入口(DomainServiceFaced)的作用是为HTTP、RPC、MQ等上层不同的请求流量暴露统一的服务入口。他将同一个业务子域内领域服务执行器集中到一起,便于流量介入层调用,同时也可以集中进行方法性能监控、调用量统计、请求日志记录等通用功能。
领域服务统一入口引用的是各个领域服务门面执行器,它负责从参数中提取业务标识并定位到具体的领域服务实例。如下图所示,所有具体的领域服务实例都继承自领域服务门面执行器,请求到来时领域服务门面先通过generateRouteKey方法从当前参数中提取出本次请求的业务标识,然后与各个领域服务实例能够支持的业务标识做匹配,从而定位到应该处理本次请求的服务实例。
能力执行图的作用是定义业务执行流程,框架提供了丰富的API及大量的语法糖和默认规则,配合链式调用的风格,在支持灵活编排的同时减少了开发者的负担。
负责从参数中提取场景标识并定位具体的领域能力实例。
拓展点的作用是作为任意维度的差异点补充分离工具。需要注意的是在新架构中拓展点不是唯一的差异分离工具,在通用对象发现及路由机制下,领域服务、领域能力和拓展点都在不同维度上起着差异点分离的作用。相对与前两者拓展点更加灵活,通常用来承接领域服务及能力自身路由维度之外的逻辑差异。比如出价设置能力已经按照出价方式做了能力维度的差异分离,但是在相同的出价方式下,京准通与流量货币化还存在一些细微的逻辑差异,那么这个时候就可以在该能力实例中通过拓展点来补充实现平台维度的差异逻辑分离。
上面的例子是在计划名称设置能力中获取不同产品线计划名称长度上下限配置的拓展点,计划名称设置能力自身按照产品线类型进行业务模式路由,但是站内计划名称设置主要业务逻辑基本一致,仅在部分校验逻辑上不同产品线有各自的要求,此时就可以使用一个名称设置能力实例服务所有的站内产品线,定义名称设置主体业务规则,而把不同产品线的细微差异抽象成一个拓展点接口。
很多同学对业务开发一直存在一种偏见,认为业务开发很简单,甚至有业务开发同学自己也时常调侃自己是CRUD工程师,认为自己的工作没什么技术含量。但其实业务开发一点都不简单,只是过去我们一直把它做简单了。如今业务形态复杂多变,商机转瞬即逝,如何在快速变化着的复杂业务需求中维持系统健康、稳定、持续迭代,要做到这一点的难度其实一点都不比底层技术差。程序员应该是一门充满学术性与创造性的职业,我们唯有坚守初心,不断夯实自己的技术功底,沉淀提升抽象与建模能力,培养自己的系统化思维,不断学习精进,追求极致编码,这才是我们无法被AI替代的核心竞争力与价值所在。
我们相信,在大家的共同努力之下新架构所追求的逻辑易拓展、知识易传承、模型更清晰、系统更稳定的设计目标一定能够实现。