https://mp.weixin.qq.com/s/lzAZXgchCg_VyLmyo2N18Q
 

故事背景

2023年,我加入了一个全新的团队,担任技术Leader的角色,可以算做是“空降”吧,至今已经一年有余的时间了。到目前为止,团队已经完成了领域驱动设计实践的内化,需求分析、领域建模、代码编写过程,都遵循了符合领域驱动设计理念的方法,团队成员的设计思维在实践的过程中发生了变化,将识别边界这件事逐步内化成了底层的价值观。

准备阶段

在初入团队之前,我有过成功落地的经验,也有信誓旦旦却草草收场的案例,更重要的是,成功在先,失败在后,在复盘和反思之后,我发现,必须在建立足够的信任的基础上,才有可能带领一支团队走进领域驱动设计的大门,毕竟这是一场价值观的战争,因此,建立信任成为我在准备阶段最重要的目标。
要获得足够的信任,就需要“上级信任”和“下(同)级信任”,对上做充分的沟通和预期管理,确保目标达成持续符合预期,对下展示技术能力和技术判断力,给团队带来共识的决策和技术的落地,比如分布式的上下文传递系统,借助该能力,系统实现了从单租户到多租户的架构变迁,同时也获得了全链路灰度的能力,这个能力我在之前的博客中有专门介绍。
在团队中的信任提升,又会形成相互的增强,上级信任的提升,会使得上级对我的决策背书加强,从而增强下级的协作配合,下(同)级的信任又会产生正向的反馈给到上级,增强上级的信任。

 
当然,我深知这一切的前提是,你遇到的团队文化是开放的、积极的,否则无论你如何做,都无法建立起必要的信任感。
 

下定决心

经过了六个月的磨合,我的大部分建议和决策都开始被团队认可和支持了,我觉得已经做好了准备,只等一个契机,恰好这个机会就来了。
团队面对一个规模比较大的需求,综合判断下来,要满足该需求基本上类似于重写一个核心模块,我们面临的最大挑战是:老代码已经不堪重负,已经团队已经丧失了对其的控制,迭代速度和交付质量双双失控,在这样的背景下做一个较大规模大迭代,所有人都没有信心。
而我认为,这是一个千载难逢的机会,可以促使团队下定革新的决心,经过短暂的思考和准备,最终,我决定,启用DDD战术框架来实现该需求。综合理由如下:
  1. 团队对老模式不满意,按照目前的状态,交付过程极其痛苦且风险高,大家渴望改善现状;
  2. 有成熟的DDD战术框架,团队要做的就是进行简单的熟悉即可,学习成本很低,一周内即可上手;
  3. 团队对我的信任达到了比较好的状态,这个决策大概率会被直属领导支持;
  4. 团队的大部分人心态都是开放的;
 
于是我花两天时间,从零开始用DDD战术框架把项目工程搭建出来,与现有系统集成,并完成了整体CI/CD的配置,让团队可以直接上手写业务代码。
随即,我展开了对后端开发的一对一沟通,为的是确认大家的真实感受,确保大家在整体协作中是足够坦诚的,因为只有大家的真实反馈,才有利于整个事情的发展,才能够在前进中不断修正,从而确保最终的成功。在沟通过程中,我问大家了几个问题:
  1. 如果我们保持现在的步调,你觉得自己一年以后会成长成什么样子?
  2. 如果我说现在有一次团队革新的机会,如果成了,之前我给大家描绘的理想团队的样子就会成为现实,你是否愿意相信我。
  3. 如果我说有一套DDD战术框架,你只需要不到一周,就能驾驭它,你是否原因相信我。
 
很幸运,大家给我的回答都与我所设想的方向一致:
  1. 如果保持现状的步调,未来也不会有太多成长,不会有新的东西,重复CRUD而已;
  2. 多学一些也无妨,不管是否如“你”所说,最终是否成功,对于自己都是有所收获的;
  3. 感觉可能没说得那么简单,但愿意试试;
 
在得到大家的正向反馈后,我就自己对整个事情的想法,与上级进行了沟通,表达了我们目前的困境,以及改革的天时地利人和,最终得到了上级的支持:

于是,我们最终敲定,上新框架,上DDD。
 

最艰难的时刻

万事开头难,我们在引入DDD战术框架的第一个迭代交付,也是最艰难的阶段,虽然有心理准备,但整个过程,团队仍然承受了比较大的压力,这些压力主要来自于:
  • 时间紧迫,有限的交付工期;
  • 新老服务的衔接工作超出了预估;
所有的问题最终都指向一个紧缺资源,就是时间,于是我们采取了三个行动来确保最终结果是成功的:
  • 与业务团队以及上级坦诚表达,工作量的实际情况,由于实际工作量比预期的要高,团队最终争取到了额外的一些研发时间;
  • 集体关进会议室,做封闭式开发,我们发现用DDD的编码范式,一旦建模完毕,我们可以按照“命令-事件”将一个复杂流程分配给多个开发者,使得团队能够快速地协作开发,完成一个复杂功能;
  • 团队组织了一定程度上的加班,这段时间,也是近一年来最辛苦的时刻;
