DDD建模系列(四)

简介: DDD建模系列(四)

一、管理面问题:传统scrum敏捷流程中的问题

设计和编码断层

在传统的迭代流程存在设计和编码断层,大致如下:

1、先看设计和编码断层

①、大部分的开发过程,弱化设计环节,简化设计环节,先把库表,接口定义个大概/七七八八,写个简单的设计文档就开始开发。

②、如果比较急,或者自认为对需求很熟悉,会省略这个已经简单到不能再简单,少到不能再少的设计流程,对着原型开始编码,开始建表,然后定义好API接口,就开始编码了。

上面的流程是轻量级的迭代流程。

敏捷迭代:周期快,你和开发经理去讨论他为什么不做好设计,他会说,不要把流程搞的那么重嘛!开发经理的意思,进度要紧,先把时间放在重要的事情上面。

开发经理的目标:编码搞定,改改上线,就是最重要的,什么软件生命质量,软件生命值,先靠边站着,回头再说。

这样导致的问题是:

①、初级开发并没有理解需求,其实并没有搞清楚需求,一周之后看成果,发现走弯路,或者白干了。另外,中高级甚至架构师,其实也有看走眼的时候。由于设计不充分,往往写到一半,会冒出一个一个的隐形字段,隐形流程,隐形接口,都是由于之前没有分析清楚,写着写着,都冒出来了。

②、数据驱动开发,从库表,到接口定义到开发代码,一气呵成,速度快,但是忘记做变和不变的隔离,造成了变和不变的紧密耦合,埋下无数地雷。

现在大家都是敏捷迭代,极速迭代,快速试错,流程不能太重。

所以,开发经理的理由也是非常充分的:后面的事情后面再说,先实现功能。

在看业务和开发隔离

业务干完PRD,人家就准备看下一个版本的需求,并等着验收这一个版本的产品。

开发这个时候在蒙头干活,吭哧吭哧写代码。

同一个词,同一个功能,如果理解有偏差,大家各自留心底,互不感知。

只有等到验收的时候,业务说,我说的流程不是这样的,你其实没有理解需求。当然,开发也不是傻子,不会坐以待毙,然后开始各种甩锅,各种扯皮。

根本的原因:业务和开发隔离。

如何强化设计与编码的依赖,拉通业务与开发的断层。

其实,DDD绝对是拯救传统开发流程的神药:它拉通业务与开发的隔离,强化设计与编码的依赖关系。

30f592539d58d78147fc3f79ec4e9b2f.png

拉通业务与开发的隔离的办法:引入领域专家,使用通用语言进行领域驱动建模。

什么是通用语言?

比如电商系统项目组的成员在一起讨论问题:

①、程序员A:我们购买商家的产品

②、程序员B:用户买商品

③、产品经理:我们采购店家商品

④、测试人员:用户购买物品

......................

以上大家其实要表达的意思都是一样的,但是不统一。

所以,通用语言最终结果,就是需求沟通没有歧义,同一个词,有大家都明确了定义。

在事件风暴过程中,通过团队交流达成共识的,能够简单,清晰,准确描述业务涵义和规则的语言就是通用语言。也就是说,通用语言是团队统一的语言,不管你在团队中承担什么角色,在同一个领域的软件生命周期里都使用统一的语言进行交流。

通用语言包含术语和用例场景,并且能够直接反映在代码中

通用语言的名词可以给领域对象命名,如商品,订单等,对应实体对象;而动词则表示一个动作或者事件,如商品已下单,订单已付款等,对应领域事件或者命令。

通用语言贯穿DDD的整个设计过程,作为项目团队沟通和协商形成的统一语言,基于它,你就能够开发出可读性更好的代码,将业务需求准确转化为代码设计。

DDD领域驱动的关键点和流程特点

领域驱动指的是以领域作为解决问题切入点,面对业务需求,先提炼出领域概念,并构建领域模型来表达业务问题,而构建过程中我们应该尽可能避免牵扯技术方案或者技术细节。

而编码实现更像是对领域模型的代码翻译,代码(变量名,方法名,类名)中要求能够表达领域概念,让人见码明义。

ff4bf740680532e820706f8dd7a830f6.png

特点之一:思维模式改变

实践DDD以前,最常使用的是数据库驱动设计

它的核心思路针对业务需求进行数据建模:根据业务需求提炼出类,然后通过ORM把类映射为表结构,并根据读写性能要求使用范式优化表与表之间的关联关系。

数据驱动是从技术的维度解决业务问题,得出的数据模型是对业务需求的直接翻译,并没有蕴含稳定的领域知识/规则

一旦需求发生变化,数据模型就得发生了变化,对应的库表的设计也需要进行调整。

这种设计思维导致变化从需求穿透到了数据层,中间并没有稳定的,不易变的层级进行阻隔,最终导致系统响应变化的能力很差。

特点之二:协同方式转变

数据驱动设计模式下,产品提需求,研发设计方案,并编码实现

这种协同式的弊端在于:无法形成能够消除认知差异的模型

产品同学从业务角度提出需求,这些需求可能是易变的,定制化的。

而研发同学在缺少行业经验的情况下,往往会选择直译,即根据需求直接转换为数据模型。

而研发同学从技术实现角度设计技术方案,其中涉及很多的技术细节,产品同学无法从中判断是否与自己提出的业务诉求和产品规划相一致,最终形成认知差异。且认知差异会随着迭代不断被放大,最后系统形成一个大泥球。

