商品中心随着自身业务的发展,系统复杂度逐渐增加。在业务治理的过程中,我们尝试引入DDD来辅助重构现有的业务模型,并在此基础上完成了中端服务能力的沉淀和对外提供。通过降低核心业务逻辑和凝聚力,它降低了调用者的业务复杂性并防止逻辑损坏。1.前言商品中心业务主要包括商品、类目等核心数据的维护,负责和支撑内部严选商品相关的业务协同。在业务快速发展的过程中,系统的复杂度也越来越高。原有结构已不能满足内外需要。因此,从2017年开始,商品中心逐步经历了管理后台拆分、商品中心服务、商品数据迁移等工作,并不断优化以适应严选不断增长的业务量。2019年开始,严选开始升级中台化架构。我们尝试引入DDD来辅助重构现有的业务模型,并在此基础上完成了中端服务能力的沉淀和对外提供。通过降低核心业务逻辑和凝聚力,它降低了调用者的业务复杂性并防止逻辑损坏。目前,商品中心已构建了一个工作台和一个中间台两个查询服务的系统架构。本文将介绍中台服建设的相关过程,踩坑记录,同时给需要进行类似尝试开发的童鞋一定的参考和参考。2、系统的痛点是什么?众所周知,软件系统总是在不知不觉中变得庞大。如果不及时干预,系统的脉络就像一团纱线一样难解。目前,商品中心主要存在以下突出问题:1、业务逻辑重复采用自然流程开发,在初始业务不复杂的情况下,系统业务上下文相对简单。一旦经历了多个版本的迭代,基于脚本的开发代码不断增删内容,甚至在复制同一段代码后对某些逻辑进行微调,导致逻辑冗余,增加了成本的理解和迭代。示例产品创建链接:开发完成后,工单审核后自动创建产品。工单审核后,直接创建纯组合产品。由于一些差异和中间不同同事的开发,导致项目中有很多相似和不同的代码,导致维护越来越困难,也出现了一些漏改导致的BUG。2、模块耦合过重。产品工作台作为业务产品管理的入口服务,承担着大量的业务协同和产品数据配置。因为没有隔离,业务协同和产品管理之间的逻辑耦合太深,不利于各个模块的复用和优化。3.DDD简介领域驱动设计是指通过领域模型的设计来驱动软件设计,最终指导代码实现的过程。一个业务领域被划分为若干个限界上下文(BoundedContext),领域模型在每个限界上下文中。DDD具有以下特点:边界更清晰DDD的设计原则是让系统的边界更加清晰,让我们本能地分治软件系统。这是它最可贵的地方。我们把问题划分得越小,就越容易解决。一种更通用的语言当边界确定时,边界内的术语(名词对象、动作等)将在产品、开发和测试的共同努力下形成具有共识的通用语言。特别是,可以保证这些术语在后续迭代中是通用的。这里特别提一下,通用语言的确定不再只是开发人员的决定,而是业务相关人员的共识,也可以加深大家对领域模型的理解。更具凝聚力的逻辑在一个明确的问题域中,子问题会落在边界内并负责处理,逻辑更具凝聚力并与外界隔离。作为业务研发人员,本质是通过技术更好地实现业务价值。面对当前系统存在的问题,我们希望DDD能够在系统改造过程中发挥作用。4、系统转型之路商品中台服务建设的核心思路是:抽取核心业务逻辑->抽象流程->标准化能力。虽然是对现有业务的改造,但我们在系统建模的过程中,尽量从头开始设计。这样做的好处是可以尽可能避免现有表结构设计的干扰。使用DDD的经典步骤如下:1.策略设计在这个过程中,主要目的是明确系统的通用语言。比如我们在商品中心服务的设计过程中,我们明确了系统模型和行为,划分了子域,编制了限界上下文和上下文映射,形成了包括产品和开发在内的普遍认可的通用语言。子域又分为几类:核心域、支撑子域、通用子域;核心域是整个业务域的主要成员。支撑域不是核心,负责一些具体的业务。如果支撑域可以应用于整个系统,它就成为一个通用域。商品中心主要通过两个步骤完成战略设计:领域愿景声明(DomainVisionStatement)由产品技术人员和其他人员解释商品领域的核心能力:商品部分负责商品管理:包括核心数据维护如商品及SKU,商品相关配置,负责支持严选内部产品相关的业务协同:包括新品开发全流程(新品立项、采购、报价、采购方工单、包装设计、上线信息审查等)、价格变动、转售等。HighlightedCore通过业务梳理,提取核心模型:SPU、SKU、实体品类、配送区域、营销配置、售后地址、服务政策等,并将这些模型按照聚合划分为四个子域关系。2.战术设计战术设计是将战略设计具体化。在这个过程中,会明确每个子域的聚合、实体、价值对象、领域实践、领域服务等。就不详细展开了。详情请参考《实现领域驱动设计》(WoVaughnVernon)。上述阶段可以使用OOAD(面向对象分析法)、四色建模、事件风暴等。在我们的项目中,我们通过事件风暴识别领域事件和命令,完成边界的划分和聚合。事件风暴:简单概括就是X主体执行A命令,产生B事件,梳理核心业务流程和规则,输出业务对象,衍生相关领域模型的过程。常用模型如下:实体(entity)每个实体都是唯一的,允许状态改变,但必须有一个唯一的标识符。ValueObject(值对象)值对象用于描述一个实体,值对象与实体的区别在于它不需要感知唯一的标识符。聚合(aggregation)聚合是一种特殊的实体,它由一组强相关的实体和值对象组成。有界上下文(boundedcontext)用于封装通用语言和领域对象,通常一个子域对应一个有界上下文。领域对象表总结如下:3.编码过程本节主要介绍商品中心实现过程中部分场景的转换方法。1)重复过程的抽象方法在代码改造中,可以找到一些分散在不同位置但做相同过程的代码。对于这部分代码,我们需要对业务流程进行抽象,并进行逻辑整合。作为品牌电商,严选的自营立项流程是我们不同行业独有的业务。比如现状分析中提到的产品创建流程,通过三个步骤(梳理流程列表-->标记公共流程-->输出公共流程),分析业务逻辑,找到核心环节如下:2)核心逻辑的抽象方法在改造过程中也会遇到流程较长的环节。我们需要获取核心节点,排除非核心节点,输出业务链接。通过三个步骤:①梳理业务节点②抓取关键节点分析链路后,根据领域模型关联标记核心节点(绿色部分),形成简化版的节点图:③这个过程中的收敛逻辑,节点需要重构,主要是节点合并和节点异步:节点合并:检查节点,我们可以返回一个统一的节点,实际业务操作的节点也按照聚合进行合并。异步非阻塞流程:通过分析,其实有些操作是可以异步的。比如:operator、操作日志、取消上架任务、缓存刷新等都可以在消息通知订阅后处理,从而继续简化核心环节。其实核心逻辑被我们分解成了四个阶段:通过这几个流程,我们对核心流程进行了逻辑重构。从结果来看,核心逻辑已经下沉到中端服务中,减少了接入端的逻辑处理和处理。代码量大大提高了可维护性。在产品创建的情况下,仅代码量就减少了大约2/3。从长远来看,它会减少未来迭代中逻辑排序的时间和人力成本。五、相关设计1.服务架构在严选平台建设初期,我们就后续的应用架构标准进行了热烈的讨论,比较了经典的四层架构和COLA(CleanArchitecture)的优缺点。虽然经典架构更直观,但鉴于COLA以领域模型为核心的设计,保证领域层的独立性,最终导致我们采用COLA架构作为统一模板。类似于六边形架构,其核心理念是:应用是通过端口与外部进行交互,内部业务逻辑(应用层和领域模型)和外部资源(外部服务、数据库资源、消息中间件等)是彼此隔离,仅通过适配器进行交互。不同于传统的用户界面、界面层、逻辑层、持久层从外到内的分层模型,这是一种全新的思路。我们认为用户界面、数据库和消息都是平等的外部方。它们都需要通过端口与应用程序进行交互。在COLA的思路中,更突出的是架构的核心是领域模型。在此基础上的商品中台服务的系统分层如下:2、事件机制场景:修改SKU价格,由我们封装成具体能力如下:上述场景中,应用层调用域在“更新价格”行为之后,还需要处理其他的行为,直到所有的行为都处理完才会向外发送事件。因此,我们的消息机制需要满足如下要求:事件提交:允许事件提交到当前场景。事件异步和控制:指的是事件实际对外通知的时机是可以控制的。事件异常重试:支持异常后重试,实现业务补偿。消息初始化流程如下:系统初始化逻辑:启动容器,创建并初始化Listeners实例。从BeanFactory扫描EventBus事件总线,将Listener注册到EventBus事件总线。将临时存放在EventContext中的消息发布到异步处理的eventBus中,由eventBus协调消息的传递和处理。如果是内部消息,则直接由订阅者处理,如果是外部消息,则由订阅者通过MQ转发给外部。当然,我们需要支持事件定制的消息异常处理机制。对于需要重试的消息,允许在启动时注册一个重试处理器。六、讨论在实践中,发现了一些问题和解决方法,供大家参考。1、实体范围大小的问题在设计中,我们将同一类型的属性归为一个实体,但是在实际使用中,我们会发现实体的使用仍然是按模块的。比如性能实体:在设计之初,我们对商品的预定发货、发票转换、税率等进行了分类,过多关注属性覆盖等问题,意味着拆分不完整,而性能实体实际上可以拆分为三个实体。因此,设计时不仅要考虑属性的相似性,还要结合业务场景进行设计。2、模型开发模式的选择首先要明确分类,因为不同时期对贫血模型的定义会存在歧义,导致理解不同。出血模型:实体只有setter/getter。贫血模型:domainojbect包含不依赖于持久化的业务逻辑。充血模型:大部分业务逻辑应该放在领域对象中(包括持久化逻辑),Service层应该是很薄的一层。血胀模型:取消Service层,只留领域对象和DAO两层,将事务封装在领域对象的领域逻辑上。在这个定义下,充血和贫血其实各有优势。本质上,我认为还是负责领域模型包含业务的思想。我们采用贫血模式。在保留模型业务逻辑的同时,我们不想引入持久化逻辑,考虑到开发验收和模型的清洁度。3、服务粒度微服务粒度建议按子域拆分。如果拆分的太细,则需要考虑分布式事务的问题,增加了复杂度(尤其是对于某些核心领域有数据一致性要求的场景)。7.结束本文主要介绍商品中心在打造中台服务过程中的DDD实践思路、业务改造案例、服务架构设计、消息机制等。希望其中的一些类似案例和实现方式能够为其他产品线的后续实践提供一种探索思路。当然,后端服务的架构演进远非如此简单。完成现有业务转型后,我们仍将面临业务变更和新增业务的挑战。系统模型不是一成不变的,我们仍然需要不断更新系统以适应业务发展。
