本文书接上回《为了落地DDD,我是这样“PUA”大家的》 ,欢迎关注我的同名公众号。
https://mp.weixin.qq.com/s/DjC0FSWY1bgJyLPIND5evA
 

什么是最重要的事

 
如果你认真读过前面的文章,那么一定知道我们的核心逻辑:领域驱动是一种价值观,这个价值观是:“领域(边界)”的明确是软件设计掌控复杂度最重要的事。
那么整个软件交付过程中,架构师的职责就是持续保持“需求”、“模型”、“代码”三者的边界范围明确且一致。再回过头看整个软件交付存在的意义,就是为了满足需求,因此本质上来说,“需求”的边界就决定了一切,那么结论就不言而喻了:
最重要的事,就是需求的边界(范围)。
 

 

什么叫边界明确

 
假如说我有两个需求A和B,那么我们建模的时候就有如下几种结果,大家感受一下,通常情况下,自己给出的结果是哪个选项?哪个选项又是最理想的?

 
我相信大部分人都会认同,其中B和D是符合边界明确、需求与模型边界一致的原则的,而现实的情况大部分结果是A和C,各种各样的“join”充斥着系统的各个角落,一个典型的例子,就是用户-角色系统的设计。
 
用户-角色系统,通常会有这样几个关键需求:
  1. 创建用户
  2. 创建角色
  3. 为用户设置角色
  4. 查看用户有哪些角色
  5. 查看一个角色包含多少个用户
 
我们用最传统的设计方法来做,模型大体是这样的:

 
这样的结果是不是对应到了前面选项A和C比较类似?因为“用户聚合”与“角色聚合”连线的存在,导致需求与模型的边界不一致。
而我们要做的,就是在满足所有需求的同时,消除打破边界的连线。
 

如何操作

 
首先我们分析上图,假如我们把下面几个需求先去掉:
  1. 为用户设置角色
  2. 查看用户有哪些角色
  3. 查看一个角色包含多少个用户
 
那么我们会得到一个符合边界明确原则的设计:

 
然后我们再思考,下面两个需求,应该哪个聚合负责:
  1. 为用户设置角色
  2. 查看用户有哪些角色
答案很显然是“用户聚合”,那么我们可以得到下面的设计:

 
这时你会疑问,如果没有“用户聚合”和“角色聚合”的连线,怎么设置用户有哪些角色呢?
问题的关键,就在这里,通常我们总是会把“关系表”在图中用一条线来表示,那如果我说,“用户聚合”有一个集合属性,叫做“用户角色”,你会认同吗?如果我们知道用户对象有一个集合属性叫“用户角色”,那么是不是上图就很合理?
如果顺着这个思路,我们再来看需求“查看一个角色包含多少个用户”,它应该由哪个模型来解决?我想你已经知道答案了,就是“用户聚合”,最终我们得到如下设计:
 

 
到此,所有的需求可以满足,需求被划分为两个范围,分别对应两个模型。

为什么说它很难

如果你一直跟着我的思路,完成了上面的过程,那么你会发现,需求的边界不是客观存在的,而是我们主观的划分,这个划分的目的是为了在一个确定的范围内,能够解决这个问题。因为它是主观的,就不可衡量和判断,每个人都可以有自己的划分思路。另外它又是简单的,因为你可以像上图一样,这样划分边界,给出对应的模型解决它,就像在给自己家的袜子分配收纳盒一样简单。
所以,我常常叹息,关于领域驱动设计:
说它难,难的是做出取舍。
说它简单,是因为能明确知道取什么舍什么。
 

