…接上
终于,我们来到了领域驱动设计的实践部分。在开始之前,我们明确一下领域驱动设计的主要产出:
领域通用语言
战略设计:子域划分到界限上下文再到上下文映射图(context mapper)
战术设计:每一个界限上下文的模型设计,即类图
首先,我们给出这个实践的需求,假设此需求来自于学术论文行业。该行业的核心业务逻辑是从各种渠道收集学术论文、或邀请行业知名专家共同撰写论文,并为用户提供在线阅读、检索等多种服务。我们先从DDD视角来俯视全局,请看下图:
上图是从整个企业考虑其业务和应用架构,图中子域的分类并不是非常合理。这里先让读者对其有点感觉。我们的实践只针对上图中一个子域:在线论文领域。
其次,让我们头脑风暴尝试挖掘此领域的商业本质和核心业务逻辑。我们从分析用户故事(User Story)开始,
Story 0:某个实体可以获得某种资源和服务。
Story 1: 某个实体需要满足某种条件才能获得某种资源和服务。
Story 2:实体A生产和制造资源,输出服务;实体B在满足某种条件下可以从实体A获得资源和服务。
其上就是对商业逻辑的顶层抽象,这里面的实体并不是DDD战术设计的实体,而是代表某个商业实体,可以是组织、企业、机构和个人等。用户故事远远没有结束,笔者这里只是简单演示一下而已。
最后,让我们看一下基于在线论文服务领域的战略设计。其核心业务模式就是用户通过web端注册,可以在线购买论文资源,web应用提供论文资源的搜索、下载、在线阅读等功能。
笔者是采用 https://contextmapper.org中的CML进行建模的。
CML是通过DSL(Domain Specific Language)来构造通用语言的,主要是通过用户故事(User Story)和用户用例(User Case)来定义的。
UserStory US_visitor1 {
As an "Visitor"
I want to "access" the "Application"
I want to "enjoy" the "Services" with its "Policy"
I want to "create" a "User" with its "Name","Email","Cellphone number" for an "Application"
I want to "Register" a "User" with its "Qualify"
so that "I can do business about your resources and get more online services"
}
UseCase UC_visitor1 {
actor "Visitor"
interactions
"access" the "Application",
"enjoy" the "services"
benefit "Get OA resources by related service"
}
UseCase UC_visitor2 {
actor "Visitor"
interactions
"register" a "User",
"offer" the "Profile",
"offer" the "Qualify",
"verify" the "Profile",
"verify" the "Qualify",
"activate" the "User",
"response" the "Result"
benefit "As a registered user of the application to get more services and resources"
}
上例展示了以 CML 来描述用户访问论文网站的用户用例和故事。整体定义非常长,就不能贴在这里了。
通用语言的定义非常重要,请大家万万不能忽视。它会成为日后确定具体需求、需求变更、模型设计的一个指导性纲要。在通用语言的术语中,名词用来给概念命名,形容词用来描述这些概念,而动词则标志可以完成的操作。
假设在上一步我们已经定义好了通用语言,对业务需求的理解已经清晰。现在我们要对领域进行拆分,
我们称这个领域为数字产品在线服务领域,它可以划分为六个子域:
用户中心
主要处理用户管理、用户验证和用户审计功能。图中虚线所声明的功能模块可以理解为界限上下文,也可以理解为子域中的子域。笔者在这个实践中建模为子子域,以下雷同。
商务中心
处理用户交易、渠道管理和商务规则。
服务中心
包含资源代理、社交服务和售后服务。这里的资源代理主要是为用户提供文献检索、下载、文献目录等基本服务和推荐、知识等智能服务。称为资源代理的原因是上述的功能已由笔者所带领的团队在数据中台中开发完成了。而本系列文章所讨论的领域驱动设计主要是为了开发业务中台的。
鉴权中心
鉴权中心就是为了鉴别用户对哪一种资源有什么样的权限。这个问题在线上论文数字服务领域较为特殊、相对复杂。因为用户可能对成千上万的文章拥有阅读权限,如何记录或者计算出用户对某一篇论文拥有什么样的权限并不是一件非常简单的事情。可能共有100w用户,1000w论文,我们不可能维护一个这么大的矩阵。这里还有权限拥有的时间、地域问题,如何寻找一个高效地方案解决这个问题成为了一个挑战。哪位读者对类似问题有好地方案,欢迎私信留言告之,不胜感激!
商品中心
主要提供商品管理功能,实际上论文目录和一些封装的产品信息已经在数据中台提供。在商品中心中可以在做一次封装。
营销中心
负责营销活动策划、实施和评估。
这里每一个子域都以某某中心命名看上去像是某个应用,实际情况下也确实带有应用层概念。本人也并不确定这样设计规划是否合理,欢迎各位读者提出自己地见解。上图中的子域分类也并不十分合理,主要是业务中台所需并配合领导的理解而已。实际上,从DDD的观点上看,最具核心价值的功能应该是诸如搜索、论文下载等数据相关功能。如前所述,由于数据中台已经提供了这些功能,所以业务中台就不能再将其列为核心域了。
下面贴出其中一些子域的设计图初稿:
用户中心
商务中心
商品中心
初稿中的设计更多是从功能上考虑,不是非常符合DDD的设计范式。请看下图所示的领域模型逻辑结构图,
上图中的领域模型层共包含六个子域,分别是用户域、商务域、服务域、商品域、鉴权域和营销域。领域模型中以椭圆型实线包围的是界限上下文。服务域中的服务代理上下文和用户交互上下文的核心功能分别由外部域的数据中台和社交平台提供。
在最外层红线与黑线围绕的领域模型层之间存在一个过度区域,用户域、商务域和服务域都已虚线跨越了这个区域。笔者将这个区域抽象为应用服务层,但设计中并没有完全依照DDD的建议。在这个区域的界限上下文,例如用户域的注册、登录和服务域的售后都是比较易变的,其功能可以通过领域模型层功能调度完成,且有可能直接以应用的方式实现或者对接应用。
上图展示了该领域模型的上下文映射图及其集成关系。ACL代表(Anti-corruption layer, 防腐层),PL代表(Published Language, 发布语言),读者可以通过前面所梳理的集成关系分类的英文首字母自行推断。
Domain digitalEC {
domainVisionStatement = "digital published article e-commerce"
Subdomain userDomain {
type = GENERIC_SUBDOMAIN
domainVisionStatement = "Subdomain support user and role management and AAA related functions"
}
Subdomain businessDomain {
type = CORE_DOMAIN
domainVisionStatement = "Subdomain supoort business rules and strategy"
}
Subdomain productDomain {
type = GENERIC_SUBDOMAIN
domainVisionStatement = "Subdomain support product management functionality"
}
Subdomain onlineServiceDomain {
type = SUPPORTING_DOMAIN
domainVisionStatement = "Subdomain support Online services for users based on article resources"
}
Subdomain Marketing {
type = SUPPORTING_DOMAIN
domainVisionStatement = "Subdomain Marketing opertaion and supervise"
}
Subdomain Authorization {
type = SUPPORTING_DOMAIN
domainVisionStatement = "Service support user authorization related resources"
}
}
以上代码展示了领域的定义和子域的划分。
import "./userStory.cml"
/* Context Mapping definitions */
ContextMap digitalECContextMap {
type = SYSTEM_LANDSCAPE
state = TO_BE
contains userManagementContext
contains userAuthenticationContext
contains userAuditContext
contains AuthorizationContext
contains orderContext, payContext, invoiceContext
contains policyManagement, channelManagement
contains productManagementContext
contains serviceProxyContext, userInteractionContext
contains postSalesContext
contains userRegisterContext, userSelfserviceContext
contains marketingManagementContext, actionEvaluationContext
contains orgManagement, partnerManagement, memberShipManagement
userManagementContext [D,ACL] <- [U,OHS,PL] userAuthenticationContext {
exposedAggregates = Authentication
implementationTechnology = "RESTfulHTTP"
}
userManagementContext [D,ACL] <- [U,OHS,PL] AuthorizationContext {
implementationTechnology = "gRPC"
exposedAggregates = Authorization
}
userManagementContext [D,ACL] <- [U,OHS,PL] userAuditContext {
implementationTechnology = "RESTfulHTTP"
exposedAggregates = Audits
}
userRegisterContext Customer-Supplier userManagementContext {
implementationTechnology = "RESTfulHTTP"
exposedAggregates = User, Role
}
userSelfserviceContext Customer-Supplier userManagementContext {
implementationTechnology = "RESTfulHTTP"
exposedAggregates = User, Role
}
userManagementContext [D,ACL] <- [U] policyManagement {
implementationTechnology = "MQ"
exposedAggregates = Policies
}
userManagementContext [U,OHS,PL] -> [D,ACL] memberShipManagement {
implementationTechnology = "RESTfulHTTP"
exposedAggregates = User, Role
}
userManagementContext [U,OHS,PL] -> [D,ACL] channelManagement {
implementationTechnology = "RESTfulHTTP"
exposedAggregates = Role
}
orgManagement [D,CF] <- [U,OHS,PL] channelManagement {
implementationTechnology = "RESTfulHTTP"
exposedAggregates = Channel
}
partnerManagement [D,CF] <- [U] channelManagement {
implementationTechnology = "RESTfulHTTP"
exposedAggregates = Channel
}
orderContext [D,CF] <- [U,OHS,PL] payContext {
implementationTechnology = "RESTfulHTTP"
exposedAggregates = Payment
}
payContext [D,CF] <- [U,OHS,PL] invoiceContext {
implementationTechnology = "RESTfulHTTP"
exposedAggregates = Invoice
}
orderContext [D,ACL] <- [U,OHS,PL] userManagementContext {
implementationTechnology = "RESTfulHTTP"
exposedAggregates = User
}
orderContext [D,ACL] <- [U] policyManagement {
implementationTechnology = "MQ"
exposedAggregates = Policies
}
channelManagement Supplier-Customer orgManagement {
implementationTechnology = "gRPC"
exposedAggregates = Channel
}
channelManagement Supplier-Customer partnerManagement {
implementationTechnology = "gRPC"
exposedAggregates = Channel
}
policyManagement [P] <-> [P] channelManagement {
implementationTechnology = "MQ"
}
policyManagement [U] -> [D] memberShipManagement {
implementationTechnology = "MQ"
exposedAggregates = Policies
}
policyManagement [U,OHS,PL] -> [D,CF] productManagementContext {
implementationTechnology = "MQ"
exposedAggregates = Policies
}
policyManagement [P] <-> [P] userManagementContext {
implementationTechnology = "MQ"
}
policyManagement [U,OHS,PL] -> [D,ACL] serviceProxyContext {
implementationTechnology = "MQ"
exposedAggregates = Policies
}
AuthorizationContext [D] <- [U] policyManagement {
implementationTechnology = "RESTfulHTTP"
exposedAggregates = Policies
}
marketingManagementContext [D,ACL] <- [U] policyManagement {
implementationTechnology = "MQ"
exposedAggregates = Policies
}
marketingManagementContext [D,ACL] <- [U,OHS,PL] actionEvaluationContext {
implementationTechnology = "RESTfulHTTP"
exposedAggregates = actionEvaluation
}
serviceProxyContext [D] <- [U] AuthorizationContext {
implementationTechnology = "gRPC"
exposedAggregates = Authorization
}
serviceProxyContext [D,CF] <- [U,OHS,PL] userInteractionContext {
implementationTechnology = "RESTfulHTTP"
exposedAggregates = UserInteraction
}
userInteractionContext [U,OHS,PL] -> [D,ACL] postSalesContext {
implementationTechnology = "RESTfulHTTP"
}
serviceProxyContext [D,ACL] <- [U,OHS,PL] productManagementContext {
implementationTechnology = "MQ"
exposedAggregates = Products
}
}
以上代码展示了以CML定义了上下文映射图,和界限上下文之间的集成关系。
到此,DDD战略设计告一段落了。
未完,待续…
DDD(Domain Driven Design) 领域驱动设计从理论到实践 一
DDD(Domain Driven Design) 领域驱动设计从理论到实践 二
DDD(Domain Driven Design) 领域驱动设计从理论到实践 三
DDD(Domain Driven Design) 领域驱动设计从理论到实践 四
DDD(Domain Driven Design) 领域驱动设计从理论到实践 五
DDD(Domain Driven Design) 领域驱动设计从理论到实践 六
DDD(Domain Driven Design) 领域驱动设计从理论到实践 七
DDD(Domain Driven Design) 领域驱动设计从理论到实践 八
DDD(Domain Driven Design) 领域驱动设计从理论到实践 九