字节一面挂了,面试官问DDD,我却不知道

日常产研迭代常见的问题

在介绍DDD(Domain-Driven Design:领域驱动设计)之前,我们先回顾一下,现阶段的产品迭代中常常出现的一些问题,以及这些问题会导致什么。通过对问题的总结和分析,再回头看一看,DDD能帮我们解决什么?

首先,针对业务价值方面

面对繁杂的业务需求和团队中良莠不齐的技术人员,如何确定哪些需求可以真正的传递业务价值?如何去针对业务价值高低进行需求优先级的排序?

其次,针对领域专家与开发人员之间的关系

在开发过程中,最大的鸿沟之一就存在于领域专家和开发人员之间。领域专家关注交付业务价值上,而研发人员关注在技术实现上

即便让他们一同工作,他们之间的协作也是表面的,这时候,在所开发的软件中便产生了如下的一种映射:

  • 将业务人员所想的映射到开发者所理解的。这样一来,软件便不能完全反映出领域专家的思维模型。
  • 随着时间的推移,这种鸿沟将增加软件的开发成本,而随着开发者转到其他项目或者离职,本应该驻留在软件中的领域知识也就丢失了。

第三,针对多个领域专家之间的关系

多个领域专家之间存在分歧的时候,他们各抒己见的对业务需求进行影响,而没有一个“地方”可以让他们坐下来统一分歧,然后“一致对外”。在这种分歧的情况下,会很大程度的导致相互矛盾的软件模型。

最后,软件的技术实现可能错误地改变软件原有的业务规则

需求交流的时候,大家彼此都没什么问题。但是,随着开发过程中的很多不确定因素,比如:临时插入紧急事情导致研发计划被打乱、研发时间大大超出合理范围、技术上无法对需求进行落地等等。那么最终交付的产品功能,有可能就跟需求交流时的设想大相径庭了

DDD能帮我们做什么

我们回顾完产品迭代过程中场景的一些问题后,我们就把视野转换到DDD上面,来看一下DDD能帮我们做什么?

首先,使领域专家和开发者一起工作,将他们组成一个密切协作的团队,这样开发出来的软件能够准确地传达业务规则(代码就好像是领域专家编写出来似的)。

其次,可以帮助业务人员自我提高。没有任何一个领域专家或者管理者敢说他对业务已经了如指掌了,业务知识也需要一个长期的学习过程。在DDD中,每个人都在学习,同时每个人又是知识的贡献者。关键在于对知识的集中,因为这样可以确保软件知识并不只是掌握在少数人手中。以免开发人员编码好久,还依然不知道自己涉猎的业务到底是什么。

第三,在领域专家、开发者和软件本身之间不存在“翻译”,意思是当大家都使用相同的语言(领域语言)进行交流时,每个人都能听懂他人所说的话。设计就是代码,代码就是设计。设计是关于软件如何工作的,最好的编码设计来自于多次试验,这得益于敏捷的发现过程。

第四,DDD同时提供了“战略设计”和“战术设计”两种方式:

  • 战略设计:帮助我们理解哪些投入是最重要的;哪些既有软件资产是可以重新拿来使用的;哪些人应该被加入到团队中。
  • 战术设计:帮助我们创建DDD模型中各个部件。

迟来的概述

通过上面的内容,大家应该可以对DDD的作用有了一些大致的认识了。那么,这个迟来的关于DDD的概述,就放在这部分吧。算是在理论定义上对DDD再来一次补充式的认知。

领域驱动设计(DDD)作为一种软件开发方法,可以帮助我们设计出高质量的、能够准确表达业务意图的软件模型。

你应该期待从DDD中得到什么呢?

  • 首先,DDD不应该是一个仪式性的过程,更不应该成为你项目进度的阻碍。
  • 其次,DDD同时提供了战略上和战术上的建模工具来帮助我们设计高质量的软件模型。

需要大家注意的是,DDD不是关于技术的,而是关于讨论、聆听、理解、发现和业务价值的,而这些都是为了将知识集中起来,构建集中化的业务知识体系

在实践DDD的过程中,你最好将那些不怎么使用技术语言的人(业务领域专家)加进自己的团队,此时你得仔细地聆听他们,还应该尊重他们的观点,并且相信他们比你了解得更多。

谁才是领域专家?

  • 领域专家并不是一个职位,他可以是精通业务的任何人——销售、产品经理、软件开发人员......

什么是领域模型?

  • 领域模型是关于某个特定业务领域的软件模型。通常,领域模型通过对象模型来实现(对象=数据+行为),并且表达了准确的业务含义。

贫血领域模型