这是DDD建模最难的部分(其实很简单)的更多相关文章

  1. DDD建模案例----“视频课程”场景

    接触领域驱动设计DDD有一年多的时间了,中间看过不少书,参与过一些讨论(ENode QQ群).目前对DDD的认知还停留在理论阶段,所以对领域建模非常感兴趣,这里说的建模是指以DDD的思想为指导再加上D ...

  2. 轻松搞定Ajax(分享下自己封装ajax函数,其实Ajax使用很简单,难是难在你得到数据后来怎样去使用这些数据)

    hey,guys!今天我们一起讨论下ajax吧!此文只适合有一定ajax基础,但还是模糊状态的同志,当然高手也可以略过~~~ 一.概念 Ajax(Asynchronous Javascript + X ...

  3. UML建模学习1:UML统一建模语言简单介绍

    一什么是UML? Unified Modeling Language(UML又称为统一建模语言或标准建模语言)是国际对象管理组织OMG制定的一个通 用的.可视化建模语言标准.能够用来描写叙述(spec ...

  4. 72. Edit Distance(困难,确实挺难的,但很经典,双序列DP问题)

    Given two words word1 and word2, find the minimum number of steps required to convert word1 to word2 ...

  5. CF 327D - Block Tower 数学题 DFS 初看很难,想通了就感觉很简单

    D. Block Tower time limit per test 2 seconds memory limit per test 256 megabytes input standard inpu ...

  6. AI PRO I 第4章

    Behavior Selection Algorithms An Overview Michael Dawe, Steve Gargolinski, Luke Dicken, Troy Humphre ...

  7. OO第三单元“技术”博客

    主要针对第三单元的三次作业 JML语言的理论基础.应用工具链情况 JML指的是Java建模语言,全称是Java modeling language,是一种行为接口规范语言,可用于指定Java模块的行为 ...

  8. 【WCF】操作选择器

    在开始吹牛之前,先说说.net Core的事情. 你不能把.NET Core作为全新体系来学习,因为它也是.NET.关于.NET Core,老周并不打算写什么,因为你懂了.NET,就懂了.NET Co ...

  9. 我心目中的Asp.net核心对象

    转:http://www.cnblogs.com/fish-li/archive/2011/08/21/2148640.html 阅读目录 开始 HttpRuntime HttpServerUtili ...

  10. 【leetcode】Convert Sorted List to Binary Search Tree (middle)

    Given a singly linked list where elements are sorted in ascending order, convert it to a height bala ...

随机推荐

  1. Lecture6

    Smiling & Weeping ---- 我渴望你的在场,又渴望你的缺席,你终究是我深藏的借口 第六章 GitFlow工作流实战 6.0 引言 在实际项目开发工作中,常常会有自测.联调.提 ...

  2. C# pythonnet(2)_傅里叶变换(FFT)

    Python代码如下 import pandas as pd import numpy as np import matplotlib.pyplot as plt # 读取数据 data = pd.r ...

  3. Python加密操作 对称加密/非对称加密

    安装包: pycryptodome https://pycryptodome.readthedocs.io/en/latest/src/installation.html#compiling-in-l ...

  4. Django-缓存、信号与序列化

    缓存 1.缓存的简介 在动态网站中,用户所有的请求,服务器都会去数据库中进行相应的增,删,查,改,渲染模板,执行业务逻辑,最后生成用户看到的页面. 当一个网站的用户访问量很大的时候,每一次的的后台操作 ...

  5. Spring的三种依赖注入的方式

    1.什么是依赖注入 依赖注入(Dependency Injection,简称DI),是IOC的一种别称,用来减少对象间的依赖关系. 提起依赖注入,就少不了IOC. IOC(Inversion of C ...

  6. Go 使用原始套接字捕获网卡流量

    Go 使用原始套接字捕获网卡流量 Go 捕获网卡流量使用最多的库为 github.com/google/gopacket,需要依赖 libpcap 导致必须开启 CGO 才能够进行编译. 为了减少对环 ...

  7. ubuntu 同时安装python2 和 python3 版本的 gunicorn

    前言 最近在学习使用 gunicorn 部署 flask 项目.发现使用 pip3 安装完 gunicorn后,如如果再使用 pip2 安装 gunicorn,后安装的 gunicorn 就会覆盖掉原 ...

  8. yb课堂之用户注册登陆模块《六》

    用户注册功能接口开发 注册接口开发 MD5加密工具类封装 UserMapper.xml <?xml version="1.0" encoding="UTF-8&qu ...

  9. Mac Eclipse 常用快捷键汇总

    寻找类:shift+command+t 删除当前行:command+d 上移当前行代码:option+↑ 下移当前行代码:option+↓ 复制当前行至下一行:option+command+↓ 复制当 ...

  10. ps -ef | grep xxx 解释

    上述内容为:命令拆解: ps:将某个进程显示出来-A 显示所有程序.-e 此参数的效果和指定"A"参数相同.-f 显示UID,PPIP,C与STIME栏位.grep命令是查找中间的 ...