幸运的是,通过这些举措,我们最终完成了交付,拿到了符合预期的结果。于是,在第一个迭代交付完成后,由产品团队发起,我们用同样的方法,完成了一个更大规模的核心模块的重构工作。
这最初的两个大的迭代,整体持续大约3个月左右,是最繁忙的,最艰难的,又是团队成长最快的一段时间,后来回想起来,大家也认为是最有必要的。
 

变化与收益

在第二个重构工作完成后,团队明显感受到了一些变化:
  • 业务建模,到编写代码不需要做太多的思考,代码可以与模型保持一致,不需要做翻译工作了;
  • 对功能的迭代不再有负担感,感觉代码是可以驾驭的,这得益于DDD的代码组织方式,使得系统变更的影响范围,总是容易掌控的,代码变动的影响面非常容易掌控;
  • 线上问题的修复相比以前更容易,新框架在数据的一致性方面有比较明显的健壮性,确保数据正确更容易;
 
我们的工作流也逐步进行了进化:

这里工作流程最大的变化是:
  • 更关注模型的设计是否符合预期;
  • 从带着大家建模,进化为团队成员可以独立建模,并基本符合预期;
  • 一旦模型确定,代码基本就确定了;
  • 模型设计完毕后,工作量的估算比过去要准确得多,漏算的情况大幅减少;
 

意外的收获

在我们决定启动DDD落地之前的一个月,我们团队来了一位新同事,这是一位刚刚毕业的学生,有编程的基础和一段时间的实习经验,这位同事在整个过程中的表现让我意识到,领域驱动设计并不是遥不可及的东西,相反它是很底层的认知,对于新人,反倒接受和实践起来,反倒没有太大的负担。下面我列举一下观察到的情况:
  • 他能够在一周左右的时间入门并使用DDD战术框架完成功能模块的开发
  • 他能够在3个月的训练之后,按照DDD的思路参与建模工作
  • 他设计的模型,会因为缺乏经验而对业务场景的分析不够充分
 
基于这些现象,我们发现:
  • 在已经落地DDD的环境下,学习DDD会非常容易;
  • DDD的战术框架极其重要,为新人学习降低了理解门槛;
  • 要做好建模,需要更多的业务和设计经验;
 
我想,如果一个团队一上来就是DDD的,那么大家会不会反而觉得面向过程的风格是“奇怪的”呢?
 

盗梦空间

以上,就是我们团队整个落地DDD的过程,看似很多关键的决策点都有些梦幻 ,团队为什么会通过两三个月时间就转变了思维,可以用DDD的模式来思考和建模,而这一切的背后,实际上还有一条暗线。
大家应该都看过《盗梦空间》这部电影,整个电影核心讲述了“向一个人心底植入一个观点”的故事,这很科幻。但我觉得我在与团队一开始相处的时候,就跟大家不断阐述了领域驱动设计的价值观,就像在植入观点一样,只不过并没有使用“领域驱动设计”的词汇。在每一次业务分析、技术方案讨论和决策过程中,我都会向大家表达“问题的范围和边界很重要”,“方案的范围和边界很重要”,“代码的职责范围和边界很重要”,我不断地重复“范围和边界很重要”,不断地把“范围和边界”与“代价和收益”建立关联,不断地用我们遇到的具体实例来对应“范围和边界”。
最终,关于“范围和边界很重要”这个观点,获得了认同,基于这个认同,我们的决策逻辑,趋于一致,我们的建模思维开始共鸣。
 

终极奥义

虽然为了吸引大家眼球,我标题党地使用了“PUA”这个词,但我认为在团队协作中要取得成功的终极奥义是:
  • 真诚是最大的PUA
  • 相信“相信的力量”
如果我不够真诚,没人会相信我,如果没人相信,那么一切都不成立,与大家共勉。