什么是贫血领域对象?

领域对象中主要是一些公有的getter和setter方法,并且在这些方法中,几乎没有业务逻辑,而仅仅是用来赋值或者获取属性值

针对领域对象的业务逻辑并不在领域对象中,而是被封装到了服务层(Service Layer) 或者 应用层(Application Layer)

贫血领域对象怎么了?

贫血领域对象是不好的,因为它根本就不是领域对象,而只是将关系型数据库中的模型映射到了对象上而已。

最初是在窗口设计领域上,将getter和setter变得过于流行了。而我们熟知的Java Bean标准最早是用来辅助Java的可视化设计工具的。此外,市场上几乎大部分框架都要求对象暴露公有属性。这样一来,开发者们只能被动地接收那些贫血对象。于是我们便到了“到处都是贫血对象”的地步。

我们以一个贫血对象为例,下面是其使用的例子:

以上代码很通用,可以根据入参去创建或修改customer实例。但是,上面的代码能够表达什么业务逻辑呢?我们通过上面的代码,并不知道saveCustomer()这个方法的业务场景是什么。为什么一开始会创建这个方法?这个方法的本来意图是什么呢?还是这个方法本来就是用来满足不同业务需求的?我从哪里可以知道创建这个方法的“鼻祖”程序员当时为什么创建这个方法呢?

由于贫血模型不包含领域相关业务逻辑,所以通过贫血模型,我们根本无法解答上面的问题。此时我们就需要结合服务层(Service Layer)或者应用层(Application Layer)的代码,找到调用saveCustomer()这个方法的所有相关代码,再去逐一向上梳理业务流程或含义。要搞明白这里面的缘由,可能需要花上几个小时甚至几天的时间。

通用语言

首先,我们先学习DDD武器库里的——通用语言。

在DDD中,通用语言限界上下文,同时构成了DDD的两大支柱,并且它们是相辅相成的。本篇文章我们会先介绍通用语言,后续文章再来介绍限界上下文。

什么是通用语言

我们可以将限界上下文看成是整个应用程序之内的概念性边界。这个边界之内的每种领域术语、词组或句子——也就是通用语言,都有确定的上下文含义。通用语言是团队共享的语言,是团队自己创建的公用语言。团队中同时包含领域专家和软件开发人员。自然地,领域专家对通用语言有很大的影响,因为他最了解业务。

通用语言更多地是关于业务本身如何思考和运作的。它就像其他语言一样,也会随着时间推移而不断演化改变

通用语言在团队范围内使用,并且只表达一个单一的领域模型。限界上下文和通用语言是一对一的关系

限界上下文是一个相对较小的概念,它刚好能够容纳下一个独立的业务领域锁使用的通用语言

当多个限界上下文需要“打交道”时,我们可以通过上下文映射图对这些限界上下文进行集成

我们以“护士给病人注射标准剂量的流感疫苗”为例,看看如何通过代码可以表现出实际的业务流程:

你该如何掌握通用语言呢?

首先,同时绘制物理模型图概念模型图,并标以名字和行为。

其次,创建一个包含简单定义的术语表。包括好的和不好的,并注明好与不好的原因。

最后,改进之后的通用语言将反映到系统的源代码中

由于团队交流和代码才是对通用语言的持续表达,你应该试着抛弃那些模型图、术语表和文档。虽然这并不是DDD所要求的,但是这样做的确很实用,因为我们很难将项目文档和软件系统保持同步

改造贫血领域模型

通过上面的学习,我们已经掌握了DDD的很多知识,并且也拥有了通用语言这把武器。在上面我们看到了一个saveCustomer方法所涉及的贫血模型,下面我们利用自己掌握的DDD相关知识,对它进行一个小改造。

首先,我们提供一个Customer接口,根据与领域专家的沟通,确定业务所需要的接口有哪些,并且在Customer接口中提供出来。这样通过接口代码就能够反映出它所支持的业务操作,即:通过代码来反映业务。如下所示:

【解释】通过上面的方式,我们可以体现出Customer是支持哪些业务操作的。而哪些业务操作它是不支持的。

另外,我们还需要知道,对领域模型的修改也将导致对应用层的修改。每一个应用层的方法都对应着一个单一的用例流,而不像上面的saveCustomer方法那样,我们使用了同一个方法来处理多个用例流。如下所示:

总结

作为DDD系列的第一篇文章,我们通过一些图表和例子,对其有一个形象的认知。由于它本身包含的战略设计和战术设计内容还很多,后续我们会再继续的学习DDD中的其他知识内容

猜你喜欢

转载自blog.csdn.net/Trouvailless/article/details/125873913