领域驱动设计之领域的定义

板桥banq 原创书籍《复杂软件设计之道:领域驱动设计全面解析与实战》

目录

  1. 领域的定义
  2. 如何编写类?
  3. 对象如何创建
  4. SQL语句要不要写

 

第一章

  领域即边界,狗狗特别是公狗都有领地意识,撒尿是做标记意思是这地盘里有人了,划分领地是其动物本性,这大概是动物包括人的一种生存意识。领地本质上是一种边界划分,领域词语中的“域”也是边界的意思。

  领域设计意思是在一定业务边界范围内进行的设计思想或活动,同时也表达了你已经非常熟悉这个业务领域,甚至达到一定的掌控程度,似乎有“我的领地我做主”的气概。

  总结一下:领域设计= 边界 + 设计。

  没有边界谈不上设计,大而全的宇宙真理我们是不需要的,但是只有边界没有设计则是满地鸡毛。

  不过进行领域设计不是一件简单事情,首先你得有这个领域的知识,然后还有一套你对这个领域知识总结和概括,甚至摸清了领域中的逻辑关系,一般人不一定掌握得好,大概只有多年业务专家才会有这个本事,或者多年来一直在开发某个业务系统,直至公司人员组织结构都按照业务领域划分成不同部门了,比如电商公司有订单组、仓库组、支付组和货运组,这种带有业务性质的组织部门其实已经代表了大家的共同领域认识。

  我们知道,微服务架构倡导“组织决定架构”,也就是说,如果我们一开始对业务无法全盘掌握得很清楚,与其坐而论道,不如行动,先让一些程序员去实现微服务,保持团队足够小,中午叫一两块披萨饼就能全部喂饱,如果这样做行得通,微服务也能开发出来了,以一个个微服务为标志的边界同时也会划分出来。

  好了,说了这么多理论,不如找个案例来分析分析,我们以某电力公司的统购统销系统为案例,说明如何进行领域的边界发现和划分吧。

电力结算系统

  电力公司是干什么的?其实就是电这个商品的批发商,从发电企业买电,通过其电网,输送到各家各户,再向各家各户收电费,商业模式很简单,上家花钱,下家收钱,它的信息系统主要是管这个钱的进出,专业术语就是电力购销。

  由于花钱和收钱是两件大事,分别由不同部门或子公司负责,比如营销部是向每个用户抄表与收费,而交易中心则负责向电厂购电,财务部门则是对购销双方进行统一资金结算。

  总结一下:电力结算系统 = 交易中心购电结算 + 营销部销电结算

  初一看,这个电力结算系统划分是不是比较简单? 分成两个领域边界,分别是购电结算系统和销电结算系统。但这可能只是表面上的一种假象而已,盲人摸象应该就是比喻成我们现在这个阶段。

  虽然山有虎偏向虎山行,别无他路,也只能现在按照这条思路走下去,假设我们让两个微服务团队去分别做这两个系统,会发生什么情况呢?

  这两个团队犹如两只狗狗,一出门就开始划分领地了,首先我们看看购电结算这块领地怎么划分?

  购电参与主体有电力公司和发电企业,他们的购电行为的发生是从购电合同开始,好吧,购电合同虽然是将电力公司和发电企业联系在一起,但是也确定了他们俩的边界点就在这里了,这种购电合同其实类似订单或采购单一样,可以归类于同一种商业模型,属于合作开始,业务活动生命周期开启点。

  再看看另外一只狗狗怎么划分销电这块领地?电力销售这块如果以普通老百姓电表计价方式看,每个月收取上个月的电费,这是以月为单位和用户结算,结算形式是电费单,电费单也是电力公司和用户的边界点。

  至此,两个团队跑马圈地初步结束,我们电力结算系统整个边界也大概摸清楚,从购电合同为起点,电费单为终点,如同我们逛商场,把商场的东南西北四个方向顶端都逛过了,大概就知道这个商场的占地面积有多大了。

  下一章我们将按照购电合同和电费单两个业务表单作为模型,进入更详细设计摸索阶段。

时间与空间的边界

  边界这个概念我们大概至此能接受了,但是仔细再想想,不但空间有边界,时间上也有边界,过了这个月再补缴电费就被拉闸了,天、日、月、年这些时间单位是一种时间刻度,其实也是一种时间边界的标记啊。

  比如前面电力结算系统,我们找到这个系统边界上两个点:购电合同和电费单,那么这两个模型是属于时间还是空间上边界呢?购电合同规定的是某一年或几年内购多少电量,电价是多少,这显然是和时间有关的,而电费单也是某个月用电的金额,和时间有关,因此,这个系统主要是从时间上进行定位分析的,那么时间就变成我们领域关键的度量,如果说这点有些难以理解,我们举一个空间上的定位案例:

  比如货运系统将货物从广州运送到上海,我们需要建立一个货运系统跟踪货物运输情况,这样我们的客户能够随时了解自己货物在哪个地方,很显然,这个领域内,空间位置是很重要的领域度量,而在电力结算系统中,不同时间尺度对于资金结算肯定不一样的,电力公司收了用户电费,延迟支付供电企业的购电费用,那么中间产生的利润就非常可观,如同共享单车使用用户押金生财一个道理。

