This commit is contained in:
by931
2022-09-06 22:30:37 +08:00
parent 66970f3e38
commit 3d6528675a
796 changed files with 3382 additions and 3382 deletions

View File

@@ -156,7 +156,7 @@ function hide_canvas() {
<li>然后将我们对业务的理解绘制成领域模型;</li>
<li>再通过领域模型指导数据库和程序的设计。</li>
</ul>
<p><img src="assets/CgqCHl_PHjCAMbspAAEZnIFmIZ0660.png" alt="Drawing 0.png" /></p>
<p><img src="assets/CgqCHl_PHjCAMbspAAEZnIFmIZ0660.png" alt="png" /></p>
<p>图 1 领域驱动设计的真谛</p>
<p>过去,我们认为软件就是,<strong>用户怎么提需求,软件就怎么开发</strong>。这种开发模式使得我们对需求的认知浅薄,不得不随着用户的需求变动反复地改来改去,导致我们很累而用户还不满意,软件研发风险巨大。</p>
<p>正是 DDD 改变了这一切,它要求我们更加**主动地去理解业务,掌握业务领域知识。**这样,我们对业务的理解越深刻,开发出来的产品就越专业,那么客户就越喜欢购买和使用我们的产品。</p>
@@ -172,11 +172,11 @@ function hide_canvas() {
<h3>基于限界上下文的领域建模</h3>
<p>回到 08 讲微服务设计部分,当在线订餐系统完成了事件风暴的分析以后,接着应当怎样设计呢?通过划分限界上下文,已经将系统划分为了“用户注册”“用户下单”“饭店接单”“骑士派送”与“饭店管理”等几个限界上下文,这样的划分也是后端微服务的划分。紧接着,就开始为每一个限界上下文进行领域建模。</p>
<p>首先,<strong></strong><strong>用户下单</strong><strong>上下文开始</strong>。通过业务领域分析,绘制出了如图 2 所示的领域模型,该模型的核心是“订单”,通过“订单”关联了用户与用户地址。一个订单有多个菜品明细,而每个菜品明细都对应了一个菜单,每个菜单隶属于一个饭店。此外,一个订单还关联了它的支付与发票。起初,它们的属性和方法没有那么全面,随着设计的不断深入,不断地细化与完善模型。</p>
<p><img src="assets/Ciqc1F_TJRqAG1xCAAF5cwFJos4897.png" alt="1.png" /></p>
<p><img src="assets/Ciqc1F_TJRqAG1xCAAF5cwFJos4897.png" alt="png" /></p>
<p>在这样的基础上开始划分限界上下文,用户与用户地址属于“用户注册”上下文,饭店与菜单属于“饭店管理”上下文。它们对于“用户下单”上下文来说都是支撑域,即给“用户下单”上下文提供接口调用的。真正属于“用户下单”上下文的,就只有订单、菜品明细、支付、发票这几个类,它们最终形成了“用户下单”微服务及其数据库设计。由于用户姓名、地址、电话等信息,都在“用户注册”上下文中,每次都需要远程接口调用来获得。这时就需要从系统优化的角度,适当将它们冗余到“订单”领域对象中,以提升查询效率。同样,“菜品名称”也进行了冗余,设计更新如图 3 所示:</p>
<p><img src="assets/CgqCHl_TJSiAAYNyAAGLorZ5CTk428.png" alt="2.png" /></p>
<p><img src="assets/CgqCHl_TJSiAAYNyAAGLorZ5CTk428.png" alt="png" /></p>
<p>完成了“用户下单”上下文以后,开始<strong>设计</strong><strong>饭店接单</strong><strong>上下文</strong>,设计如图 4 所示。上一讲谈到,“用户下单”微服务通过<strong>事件通知机制</strong>,将订单以消息的形式发送给“饭店接单”微服务。具体来说,就是将订单与菜品明细发送给“饭店接单”上下文。“饭店接单”上下文会将它们存储在自己的数据库中,并在此基础上增加“饭店接单”类,它与订单是一对一的关系。</p>
<p><img src="assets/Ciqc1F_TJTqAJ682AAF46Z4VQ9M315.png" alt="3.png" /></p>
<p><img src="assets/Ciqc1F_TJTqAJ682AAF46Z4VQ9M315.png" alt="png" /></p>
<p>同样的思路,通过领域事件通知“骑士派送”上下文,完成“<strong>骑士派送</strong><strong>的领域建模</strong></p>
<p>通过以上设计,就将上一讲的微服务拆分,进一步落实到每一个微服务的设计。紧接着,将每一个微服务的设计,按照第 03 讲的思路落实数据库设计,按照第 04 讲的思路落实贫血模型与充血模型的设计。</p>
<p>特别值得注意的是,<strong>订单与菜品明细是一对聚合</strong>。过去按照贫血模型的设计分别为它们设计订单值对象、Service 与 Dao菜品明细值对象、Service 与 Dao现在按照充血模型的设计只有订单领域对象、Service、仓库、工厂与菜品明细包含在订单对象中而订单 Dao 被包含在订单仓库中。贫血模型与充血模型在设计上有明显的差别。关于聚合的实现,下一讲再详细探讨。</p>
@@ -199,7 +199,7 @@ function hide_canvas() {
<p><strong>订单状态的跟踪</strong></p>
<p>当用户下单后,往往会不断地跟踪订单状态是“已下单”“已接单”“已就绪”还是“已派送”。然而,这些状态信息被分散到了各个微服务中,就不可能在“用户下单”上下文中实现了。如何从这些微服务中采集订单的状态信息,又可以保持微服务间的松耦合呢?解决思路还是<strong>领域事件的通知</strong></p>
<p>通过消息队列,每个微服务在执行完某个领域事件的操作以后,就将领域事件封装成消息发送到消息队列中。比如,“用户下单”微服务在完成用户下单以后,将下单事件放到消息队列中。这样,不仅“饭店接单”微服务可以接收这个消息,完成后续的接单操作;而且“订单查询”微服务也可以接收这个消息,实现订单的跟踪。如图 5 所示。</p>
<p><img src="assets/Ciqc1F_PHmeASNLIAAPIbRv-4po922.png" alt="Drawing 4.png" /></p>
<p><img src="assets/Ciqc1F_PHmeASNLIAAPIbRv-4po922.png" alt="png" /></p>
<p>图 5 订单状态的跟踪图</p>
<p>通过领域事件的通知与消息队列的设计,使微服务间调用的设计松耦合,“订单查询”微服务可以像外挂一样采集各种订单状态,同时不影响原有的微服务设计,使得微服务之间实现解耦,降低系统维护的成本。而“订单查询”微服务通过冗余,将“下单时间”“取消时间”“接单时间”“就绪时间”等订单在不同状态下的时间,以及其他相关信息,都保存到订单表中,甚至增加一个“订单状态”记录当前状态,并增加 Redis 缓存的功能。这样的设计就保障了订单跟踪查询的高效。要知道,面对大数据的高效查询,通常都是通过冗余来实现的。</p>
<h3>总结</h3>