e6fd8e8aad0ef9b3f74928bd937966a0.png

DDD通过解锁新角色"领域专家“,以及模型驱动设计,有效地降低产品和研发的认知差异。

领域专家是具有丰富行业经验和领域知识储备的人,他们能够在易变的,定制化的需求中提炼出清晰的边界,稳定的,可复用的领域概念和业务规则,并携手产品和研发共同构建出领域模型。

设计的根本思想:分离变和不变。

保证领域模型的稳定性,提升代码的生命值。

领域模型是对业务需求的知识表达形式,它不涉及具体的技术细节(但能够指导研发同学进行编码实现),因此消除了产品和研发在需求认知上的鸿沟。

而模型驱动设计则要求领域模型能够关联业务需求和编码实现,模型的变更意味着需求变更和代码变更,协作围绕模型中心。

b050fae78d6f5795d5f21e85e94753c7.png

特点之三:精炼循环

精炼循环指的是在统一语言,提炼领域概念,明确边界,构建模型,绑定实现过程中,这些环节相互影响,相互反馈,在不断的迭代试错,不断反馈,不断调整,最终沉淀出稳定的,深层次的模型的过程。

比如:我们在提炼领域概念的时候会觉得统一语言定义不合理/有歧义,此时我们就会调整统一语言的定义,并重新进行提炼领域模型。

通过精炼循环,我们逐步形成稳定的领域模型,设计的根本思想:分离变和不变。

①、识别出稳定的领域模型

②、分离出不稳定的领域模型

保证领域模型的稳定性,提升代码的生命值。

在DDD中,让领域专家来主导概念提炼,边界划分等宏观设计,原因就在于领域专家的经验和行业洞见来源于过去已经迭代的无数个精炼循环,因此由这些宏观设计推导出来的领域模型,往往都是非常稳定的。

精炼循环的核心是循环,它避免知识只朝单一方向流动,最终因各环节上的认知差异,最终导致模型无法在产品,领域专家和研发中达成一致,模型与实现割裂。

相关文章
真下饭!字节技术官DDD(领域驱动设计)手册,拆解业务代码首选
至少20年前,一些顶尖的软件设计人员就已经认识到领域建模和设计的重要性,但令人惊讶的是,这么长时间以来几乎没有人写出点儿什么,告诉大家应该做哪些工作或如何去做。尽管这些工作还没有被清楚地表述出来,但一种新的思潮已经形成,它像一股暗流一样在对象社区中涌动,我把这种思潮称为领域驱动设计(domain-driven design)。
|
设计模式 前端开发 关系型数据库
【DDD】全网最详细2万字讲解DDD,从理论到实战(代码示例) 3
【DDD】全网最详细2万字讲解DDD,从理论到实战(代码示例)
5901 2
|
微服务 测试技术 Java
阿里技术专家详解 DDD 系列- Domain Primitive
关于DDD的一系列文章,希望能继续在总结前人的基础上发扬光大DDD的思想,但是通过一套我认为合理的代码结构、框架和约束,来降低DDD的实践门槛,提升代码质量、可测试性、安全性、健壮性。
62661 17
阿里技术专家详解 DDD 系列- Domain Primitive
|
前端开发 测试技术 人机交互
DDD - 理论到落地从统一语言开始
DDD - 理论到落地从统一语言开始
1199 0
|
设计模式 弹性计算 人工智能
阿里技术专家详解DDD系列 第四讲 - 领域层设计规范
在一个DDD架构设计中,领域层的设计合理性会直接影响整个架构的代码结构以及应用层、基础设施层的设计。但是领域层设计又是有挑战的任务,特别是在一个业务逻辑相对复杂应用中,每一个业务规则是应该放在Entity、ValueObject 还是 DomainService是值得用心思考的,既要避免未来的扩展性差,又要确保不会过度设计导致复杂性。
|
SQL 缓存 Java
殷浩详解DDD系列 第三讲 - Repository模式
# 第三讲 - Repository模式 **写在前面** 这篇文章和上一篇隔了比较久,一方面是工作比较忙,另一方面是在讲Repository之前其实应该先讲Entity(实体)、Aggregate Root(聚合根)、Bounded Context(限界上下文)等概念。但在实际写的过程中,发现单纯讲Entity相关的东西会比较抽象,很难落地。所以本文被推倒重来,从Repository
38628 8
|
存储 Java API
阿里高级技术专家谈开源DDD框架:COLA4.1,分离架构和组件(下)
阿里高级技术专家谈开源DDD框架:COLA4.1,分离架构和组件(下)
11754 8
阿里高级技术专家谈开源DDD框架:COLA4.1,分离架构和组件(下)
|
消息中间件 网络协议 前端开发
殷浩详解DDD:如何避免写流水账代码?
在日常工作中我观察到,面对老系统重构和迁移场景,有大量代码属于流水账代码,通常能看到开发在对外的API接口里直接写业务逻辑代码,或者在一个服务里大量的堆接口,导致业务逻辑实际无法收敛,接口复用性比较差。所以本文主要想系统性的解释一下如何通过DDD的重构,将原有的流水账代码改造为逻辑清晰、职责分明的模块。
殷浩详解DDD:如何避免写流水账代码?