[DDD]读书笔记《领域驱动设计:软件核心复杂性应对之道》(3)通过重构来加深理解①

前文回顾

上一篇介绍了该书的第二部分“模型驱动设计的构造块”,将面向对象领域建模中的一些核心的最佳实践提炼为一组基本的构造块。我们在一个模拟的场景中,运用学到的建模知识,处理了假象的需求,并对模型进行了改进。

这一篇,我们开始学习该书的第三部分。这部分,我们会讨论如何将构造块装配为实用的模型,从而实现其价值。这一部分没有直接讨论深奥的设计原则,而是着重强调一个发现过程。有价值的模型不是立即就会出现的,为了对领域一步一步深入理解,需要反复改进这个模型设计。

建模和重构

从第三部分的标题就能看出,这部分的重点在于两个字:重构!前面我们一直在讨论建模,那么重构跟建模有什么关系呢。先不着急,回到建模的问题,想要成功地开发出模型,有几点需要特别注意:

  1. 复杂巧妙的领域模型是可以实现的,也是值得我们去花费力气实现的。
  2. 这样的模型如果没有不断的重构是很难开发出来的,重构需要领域专家和热爱学习领域知识的开发人员密切参与进来。
  3. 要实现并有效地运用模型,需要精通设计技巧。

简单讲:开发好的模型 → 需要不断重构。

重构的分类

重构就是在不改变软件功能的前提下,重新设计软件。作者Eric将重构分为3类:

  1. 改进细节的重构,提升代码可读性、规范性。
  2. 利用设计模式的重构,采用成熟的设计模式,提升代码的重用性、可靠性。
  3. 表达领域模型的重构,基于对领域知识的认知,通过代码清晰地表达模型的含义。

3种类型的重构具有不同的深度,前两种都属于技术角度的重新设计,只有第3种重构才可以得到更深层次的领域模型。这种重构是我们需要重点讨论的,它的目标在于:开发人员通过重构不仅能够了解代码实现的功能,还能明白个中原因,并把它们与领域专家的交流联系起来。

与所有的探索活动一样,建模本质上是非结构化的。要跟随学习与深入思考所指引的一切道路,然后据此重构,才能得到更深层的理解。

深层次的领域模型

通过不断重构可以获得深层次的领域模型,那么何谓深层次? 对象分析的传统方法是先在需求文档中确定名词和动词,并将其作为系统的初始对象和方法。这种方式太过简单,只适用于教导初学者如何进行对象建模。

而深层模型能够穿过领域表象,清楚地表达出领域专家们的主要关注点以及最相关的知识。深层模型可以包含抽象的元素,也可以有具体的元素,它的特点是:功能多样、简单易用、解释力强

从渐进到突破

每一次的重构都是前进的一小步,累计到一定程度就会带来质的飞跃,作者称之为突破,这是领域驱动设计中最令人兴奋的事情。有时,当我们拥有了MODEL DRIVEN DESIGN和显式概念,就能够产生突破。我们有机会使软件更富表达力、更加多样化,甚至会使它变得超乎我们的想象。这可以为软件带来新特性,或者意味着我们可以用简单灵活的方式来表达更深层次的模型,从而替换掉大段死板的代码。

image.png

重构的投入与回报并非呈线性关系。通常,小的调整会带来小的回报,小的改进也会积少成多。小改进可防止系统退化,这是防止模型腐化的第一步。不断重构,带来一系列快速的改变,得到了更符合用户需要并更加切合实际的模型。其功能性及说明性急速增强,而复杂性却随之消失。

一个小故事

在很多年前的美国纽约,作者和他的团队经过一个漫长冬天的重构,终于得到了一个反映了一些领域知识的模型。他们在给一家投资银行开发用于管理贷款的软件。

当一家公司(如华为)需要一笔巨额贷款(比如10亿美元)用于建造工厂,由于额度太大,没有一家借贷公司(lending company)可以单独承担。于是多家公司一起组成银团,发放银团贷款。 借贷公司(lending company)对于借款者(borrower)而言是放贷方(lender),对于银团而言是投资者(investor)。

作者得到了如下模型,在商业银行领域中,Facility(信用贷款)是公司为借款而作出的承诺,相当于贷款额度。信用卡就是一种信贷,卡片持有者有权在需要时借出不超过预设限额的资金,并且以预定利息还款。LoanInvestment(贷款投资)是一个派生对象,用来表示某一投资者(即借贷公司)在Loan(贷款)中所承担的股份,它与投资者在Facility(信用贷款)中所持有的股份(Investment)成正比。

image.png

当预料之外的需求出现时,这个模型的不足之处开始显现出来。在借款者提取(Drawdown)贷款时,信贷股份比例只是放贷方投入金额的指导原则,实际出资时放贷方可以跟银团其他成员协商,以调整投入金额。于是模型中加入了LoanAdjustment(贷款调整)。

image.png

模型虽然反映了贷款调整,但是复杂度也随之增加,更严重的是复杂的算法降低了舍入运算的精度,即使差异只有几分钱,也会造成非常不好的客户体验。在重构过程中,作者领悟到了问题的关键,即Facility的股份和Loan的股份被绑定在了一起。而实际业务中,两者互不影响,可以独立发生改变。

比如下图中的信贷(Facility)的限额是1亿美元,借款方决定提取(Drawdown)一笔5000万美元的借款(Loan)。3个放贷方决定按照Facility的股份来支付。 image.png

随后借款方又决定提取一笔3000万美元的借款,这次公司B选择不参加,由公司A承担。 image.png

当借款方偿还1000万美金的借款时,本金会按照Loan的股份来分配给放贷方,而不是按照Facility的股份来分配。

image.png

另一方面,当借款方支付费用(如信用卡年费)时,是按照Facility的股份来分配的。 image.png

作者从这个故事中领悟到,不要试图去制造突破,那只会使项目陷入困境。通常,只有在实现了许多适度的重构后才有可能出现突破。

猜你喜欢

转载自juejin.im/post/7017736928938164232