轻松学DDD之二:如何高效消化知识
我是2012年开始接触DDD的,后续研读过几遍《领域驱动设计:软件核心复杂性应对之道》,也用DDD做过项目。总的感受是DDD的一些概念比较晦涩难懂,很难掌握,因此想写个系列短文,希望能帮助大家更轻松地理解DDD。文章很多都是我个人体会和理解,难免有错误,希望大家能及时指正,共同探讨提高。前面短文链接:
轻松学DDD之一:模型驱动设计
本文是系列短文第二篇,介绍如何高效消化知识。
1. 知识来源
在讲如何消化知识前,我们要明确下建模的知识来源有哪些。首先我们通过下图来考察模型、领域、软件、现实世界、计算机系统等几个概念的关联。
- 现实世界(蓝线左半边)和计算机系统(蓝线右半边)。我们把用户需求理解为用户要求我们构建一个特定的计算机系统,通过它用户能按自己的期望来改变现实世界。比如淘宝网就是一个这样的计算机系统,通过它阿里巴巴可以让商品销售变得更快捷、更方便、成本更低。
- 领域和软件。领域就是用户需求和从用户需求这个视角出发对现实世界的认知集合;软件就是可以让计算机系统按照用户期望方式来运转的程序。
- 领域模型。它富含领域知识,与实现绑定,能够把领域和软件有效地耦合起来,从而能够让我们基于模型快速开发功能丰富的软件产品。
从上面的认知我们可以知道模型就是在用户目标和软件实现技术的约束下对领域知识的精确化、结构化和抽象。
2. 知识消化
由于建模依赖于在用户目标和软件实现技术约束下的领域知识梳理,因此建模就要求领域专家、建模专家和软件开发之间通过高效地沟通协作来有效地消化领域知识。下面我们从沟通媒介、沟通形式和目标三个方面来展开说明如何做到这一点。
2.1 沟通媒介
消化知识的沟通媒介可以是多种多样,下面是几种主要的沟通媒介:
- 口语:这是人类最擅长的沟通方式,成本低廉,形式丰富,是eric最为推崇的沟通手段。
- 文字:擅长精确表达,同时与口语的转换也非常方便。我们用文字来记录模型中最重要的概念、行为、规则的定义和解释。
- UML:图形形式的UML非常擅长表达对象间的关系和交互,也能有效地指导OO语言的代码编写。但是它不擅长概念的定义,也难以表达对象的行为和约束,需要与文字说明配合。UML图包含了大量的实现细节,大家很难基于它们做高效沟通,同时创建维护它们需要大量的工作量,因此我们往往用简单的非正式的UML图作为讨论的主题。
- 代码:通过代码表达业务细节可以让我们节省大量的文档编写维护的工作量;同时如果代码能够让领域专家容易理解乃至编写,也可以让模型能更好地与实现绑定。但是代码往往充斥实现细节,难以表达整体的、大比例的模型知识。
- 解释性模型:用户驱动软件开发过程的技术模型必须经过严格的精简,受到严格的限制,因此基于技术模型学习领域知识效率很低。解释性模型则没有这些限制,用它可以更快更好地理解领域知识。
总体来讲,我们应该以口语为主要沟通手段,用文字定义重要的领域对象、约束和行为,用简化的非正式UML图表达领域对象间的关联和交互,用代码来承载设计细节,用解释性模型来加快领域知识的学习。
2.2.知识消化的沟通形式
有了沟通手段,我们还需要沟通形式,下面是一些主要的沟通形式:
- 头脑风暴。当一群人围绕一个特定的兴趣领域产生新观点的时候,这种情境就叫做头脑风暴。头脑风暴通过参与者之间充分的思想碰撞来激发新观点和解决方法,因此非常适合在建模初期使用。头脑风暴具体展开形式我们可以采用以简化的UML图为主题,一边讨论一边精炼的方式;也可以采用现在比较流行的事件风暴方式。
- 场景走查。我们可以基于模型来走查各种场景,以便确认模型能够很好地表达和实现各种场景。场景走查是一个成本低廉的试错手段,通过它我们可以避免由于不合理的模型造成软件开发的返工。
- 原型反馈。当建模有初步成果时,开发可以基于现有模型快速实现一个没有界面和持久化数据库的原型,以验证模型的有效性,同时基于原型可以更加直观地与领域专家做进一步沟通。
- 建模专家与开发结对编码。建模专家可以通过与开发的结对编码,可以更加全面地收集模型映射为代码的过程中的各种碰到的问题,这样能更好地识别和修正模型中存在的缺陷。
- 小范围讨论。当模型初步稳定后,模型仍会根据需求变化以及理解的加深不断演进,此时团队中已经有若干能深刻理解模型的骨干,因此对于模型的局部修改,与他们一起做小范围讨论会更加高效。变化的结果可以通过各种方式通知给团队的全体成员。
2.3. 目标
知识消化的最终目标无疑是构建良好的模型,但是构建良好的模型需要通过统一语言和精炼模型来支撑。
2.3.1. 统一语言
统一语言是指团队所有成员用统一的术语来指代领域概念和知识,它有如下几方面:
- 统一的术语。这个可以说是统一语言的起点。
- 术语是精确的。确保术语是精确地指代一个领域概念和知识。当术语的含义模糊、含义过于宽泛、在不同上下文下有不同含义等情况时,往往会造成大家理解上的偏差,最终统一只沦落为形式上的。
- 术语理解不需要翻译。团队有些成员或者角色(比如开发)在理解术语时,会在头脑中把它翻译为另一个更容易理解的术语再来理解。如果有这种情况,请把头脑中的术语也表达出来,大家要重新看看哪个术语能更好地表达领域知识。
- 统一口语、文档和UML等各种形式的语言。同样一个概念不管在口语、文档描述还是UML图中都应该统一起来,否则也容易造成理解偏差。如果有些术语不能郎朗上口,那么就修改为一个可以郎朗上口的术语。
2.3.2 模型精炼
我们知道简单合理的软件设计是软件在长期的开发过程中能够保持低成本修改的关键。在DDD中,领域模型的复杂度决定了软件设计的复杂度,因此模型精炼就是我们消化领域知识的最重要的目标。也就是说我们消化领域知识的目标不是为了理解全部的领域知识;而是为了明确对于实现用户需求而言,哪些领域知识是重要的,哪些是不重要的。模型精炼是一个持续的过程。随着我们对于领域理解的不断深入,模型会持续精炼。随着需求的不断变化,模型关注的最重要的概念也会不断添加和删除。
3. 知识传承
消化知识是如此之难,因此保证这些知识的平稳传承就很重要。尽管这些知识会沉淀在我们的文档、UML和代码等各种物质载体之中,但是它们最重要的载体还是团队中深刻理解了这些知识的核心骨干,因此在软件开发过程中保证这些核心骨干的相对稳定才能保证知识的有效传承,才能最终保证DDD的成功。