为了落地DDD,我是这样“PUA”大家的的更多相关文章

  1. 我们团队是如何落地DDD的(1)

    最近发现文章老是被窃取,有些平台举报了还没有用.请识别我的id方丈的寺院. 摘要 DDD领域驱动设计,起源于2004年著名建模专家Eric Evans发表的他最具影响力的著名书籍:Domain-Dri ...

  2. 跨越DDD从理论到工程落地的鸿沟

    摘要:本文从DDD的核心概念讲起,重点放在如何把理论落地成代码,期望给那些正在探索DDD的同学一些指引和启发. 本文分享自华为云社区<跨越DDD从理论到工程落地的鸿沟>,作者:敏捷小智. ...

  3. 可落地的DDD(7)-战术设计上的一些误区

    背景 几年前我总结过DDD战术设计的一些落地经验可落地的DDD(5)-战术设计,和一次关于聚合根的激烈讨论最近两年有些新的落地体验,回过头来发现,当初对这些概念的理解还是没有深入,这篇文章重新阐述下. ...

  4. 在单体应用的一些DDD实践经验

    阅读此文需要一定的DDD基础,如果你是第一次接触DDD读者,建议先去阅读一些DDD相关的书籍或者文章之后再来阅读本文. 背景 自从我在团队中推行DDD以来,我们团队经历了一系列的磨难--先是把核心项目 ...

  5. DDD-CQRS的落地案例

    摘要 在之前的文章DDD-CQRS能解什么问题中,阐述了什么是CQRS.但是并没有业务需求可以应用CQRS.最近需要处理一个文本增量更新的业务,经过需求分析后,尝试使用CQRS来解这个问题 问题分析 ...

  6. 基于ABP落地领域驱动设计-02.聚合和聚合根的最佳实践和原则

    目录 前言 聚合 聚合和聚合根原则 包含业务原则 单个单元原则 事务边界原则 可序列化原则 聚合和聚合根最佳实践 只通过ID引用其他聚合 用于 EF Core 和 关系型数据库 保持聚合根足够小 聚合 ...

  7. DDD领域驱动设计-概述-Ⅰ

     如果我看得更远,那是因为我站在巨人的肩膀上.(If I have seen further it is by standing on ye shoulder of Giants.)         ...

  8. 怎么说服领导,能让我用DDD架构肝项目?

    作者:小傅哥 博客:https://bugstack.cn 原文:https://mp.weixin.qq.com/s/ezd-6xkRiNfPH1lGwhLd8Q 沉淀.分享.成长,让自己和他人都能 ...

  9. 领域驱动设计(DDD)在美团点评业务系统的实践

    前言 至少 30 年以前,一些软件设计人员就已经意识到领域建模和设计的重要性,并形成一种思潮,Eric Evans 将其定义为领域驱动设计(Domain-Driven Design,简称 DDD).在 ...

  10. Vue的生命周期

    1.1.实例生命周期 每个 Vue 实例在被创建之前都要经过一系列的初始化过程.例如需要设置数据监听.编译模板.挂载实例到 DOM.在数据变化时更新 DOM 等.同时在这个过程中也会运行一些叫做生命周 ...

随机推荐

  1. 深入了解身份认证和授权机制,看看API请求到底发生了什么?

    前段时间写了一篇基于.NetCore环境使用IdentityServer4为API接口鉴权的文章,更多的是从快速上手的角度描述了IdentityServer4的使用.后续使用过程中,自己有了一些其他想 ...

  2. 常用RAID级别简介

    RAID不同等级的两个目标: 1. 增加数据可靠性 2. 增加存储的读写性能 RAID级别: ​ RAID-0: 是以条带的形式将数据均匀分布在阵列的各个磁盘上 ​ 优点:读写性能高,不存在校验,不会 ...

  3. UIButton选择状态下长按时会变回原始状态

    问题大概就像这样 (请无视那红字) 一般而言这是高亮状态的设置有所缺乏.完善代码如下: [_pupilBtn setImage:[UIImage imageNamed:@"a1"] ...

  4. Win10升Win11后出现的文件系统错误-1073740771的几种可能解决办法

    可能性1 有服务没能启动 键盘按"WIN+R"打开"运行"对话框 在对话框输入"services.msc"点击"确定"按 ...

  5. 在win10上安装MTK驱动(附驱动下载链接)

    参考:https://www.cnblogs.com/keepgoing707/p/4926171.html 背景 在调试MTK平台MT67XX的时候,发现安装preloader驱动装不上. 第三方i ...

  6. Rougamo、Fody 实现静态Aop

    最近在看项目,看到别人使用Rougamo框架,好奇花了点时间仔细研究了,在这里记录一下. 0. 静态编织 Aop 首先,我们先了解什么是Aop? Aop 是指面向切面编程 (Aspect Orient ...

  7. B 站和小红书又又又崩了,罪魁祸首竟然又是他。。。

    大家好,我是凌晨. 今天上午10点左右,我打开B站发现无法刷新视频列表和评论区,收藏夹和弹幕也均不可用. 原以为是手机网络问题,换网络重启手机都还是不行,第一时间打开微博,果然,B站崩了的新闻荣登榜首 ...

  8. Linux运行等级

    Linux运行级别 Linux system存在7个运行级别 运行级别0:所有进程终止,机器将有序停止,关机时就处于这个运行级别 运行级别1:单用户模式(root用户进行维护),系统中所有的服务也不会 ...

  9. Python性能测试框架:Locust实战教程

    01认识Locust Locust是一个比较容易上手的分布式用户负载测试工具.它旨在对网站(或其他系统)进行负载测试,并确定系统可以处理多少个并发用户,Locust 在英文中是 蝗虫 的意思:作者的想 ...

  10. Centos7安装nacos详细步骤(配置开机自启)

    Nacos 解压文件 创建数据库nacos,导入nacos的sql文件 创建数据库nacos,导入nacos的sql文件 修改启动文件(根据系统选择) [root@localhost bin]# cd ...