DDD 项目失败的几个原因

简介: DDD 项目失败的几个原因

为什么想写这个,主要是感受到同志们的学习高潮,恨不得各种练习,但又遭遇到一些挑战,比如“我想在项目中推行DDD,但担心其他人不配合”,“DDD门槛太高,概念多”......



image.png


image.png


就笔者之所见,一个标榜实践TDD的项目要不是口号,噱头,要不就失败了,如同要推行DDD的一样。项目不是兵器的练兵场,首先要回到“问题域”,要解决什么问题。


一个以推行DDD为目标的项目,总觉得有点慌。


就笔者之所见所闻,有1个典型的推广XXX的case。

一个是某司的一位空降boss,是一位有创派别的国内“敏捷”专家。当然,敏捷专家几乎都耻于谈敏捷 ,这样也就和其他人谈的“敏捷”无法区分开去。空降boss一来大谈敏捷实践和各种老外前辈云云,但却被团队吐槽,因为那会这群码农最关心的是“生存问题”,去总部找活回来干的问题 。几个月后这位boss转变了思路,通过抓稳定迭代的release,促进快速反馈,赢得了团队尊重和客户认可。


这个case,让人懂得了 一个道理,一位病人发烧了,医生可以先采取措施让他退烧,然后治疗。病人并不喜欢医生跟他讲中西医区别,药理知识。第二个道理就是,鸡蛋好吃,你非要去分辨是那只鸡下的蛋,并无多大必要。


团队员工的期待是空降老板给我们指方向,找活干,加薪而不是推广敏捷 。

同理,江湖上流传着这样的说法:

老板看问题的视角是,“这个需求很简单,怎么实现我不管”。

某些技术人员的视角可能是,“十八般武艺都用,至少面试用得着”。


另外很诡异的一个点在于,人类对于所谓 “建议”往往听不进去,然后总会找到一堆来证伪,然后又乐此不彼的“学习着”,争论他认为对的观点...


笔者自己也做过推广XXX的事情,持续集成。这东西大家都知道,我们之前有一个简单的规约,就是每天下班前的构建要绿色 ,单元测试和接口测试都得通过。好些同学怨声一片,代码都写不完,干嘛还要去写测试代码?尤其是之前测试代码覆盖率巨低的系统,几百个测试case不通过的系统 ......


采取简单粗暴的每天强制的方式,存量用例设定计划治理,研发同学不情愿的被要求每天跑CI......在大显示屏的曝光和强迫之下,持续了半年多... 后来有项目团队主动分享CI带来的好处,测试代码在他们后面的重构过程中发挥了作用,心里有底多了。


这个故事让我“自以为是”的懂得了第二个道理,让人懂得或者转变是很难的,猴子自己上树和硬推猴子屁股上树的区别。如果你拿着香蕉在猴子面前晃,就不一样了。


Greg Young 先生有一个presentation ,主题就是“

7 Reasons Why DDD Projects Fail“,

简单总结DDD 失败的要点:

Lack of intent(缺乏意图)

Anemic Domain Model(贫血模型)

DDD-Lite

Lack of isolation (缺乏隔离)

Ubiquitous what?

Lack of refinement(缺乏完善)

Proxy Domain Expert (Business analyst)  


笔者稍微谈一下自己的理解。


