苏眠月|DDD as Code:如何用代码诠释领域驱动设计?( 五 )

  • BoundedContext的属性字段:type表示类型 , 如APPLICATION、SYSTEM等 。 domainVisionStatement描述一下BoundedContext的职责 。 implementationTechnology表示具体的技术 , 前面我们说到BoundedContext已经涉及具体的应用和系统等 , 所以要说明对应的技术方案实现 , 核心的部分描述一下就可以 。 responsibilities 表示BoundedContext的职责列表 , 这里只需要关键字就可以 , 如Account要负责安全验证等 。
  • AccountFacadeAggregate: 表示提供给外部调用的聚合 , 这里DTO的对象定义、服务接口的定义等 。
  • Aggregate Accounts:这个表示BoundedContext内部的聚合 , 如entity、value object、service等 。 这里说明一下 , DDD中的那个Aggregate是entity , value object的聚合对象 , 而ContextMapper中的Aggregate表示为一些资源的集合 , 如Service集合等 。
BoundedContext的更多信息 , 可以参考sculptor的文档[4] , 根据实际的情况可以添加对应的部分 , 如DomainEvent、Repository等 。
个人觉得这里BoundedContext还没有涉及到Ubiquitous Language , 还是需要对应的辅助设计文档 , 需要交代相关的项目背景 , 技术决策等等 。 个人是推荐采用C4架构设计作者编写的 《Visualise, document and explore your software architecture》[5] , 非常实用 , 作为DDD架构设计文档 , 完全没有问题 。
文章的一开头我们说到之前的DDD DSL更多的是代码生成器 , 如果是代码生成器 , 那么生成的代码一定有对应的规范和结构等 , 如entity、value object , service , repository保存的目录 , 生成的代码可能还包括一定的Annotation或者interface , 标准字段等等 。 当然这里我们不讨论代码生成器的问题 , 但我们希望大家的DDD架构设计还是要采用一定的规范目录结构 , 这里有几个标准推荐给大家:
  • ddd-4-java: Base classes for DDD with Java[6]
  • jDDD:Libraries to help developers express DDD building blocks in Java code[7]
  • ddd-base: DDD base package for java[8]
这三者其实出发点都是一致的 , 就是在代码层面来描述DDD , 核心是一些annotation、interface , base class , 当然也包括推荐的package结构 。
ContextMapper的其他特性
讲到这里 , 其实DDD整体上来说 , 我们已经阐述清楚:Domain划分、整体Domain的BoundedContext拓扑图和关联关系、BoundedContext具体定义和架构设计文档规范 。 但是ContextMapper还提供了UserStory和UseCase对应的DSL , 让我们来看一下 。
UserStory
好多同学都问UserStory如何写 , 有了这个DSL , 同学们再也不用担心如何编写UserStory啦 。 这个DSL比较明确的 , 主要是三元素:作为 “aaa" , 我希望能"xxx" , 我希望能”yyyy" , 以便 "zzz" ,也是符合UserStory的典型三要素:角色、活动和商业价值 。
UserStory Customers {As a "Login User"I want to update a "Avatar"I want to update an "Address"so that "I can manage the personal data."}UseCase
Use Case是描述需求的一种方式 , 在UML图就有对应的UseCase图 , 核心就是actor , 交互动作和商业价值 , 对应的DSL代码如下:
UseCase UC1_Example {actor = "Insurance Employee"interactions = create a "Customer", update a "Customer", "offer" a "Contract"benefit = "I am able to manage the customers data and offer them insurance contracts."}在Aggregate聚合中 , 你可以设置useCases属性来描述对应的UseCase ,如下:
Aggregate Contract {useCases = UC1_Example, UC2_Example}