领域驱动设计:概念
领域驱动是一个比较老的话题了,很多人都自以为是“领域专家”,但大家对领域的概念理解又有多少呢?最近项目中碰到一些问题,归因后发现大部分问题是前期设计对领域的认识不到位,上下游边界划分不清晰、各种mapping映射,导致系统趋于失控。如果设计之初多关注一些领域的问题,结果会大不同
为什么会存在领域驱动设计?
任何一个软件系统存在都是有原因的,它都要解决特定的“问题”,否则就没有必要做这个系统
那么问题的概念是如何定义的?
问题,可以理解成是现状和预期的落差,落差就是需求的真正来源,于是很自然的得出一个目标,知道自己的需求是什么?通过哪些事情来让未来达到预期?
如何确定问题是不是问题?
准确的定位问题是成功的开始,大部分糟糕的设计基本上是摸不清楚自己到底要解决什么问题,总是觉得这个问题我要解决,那个问题我也要解决,甚至不是问题的问题我也要解决,然后设计出了一个能解决所有“问题”的方案。比较常犯的错误是没有定位到问题本质:
1)误把方法/手段当"问题"(解决洪水和财产安全,答案应该是疏导洪水,而不是堵)
2)误把挑战当"问题",(同洪水示例,认为洪水猛如虎,能把洪水堵住牛逼至极)
3)思考问题时缺少时间维度,过了某个时间点,问题便不是问题,所以,有时候停下来、懒一点是好事儿
如何准确的定位问题呢?
可以为自己准备问题列表:
1)我是在解决什么问题(这里要更多的站在客户角度去思考,要解决客户什么问题)?
2)这个问题是已经发生的问题,还是未来将会发生的问题?
3)问题背后的问题是什么,背后的问题的背后的问题又是什么
4)我投入的大部分时间是讨论问题的定义?还是方案的设计?
5)我当前解决的问题有多严重,投入产出比是否合适
6)我定义的问题到底是客户的问题,还是方案中的技术挑战
7)如果这是个老问题,那么在新的技术条件下,有没有新的解法
8)对这个问题进行拆解的时候要使用升维思考吗,是否存在可能自己不知道的维度
一句话总结:我们不能只局限于问题本身,还需要看到问题背后的问题,然后才能更容易的找到更多的解决方案
回到领域驱动:看透问题的本质是DDD的最核心价值
我们过去过于强调架构而忽略了DDD建模的重要性,架构从系统实现上来看固然是重要的,但是架构不是一成“不变”的。我们应将重点放在领域模型上,领域模型是相对“静止”的,并且能产出更多的业务价值。
DDD相关概念
先介绍两个概念:问题空间 和 解决方案空间
1.问题空间,是当前环境下业务所面临的一系列问题和问题背后的需求,属于产品规划阶段,通常是业务和产品领域专家主导问题、需求的收集描述和分析
2.解决方案空间,是针对问题空间的解决方案,这里思考的是如何实现软件系统已解决这些问题,属于工程实现阶段,由技术专家主导方案设计
软件开发过程,本质上可以看作是问题空间到解决方案空间的一个映射转化:
1.在问题空间里,是找出业务绵连的挑战及其对相关需求场景用例分析
2.在解决方案空间里,是通过具体的技术工具手段来进行设计实现
DDD不是关于技术的,而是关于业务讨论、聆听、理解、发现和业务价值的,这些都是为了将知识集中起来
再介绍两个概念:领域 和 领域模型
什么是领域?
领域,领域相对于软件系统来说,就是系统要解决的现实问题,一个领域对应一个问题空间,是一个特定范围边界内的业务需求的总和。领域来自于需求,但它却高于需求,相对于善变的需求而言,领域知识和领域模型本身是“静止”的,是“不变”的
这里还有几个重要概念(概念比较多,哈哈...):
核心域:是业务域的一部分,也是业务是否能够促成的主要因素,应该给予最高的优先级
支撑子域:对应着业务的某个重要组成部分
通用子域:如果某个域被用做整个系统,那这种部分就是通用子域
限界上下文:“限”的意思就是划分、规定,“界”就是界限、或者一个边界,上下文就是业务的整个流程,总的来说,可以称限界上下文为业务流程在一个划定的界限中;限界上下文,是一个显示的边界,领域模型存在于这个边界内。在边界内,通用语言中的所有术语和词组都有特定的含义,而模型需要准确地反应通用语言
领域模型:针对特定领域里的关键事物及其关系的可视化表现,属于"解决方案空间",为了准确定义需要解决问题而构造的抽象模型,为软件系统的构建目标统一认知,是业务功能场景在软件系统里的映射转化
建模的意义?
建模能够帮我们提炼出事物的本质,以便能更好的指导应用系统规划建设,领域建模不是面向技术的一种纯软件设计方法,它是一种思维方式,我们采用它来搭建领域模型,以此弥补业务和代码之间的 Gap,促进团队合理的分工协作,同时也时刻真实的反映着我们所要解决的问题的变化,让我们构建的系统富有价值和生命力,所以,领域模型的价值不在于它的设计优美﹐而在于它体现了系统的核心价值
那么什么是系统的核心价值?
一个互联网的大型系统,它们本质的区别不是用了什么编程语言,也不是用了什么数据库,而是其提供的服务及其服务质量,也就是我们说:它能解决的问题及解决的程度
建模时碰到的问题
》建模时没有正确的推到方法,各自都有对自己有利的说辞,长时间不能达成共识(问题:长期讨论业务域模型没有结论)
》建模时没有正确判断标准来评估结果,导致模型的结果不够正确(问题:业务域、概念定义、边界,不清晰,无法整合)
正确的做法:
》合理的推导方法,帮助大家一起快速的将模型推导演绎(逻辑缜密)出来
》统一的判断标准,帮助大家判断结果是否正确(公认的标准,架构规约)
领域建模的收益
》即使组织职责不清晰,只要我们根据方法论和判断标准来做决策,就会有好的解决方案,因为,所有人的动机都是去做正确的事,大家不会有私心,我们都成了"护法(建模方法论)"
》法制,我们打的各种牌,权力牌,感情牌,互惠牌都是在维护和改进这些标准和方法论。正直的人用权力牌和感情牌来维护法,于是服众,不正直的人用用权力牌,感情牌来驱逐法制牌,以获取一己私利
领域建模方案
1.顶层业务共识
》调研客户需求
》调研竞争对手产品动态
》根据客户需求和竞争对手动态制定战略
》产品战略决定产品组合
》产品组合决定用例集合
2.架构、研发、PD管理者在业务领域模型上共识
》业务概念模型
》业务概念间的关系
》业务域划分及边界
过程中我们要考虑
》业务概念提取方法
》业务概念关联关系
》业务边界划分原则
3.研发人员达成共识
》软件模型工具
》实体之间的关联(组合、聚合、继承)
》实体职责、系统边界,定义
重点说下产品战略、架构和业务概念模型
产品战略
伐谋战术:产品来源于市场,市场由两个C组成
》customer(客户需要什么?谁是客户?)
》competitor(竞争对手有什么?谁是竞争对手?)
架构的定义
》原则:架构要尽可能简单(在当前场景下尽可能简单便于扩展和维护),但是不能太简单(太简单在场景上会有遗漏)
》目的:架构既要解决解决过去的问题,也要解决现在的问题,还要适度解决未来的问题,问题包括技术问题和业务问题
》2纬角度:解决横向和纵向的问题,横向就是分层,纵向就是分区
》3位角度:在2纬的角度上考虑粒度问题(也就是微服务)
》时间角度:架构不是一层不变的,是随着业务的发展不断演进的
架构需要
》职责明确的模块或者组件
》组件间关联关系明确
》需要有约束和指导原则
架构分类
1.产品功能架构:面向用户,描述产品能力;产品功能架构强调的是功能模块能力,受众是最终使用产品的用户
2.业务概念架构:面向研发与业务人员,描述业务概念模型,模块,基本关系;业务架构是对业务的一种分析和理解,用来如何更好的构建产品,受众是产品的同学和技术同学
3.应用逻辑架构:模块之间的联系和约束,粒度,职责,复用等等;描述模块间如何协同工作;应用逻辑架构强调的是研发时,各逻辑模块的职责,受众是研发同学和架构师
4.应用部署架构:机房、硬件、网络;稳定性、性能、成本
5.基础设施架构:中间件、存储、监控、报警
架构能力和职责
能力是产品的能力,职责是架构内部的职责
》能力,一个产品(业务或者技术)能做什么
》职责,架构内模块的职责,用来指导开发
架构推导思路
1.自顶向下的推导,未知业务领域
》关键,问题要被准确的定义,对问题进行转换分解,把业务问题转换成技术问题,然后对技术问题进行分解,架构中各个模块解决分解后的子问题
2.自底向上的推导,已知业务领域
需求来源:产品拍脑袋;分析数据做的产品策略改进;产品暴漏的缺陷
用例集合推导概念模型
》根据用例集合推导业务概念模型
》根据用例中的动词和量词推导业务概念模型的关系
》在特定的边界内根据职责归纳子域
用例要简单明了:“谁” 通过 “什么动作” 达成 “什么目的”
对业务概念模型进行归纳
什么叫归纳?
归纳的意思是将所有的结果和想法合并,变成一种思维慨念。或者让某个模型归属于某个已经存在的思维概念。且这些模型或者模块的职责不能超越这个高层次思维概念的边界
归纳是根据事物的某个维度来进行归类,越是高层的,越需要归纳:
1)问题空间模块划分属于归纳
2)逻辑架构中有部分也属于归纳
3)根据一堆稳定性问题,归纳出,事前,事中,事后都需要做对应的操作,是就是根据时间维度来进行归纳
为什么要归纳?
1)为了保证相近的职责模型聚拢在一起从而保证职责的高内聚,同时明确出来的两个子域的边界,保证模块和模块之间的低耦合
2)对业务概念模型的归纳有助于做业务需求分析时判断高内聚和低耦合,而且在系统模型上,对系统模型进行分类也有助于做应用逻辑架构中模块的高内聚和低耦合,但是应用逻辑架构的不止高内聚和低耦合,还有其他让职责单一的方法
按职责来进行归纳
》通过名词定义来进行归纳思维概念
》通过内聚的度量公式归纳,模块内连线数量/模块内模型的数量
》通过对实体属性抽取
如何保证模型的有效性
》为了避免推倒重造的问题发生,我们需要不断的自底向上的方式来修正架构,修正其实是在做局部的模块重构,谈到修正,具体的方法是由这里就不得正视归纳和演绎的重要性了,而这里的演绎和归纳是抽象的核心概括
》自底向上的推导的重点在于演绎和归纳,越是底层的越是要使用演绎的方法,越是高层的越是使用归纳
》演绎,演绎就是逻辑推导,越是底层的,越需要演绎:
1)从用例到业务模型就属于演绎
2)从业务模型到系统模型也属于演绎
3)根据目前的问题,推导出要实施某种稳定性措施,这是也是演绎
》我们从对业务的理解,演绎出用例,从用例演绎抽象出业务概念模型,从业务概念演绎抽象出系统模型,从系统模型演绎抽象出物理存储模型。
这是一个从A推导出B,从B推导出C,从C推导出D,从D推导出E的过程,而在B,C,D上又有很多逻辑分支。推导出的层次越深,
逻辑分支越广(保障每层的准确度的基础上),一般来说实力越强
》我们从对业务的理解,演绎出用例,从用例演绎出业务流程,再从业务流程演绎抽象成系统流程,然后再演绎成数据流
这是也是一个从A推导出B,从B推导出C',从C'推导成D',从D'推导出E'的过程。这个推导过程比如有方法论辅助,否则逻辑的深度和广度都会受到影响。
》总的来说:演绎推导的层次越深,分支逻辑越多,越能穿透迷雾,看问题就越透彻,说明功力越深厚
啪啪啪...的写了一堆,之前没有接触过相关概念的同学不要觉得太虚,后面会抽时间整理点实际的:如何从DDD落到CRUD