1、首要解决通用语言UL(Ubiquitous Language问题,统一域语言。


张逸老师指出,统一语言是提炼领域知识的产出物,获得统一语言就是需求分析的过程,也是团队中各个角色就系统目标、范围与具体功能达成一致的过程。使用统一语言可以帮助我们将参与讨论的客户、领域专家与开发团队拉到同一个维度空间进行讨论,若没有达成这种一致性,那就是鸡同鸭讲,毫无沟通效率,相反还可能造成误解。因此,在沟通需求时,团队中的每个人都应使用统一语言进行交流

可以想象一下,做支付、银行、电商行业的朋友在谈及记账、清算、结算、核算这些词的时候是否是一个明确统一的含义。一旦确定了统一语言,无论是与领域专家的讨论,还是最终的实现代码,都可以通过使用相同的术语,清晰准确地定义领域知识。重要的是,当我们建立了符合整个团队皆认同的一套统一语言后,就可以在此基础上寻找正确的领域概念,为建立领域模型提供重要参考。


前几天和某社区电商的一位工程师聊天,他们把给商家返佣之类的纳入到“清算”的范畴。这里他们用的“清算”肯定跟银行间“清算”不是一回事情。

2、没有基于通用语言建立的所谓的聚合,实体,值对象,只能算是DDDLite,只是技术层面的一种设计方式。


3、要解决好隔离问题,则需要以一种最宏观的角度去对“问题域”进行拆分,来划分“界限上下文”,最终形成一个具有俯瞰视角的“上下文映射图”。这里特别说一下“界限上下文”和问题域、以及服务谁,产生什么价值息息相关。比如一个采用第三方支付(支付宝)的小店网站,可能并不对支付宝背后的网联,以及银行渠道进行建模。


4、refinement的问题

架构腐化见怪不怪,如何领域层腐化了就“烂到跟上”。笔者见过一个系统,初期磨拳搽掌,建造者经验丰富,算是很成功的开端。但是若干年后这个系统domain层的代码和当初的领域模型图大相径庭,面目全非。持续的refinement、保鲜非常重要。


另外,前几天和一位TL聊天,他说,我很注重代码追求的,为什么1年多我没怎么看代码,他们完全不是按照我想象的样子在写代码。

相关文章
element-plus:el-date-picker日期只选择年月不要日
element-plus:el-date-picker日期只选择年月不要日
1817 0
|
Java 数据库
Springboot 根据数据库表自动生成实体类和Mapper,只需三步
Springboot 根据数据库表自动生成实体类和Mapper,只需三步
8473 3
Springboot 根据数据库表自动生成实体类和Mapper,只需三步
|
3月前
|
开发框架 Java 测试技术
领域驱动设计(DDD)在中小型项目中的落地实践
本文探讨领域驱动设计(DDD)在中小型项目中的落地实践,涵盖核心概念如领域模型、聚合、限界上下文与事件驱动架构,并结合电商订单系统案例,展示分层架构、仓储模式与领域服务的实际应用,助力团队构建高内聚、易维护的业务系统。
717 10
|
6月前
|
安全 Go 开发者
你真的懂 close(chan) 吗?90% 的 Go 开发者都掉过这个坑!
在 Go 并发编程中,初始化 channel 后直接 `close` 是合法且常见做法,用于广播通知、表示任务完成或作为退出信号。相比发送数据,关闭通道能非阻塞地通知多个 goroutine,更安全高效。理解这一机制有助于构建稳定、优雅的并发系统。
182 0
|
7月前
|
人工智能 中间件 Go
Go 项目实战:全局异常处理
在 Go 项目中,异常处理是保障程序稳定性的关键。本文介绍 Go 的错误处理机制与 panic 恢复方法,并探讨如何实现全局异常处理中间件,以统一捕获和处理运行时错误,提升代码可维护性与健壮性。
382 7
|
消息中间件
RabbitMQ的 RPC 消息模式你会了吗?
【9月更文挑战第11天】RabbitMQ 的 RPC(远程过程调用)消息模式允许客户端向服务器发送请求并接收响应。其基本原理包括:1) 客户端发送请求,创建回调队列并设置关联标识符;2) 服务器接收请求并发送响应至回调队列;3) 客户端根据关联标识符接收并匹配响应。实现步骤涵盖客户端和服务器的连接、信道创建及请求处理。注意事项包括关联标识符唯一性、回调队列管理、错误处理及性能考虑。RPC 模式适用于构建可靠的分布式应用程序,但需根据需求调整优化。
477 3
|
存储 缓存 Linux
docker的底层原理六: 联合文件系统(UnionFS)
本文介绍了Docker使用的联合文件系统(UnionFS),它通过分层存储和写时复制(CoW)机制,实现了容器的轻量级、高性能存储,支持了镜像继承、数据持久化和隔离性。
794 0
|
前端开发 Java Spring
springboot 整合 netty框架, 实现 心跳检测,自动重连
springboot 整合 netty框架, 实现 心跳检测,自动重连
|
JSON Java Apache
SpringCloud - Feign 调用服务及传递参数踩坑记录(上)
SpringCloud - Feign 调用服务及传递参数踩坑记录(上)
3373 0