领域不只是边界

  前面我们主要从边界这个角度谈领域这个概念,但是领域不只是边界,还带有游戏规则的含义,也就是在某个边界內的游戏规则或逻辑,严格地说,是某个业务边界內的业务逻辑,比如我们常说领域知识或领域规则等概念。

  注意,我们讲的这些领域概念与逻辑知识不是纯粹抽象的概念,抽象概念是理性思考的结果,虽然很通用,这个概念说出来大家都能明白,但是因为太抽象已经失去了人类知觉和看事物的角度,比如我们正面角度看到一间房子,那么房子背面就看不到,但是如果你抽象出'房子'这个抽象概念,每个人就变成上帝俯视房子的三维全貌,失去人的视角和有限性。

  只有带有人的视角和有限性甚至偏见,但是逻辑自洽的概念才是真正领域概念,我的领地我作主,这个领地带有领域专家个人视角与痕迹的,反而通用抽象的概念并不是领域概念。

  我们做某个行业的信息系统,首先需要掌握这个行业的领域知识和概念,这些知识概念是先与信息系统存在的,可以说领域知识是一种先验知识。

  当我们拥有了某个领域的先验知识和逻辑,我们带着这些知识逻辑开始设计我们的系统,比如我们了解电力结算的领域知识后,就准备好实现电力结算功能了,这些功能都是在一定场景下发生的事情,分析哲学宗师维根斯坦说,世界是事实总和,不是事物的总和。事实就是指在一定场景上下文中发生的事情,我们信息系统需要跟踪记录发生的这些事实。比如电力结算系统需要记录跟踪每笔资金和上下游单位结进行结算的事实情况。

  从这里我们看到了领域和有界上下文的区别。我们可以用这段话来表达它们之间的关系,我们带着这个领域多年来总结的逻辑概念,将其通过领域模型表达在这个软件信息系统中,在一个个有界上下文中发挥其作用,完成用户要求的功能。这也是我们使用DDD目的所在。

  从上面这段话我们可以得出:有界上下文 = 用户 + 领域模型 + 功能。

  如果以烹饪作为比喻,今天我们要做一道红骚扰的菜,那么首先上网百度一下红烧肉的做法,
  这个就是准备领域知识,具体红烧肉做法是领域逻辑了,然后准备食材,这类似放在领域模型对象中的数据了,做好红烧肉这道菜后,我们端上桌子,用户品尝这道菜,感觉很很满意,满足了他想吃红烧肉的需求,那么整个这样的一个场景就是一个有界上下文,满足的需求其实就是满足用户要求的功能实现。

  所以,有界上下文是一种多方面混合的产物,是最终面向用户、需要有用户参与、必须满足用户功能需求的生产现场,是领域模型与逻辑的最终检验场所。说白了,你那套领域逻辑到底有没有效?逻辑上自洽为真,没有逻辑矛盾,是不是现实中也是为真呢?需要在有界上下文中验证。

  下面我们按照上面的方法再回到电力结算系统这个领域,去发现领域逻辑和有界上下文。

电力结算的领域分析

  以电力结算为例,我们重新审视它的领域知识,首先电力系统原来是国家统购统销,国家垄断了整个电力行业,随着进入市场经济,国家不断加大改革,比如成立专门的电网公司,独立核算,它的营销部到每个用户那里抄表,收取电费;交易中心负责与电厂商谈电价,采购电力;财务对两边结算,结算电价与电费。电改以后,最终用户和电厂之间可以自主交易,商谈价格,由电网公司给予结算,这样电厂可以成立售电公司,批发售电,实现更精确的
零售用电策略,比如省内价和卖给外省价,两者电价都不同,一度电价不同场景定价都不同。

  从上面这段领域知识中,我们可能发现了这样一个关系图:

  在这样的关系图中,我们需要分别发现用户、领域逻辑、功能:

  1. 结算系统的使用用户应该是供电公司和用电用户,供电公司关心它的电被哪些用户使用了,使用情况如何,而用电用户关心哪些供电公司的电价比较便宜,哪家便宜我买哪家。
  2. 结算系统的功能其实已经在上面一段话里透露了,他不但关心被谁用了电,而且对方付钱是否及时,什么时候收到款?结算系统至少要提供这套功能。同样,对于用电用户,他不但要更便宜地采购电力,而且要知道自己的用电明细,哪段时间用了多少等等。
  3. 下面是关键的领域逻辑,我们如何满足用户的这些功能?这样的结算系统是不是有点类似淘宝网和支付宝,在淘宝网上买卖商品:电力;在支付宝上进行双方结算?好了,有了这套目标参考,其中逻辑设计方向是不是就已经明确了呢?

通过上面的上下文要素的分析,很显然,结算系统面对两种用户,上游的供电企业和下游的用电用户,我们这个领域中的界定上下文有了两个:

这两个上下文的内部细节如下:

总结

  本章我们学习了DDD中领域与有界上下文两个重要概念,重要的事情重复三遍,这里再将这
两个公式贴在下面:

1. 领域设计= 边界 + 设计。
2. 有界上下文 = 用户 + 领域模型 + 功能。

将这两个公式联系起来看看,是不是也有些逻辑关系呢?留给你们自己思考和顿悟去吧。

备注:有的同学可能会提问最后一张用例图是怎么画的?我使用的是EA(Enterprise Architect)这个软件,有界的上下文表达是使用UML中用例图方式,以后你画用例图是不是也有了方法依据呢?所以,会画UML图很容易,难的是针对项目去画,需要一套思想方法,DDD为你提供了这套思想方法哦。

幽默图:程序员准备编写SQL前的热身

幽默:当你的代码中有多个嵌套if-else语句时

杠上敏捷宣言了!在推动敏捷过程中我们失去了软件设计!

什么是模型? 人工智能建模和人脑分析建模的异同点 

鲍勃大爷:先设计对象的行为,再设计数据库的表结构!

下一章