一 领域驱动设计-运用领域模型-消化知识
运用领域模型-消化知识
示例
有效建模的要素
知识消化
持续学习
知识丰富的设计
深层模型
运用领域模型-消化知识
非原创,感谢《领域驱动设计》这本书
有效建模的要素
(1) 模型和实现的绑定。最初的原型虽然简陋,但它在模型与实现之间建立了早期链接,而且在所有后续的迭代中我们一直在维护该链接。
(2) 建立了一种基于模型的语言。随着项目的进展,双方都能够直接使用模型中的术语,并将它们组织为符合模型结构的语句,而且无需翻译即可理解互相要表达的意思。
个人理解:定义专业词语的字典解释,保证每个人对每个术语的理解都是一样的
(3) 开发一个蕴含丰富知识的模型。对象具有行为和强制性规则。模型并不仅仅是一种数据模式,它还是解决复杂问题不可或缺的部分。模型包含各种类型的知识。
(4) 提炼模型。在模型日趋完整的过程中,重要的概念不断被添加到模型中,但同样重要的是,不再使用的或不重要的概念则从模型中被移除。当一个不需要的概念与一个需要的概念有关联时,则把重要的概念提取到一个新模型中,其他那些不要的概念就可以丢弃了。
(5) 头脑风暴和实验。语言和草图,再加上头脑风暴活动,将我们的讨论变成“模型实验室”,在这些讨论中可以演示、尝试和判断上百种变化。当团队走查场景时,口头表达本身就可以作为所提议的模型的可行性测试,因为人们听到口头表达后,就能立即分辨出它是表达得清楚、简捷,还是表达得很笨拙。
正是头脑风暴和大量实验的创造力才使我们找到了一个富含知识的模型并对它进行提炼,在这个过程中,基于模型的语言提供了很大帮助,而且贯穿整个实现过程中的反馈闭环也对模型起到了“训练”作用。这种知识消化将团队的知识转化为有价值的模型。
知识消化
金融分析师要消化理解的内容是数字。他们筛选大量的详细数字,对其进行组合和重组以便寻求潜在的意义,查找可以产生重要影响的简单表示方式——一种可用作金融决策基础的理解。
高效的领域建模人员是知识的消化者。他们在大量信息中探寻有用的部分。他们不断尝试各种信息组织方式,努力寻找对大量信息有意义的简单视图。很多模型在尝试后被放弃或改造。只有找到一组适用于所有细节的抽象概念后,工作才算成功。这一精华严谨地表示了所发现的最为相关的知识。
知识消化并非一项孤立的活动,它一般是在开发人员的领导下,由开发人员与领域专家组成的团队来共同协作。他们共同收集信息,并通过消化而将它组织为有用的形式。信息的原始资料来自领域专家头脑中的知识、现有系统的用户,以及技术团队以前在相关遗留系统或同领域的其他项目中积累的经验。信息的形式也多种多样,有可能是为项目编写的文档,有可能是业务中使用的文件,也有可能来自大量的讨论。早期版本或原型将经验反馈给团队,然后团队对一些解释做出修改。
在传统的瀑布方法中,业务专家与分析员进行讨论,分析员消化理解这些知识后,对其进行抽象并将结果传递给程序员,再由程序员编写软件代码。由于这种方法完全没有反馈,因此总是失败。分析员全权负责创建模型,但他们创建的模型只是基于业务专家的意见。他们既没有向程序员学习的机会,也得不到早期软件版本的经验。知识只是朝一个方向流动,而且不会累积。
个人理解:现在依然有公司在这样做,业务需求人员定义需求,再由架构师或者组长进行翻译,之后直接分配给程序员任务,最后做出的程序往往和需求偏差较远,大部分会议是组行和业务参加,真正实现功能的程序员没有参与到会议讨论中来。
有些项目使用了迭代过程,但由于没有对知识进行抽象而无法建立起知识体系。开发人员听专家们描述某项所需的特性,然后开始构建它。他们将结果展示给专家,并询问接下来做什么。如果程序员愿意进行重构,则能够保持软件足够整洁,以便继续扩展它;但如果程序员对领域不感兴趣,则他们只会了解程序应该执行的功能,而不去了解它背后的原理。虽然这样也能开发出可用的软件,但项目永远也不会从原有特性中自然地扩展出强大的新特性。
好的程序员会自然而然地抽象并开发出一个可以完成更多工作的模型。但如果在建模时只是技术人员唱独角戏,而没有领域专家的协作,那么得到的概念将是很幼稚的。使用这些肤浅知识开发出来的软件只能做基本工作,而无法充分反映出领域专家的思考方式。
在团队所有成员一起消化理解模型的过程中,他们之间的交互也会发生变化。领域模型的不断精化迫使开发人员学习重要的业务原理,而不是机械地进行功能开发。领域专家被迫提炼自己已知道的重要知识的过程往往也是完善其自身理解的过程,而且他们会渐渐理解软件项目所必需的概念严谨性。
有这些因素都促使团队成员成为更合格的知识消化者。他们对知识去粗取精。他们将模型重塑为更有用的形式。由于分析员和程序员将自己的知识输入到了模型中,因此模型的组织更严密,抽象也更为整洁,从而为实现提供了更大支持。同时,由于领域专家也将他们的知识输入到了模型中,因此模型反映了业务的深层次知识,而且真正的业务原则得以抽象。
模型在不断改进的同时,也成为组织项目信息流的工具。模型聚焦于需求分析。它与编程和设计紧密交互。它通过良性循环加深团队成员对领域的理解,使他们更透彻地理解模型,并对其进一步精化。模型永远都不会是完美的,因为它是一个不断演化完善的过程。模型对理解领域必须是切实可用的。它们必须非常精确,以便使应用程序易于实现和理解。
个人理解:对于业务和开发来说,最大的问题是思维想法的同步,同步最大的问题是交流沟通,程序员大部分相对内向沉默,业务有时候也会厌烦重复的表述,造成理解偏差。建立模型并共同改进精化可以很好的解决这个问题,既然开发人员的思维方式(机器思维)和业务人员的思维方式(功能结果导向思维)不同,那么就使用一个中间翻译的语言,这个语言就叫做模型,也是抽象的模型。是大家一起来制定的一种抽象表达方式,每个人都要参与其中,并且不断进行更新。模型也充当了业务转化为开发逻辑的一种中间过程表示。
持续学习
当开始编写软件时,其实我们所知甚少。项目知识零散地分散在很多人和文档中,其中夹杂着其他一些无关信息,因此我们甚至不知道哪些知识是真正需要的知识。看起来没什么技术难度的领域很可能是一种错觉——我们并没意识到不知道的东西究竟有多少。这种无知往往会导致我们做出错误的假设。
同时,所有项目都会丢失知识。已经学到了一些知识的人可能干别的事去了。团队可能由于重组而被拆散,这导致知识又重新分散开。被外包出去的关键子系统可能只交回了代码,而不会将知识传递回来。而且当使用典型的设计方法时,代码和文档不会以一种有用的形式表示出这些来之不易的知识,因此一旦由于某种原因人们没有口头传递知识,那么知识就丢失了。
个人理解:团队的解散,人员的离职或变更,文档的丢失和散乱,都会使项目组丢失知识,有时候代码写完了但是没有文档或者注释(程序员黑话:先开发产品功能,后写文档,其实就是懒得写),别人接手需要经历非常大的痛苦,然后疯狂吐槽以前的开发人员。这些都可以归于知识的丢失。
高效率的团队需要有意识地积累知识,并持续学习。对于开发人员来说,这意味着既要完善技术知识,也要培养一般的领域建模技巧。但这也包括认真学习他们正在从事的特定领域的知识。那些善于自学的团队成员会成为团队的中坚力量,涉及最关键领域的开发任务要靠他们来攻克,这个核心团队头脑中积累的知识使他们成为更高效的知识消化者。
关键的模型元素被保留下来,早期工作启动了知识消化的过程,这使得所有后续工作更加高效:团队成员、开发人员和领域专家等都学到了知识,他们开始使用一种公共的语言,而且形成了贯穿整个实现过程的反馈闭环。
个人理解:所有人都参与,制定模型,学习知识(业务逻辑或者开发思维或者处理流程等等都是知识),后期团队效率会非常高,就算人员变更,只需要理解开发过程中一起制定的模型就可以了。
知识丰富的设计
当我们的建模不再局限于寻找实体和值对象时,我们才能充分吸取知识,因为业务规则之间可能会存在不一致。领域专家在反复研究所有规则、解决规则之间的矛盾以及以常识来弥补规则的不足等一系列工作中,往往不会意识到他们的思考过程有多么复杂。软件是无法完成这一工作的。正是通过与软件专家紧密协作来消化知识的过程才使得规则得以澄清和充实,并消除规则之间的矛盾以及删除一些无用规则。
个人理解:业务或者产品如果不懂开发,会提出一些天马行空的功能,不会意识到他们的想法实现起来由多复杂。比如:产品经理要程序要开发一个功能,要求app根据手机壳的颜色而改变主题颜色(新闻有报道,产品经理被打了,哈哈哈)。大家一起紧密协作来消化知识,可以消除这些矛盾或者无用的想法。
示例
我们从一个非常简单的领域模型开始学习,基于此模型的应用程序用来预订一艘船在一次航程中要运载的货物
们规定这个应用程序的任务是将每件货物(Cargo)与一次航程(Voyage)关联起来,记录并跟踪这种关系。现在看来一切都还算简单。应用程序代码中可能会有一个像下面这样的方法
由于总会有人在最后一刻取消订单,因此航运业的一般做法是接受比其运载能力多一些的货物。这称为“超订”。有时使用一个简单的容量百分比来表示,如预订110%的载货量。有时则采用复杂的规则——主要客户或特定种类的货物优先。这是航运领域的一个基本策略,从事航运业的业务人员都知道它,但在软件团队中可能不是所有技术人员都知道这条规则。需求文档中包含下面这句话:允许10%的超订。(这个时候由问题了哈)
现在,一条重要的业务规则被隐藏在上面这段方法代码内,非常容易误解,我们主要考虑如何把这条规则更清楚地表达出来,并让项目中的每个人都能了解到它。这将使我们得到一个类似的解决方案。
(1) 如果业务规则如上述代码所写,不可能有业务专家会通过阅读这段代码来检验规则,即使在开发人员的帮助下也无法完成。
(2) 非业务的技术人员很难将需求文本与代码联系起来。如果规则更复杂,情况将更糟。
修改成下面这样:
现在所有人都清楚超订是一个独特的策略,而且超订规则的实现即明确又独立。
现在,我并不建议将这样的精细设计应用到领域的每个细节中。第15章将深入阐述如何关注重点以及如何隔离其他问题或使这些问题最小化。这个例子的目的是说明领域模型和相应的设计可用来保护和共享知识。更明确的设计具有以下优点:
(1) 为了实现更明确的设计,程序员和其他各位相关人员都必须理解超订的本质,明白它是一个明确且重要的业务规则,而不只是一个不起眼的计算。
(2) 程序员可以向业务专家展示技术工件,甚至是代码,但应该是领域专家(在程序员指导下)可以理解的,以便形成反馈闭环。
个人理解:模型要把重要的细节表达出来,不能隐藏的自己知道的认知中(就不告诉别人,说你这样做就行了,这样不好),要体现出为什么是这样的,是什么导致必须要加入这个,要让模型在成为沟通的桥梁时更加明确易懂。
深层模型
有用的模型很少停留在表面。随着对领域和应用程序需求的理解逐步加深,我们往往会丢弃那些最初看起来很重要的表面元素,或者切换它们的角度。这时,一些开始时不可能发现的巧妙抽象就会渐渐浮出水面,而它们恰恰切中问题的要害。
前面的例子大体上是基于一个集装箱航运项目,这是本书列举的几个项目之一,本书还有几个示例会引用这个项目。本书所举的示例都很简单,即使不是航运专家也能理解它们。但在一个需要团队成员持续学习的真实项目中,要想建立实用且清晰的模型则要求团队成员既精通领域知识,也要精通建模技术。
在这个项目中,由于航运从预订货运开始,因此我们开发了一个能够描述货物和运货航线等事物的模型。这是必要且有用的,但领域专家却不买账。他们有自己的考虑业务的方式,这种方式是我们没有考虑到的。
最后,在经过几个月的知识消化后,我们知道货物的处理主要是由转包商或公司中的操作人员完成的,这包括实际的装货、卸货和运货。航运专家的观点是,各部分之间存在一系列的责任传递。法律责任和执行责任的传递由一个过程控制—从托运人传递到某个本地运输商,再从这家运输商传递到另一家运输商,最后到达收货人。通常,在一些重要的步骤中,货物停放在仓库里。在其他时间里,货物则是通过复杂的物理步骤来运输,而这些与航运公司的业务决策无关。在处理航线的物流之前,必须先确定诸如提单等法律文件以及支付流程。
对航运业务有了更深刻的认识后,我们并没有删除Itinerary(航线)对象,但模型发生了巨大改变。我们对航运业务的认识从“集装箱在各个地点之间的运输”转变为“运货责任在各个实体之间的传递”。处理这些责任传递的特性不再是一些附属于装货作业的次要特性,而是由一个独立的模型来提供支持,这个模型正是在理解了作业与责任之间的重要关系之后开发出来的。
知识消化是一种探索,它永无止境。
个人理解:随着对业务的理解更加深刻以后,模型同时也要进行更新,会变得复杂,怎么办?开发容易理解的一种形式是:就相当于sql中做子查询,java开发中就小模块封装,大模块调用函数。模型也是一样,再做一个新模型,对某一部分功能做抽象,由大模型链接过去。例如:a-b-c原来是一个模型,后来增加到a-b-c-c1-c2-c3,c的功能原来越多,这个时候可以做成这样:模型1是a-b-C,模型C(独立小模型):c1-c2-c3。这就是深层模型的理解。