DDD 实战之一:从需求到代码实现生鲜电商系统

2023-03-23 17:21:48 浏览数 (2)

作者深清秋:21年老码农,持续创业中。热爱写代码、热爱做软件架构设计、热爱做软件产品设计,一旦做这些就很容易进入“心流”状态,忘了吃喝拉撒、废寝忘食!最近决定把自己的一些代码或设计经验分享出来,希望对大家有用!个人秉承的职业理念:通过自己给自己加班,提升自己的稀缺性,其实所有人都可以突破年龄障碍!

本系列获得深清秋同意在「逸言」发表,本文观点仅代表作者观点。

01

缘起

开始之前,我想说的是:感谢您在百忙之中,还有兴趣看一位老程序员的分享,尤其是还有点唠叨!

近几年随着云原生技术的发展,微服务如何拆分的问题,越来越成为企业应用架构设计中最为重要的设计决策之一。我在实际工作中,时常碰到客户提出的疑惑:微服务到底要“微”到什么程度才算好?用了微服务架构后,真的能减少业务模块之间的相互耦合、进而提高系统整体可用性吗?为什么我们拆了微服务后,系统反而不如之前的单体应用稳定?不但如此,拆了微服务后,每次需求变更比以前更复杂,不可预测的连带 BUG 持续出现......等等等等。

基于这样的客户诉求,我开始学习 DDD 设计方法。但随着学习的深入,越来越发现软件开发团队要落实 DDD 设计方法并不是一件容易的事。DDD 方法鼻祖 Eric 的经典著作《领域驱动设计 软件核心复杂性应对之道》、以及 Vaughn 的《实现领域驱动设计》都写得比较抽象,很难落地实施。DDD 的难落地程度,导致了程序员圈子甚至出现了一种看法:本来会写代码的,学了 DDD 后反而不会写代码了——也就是俗称的“学废了”。

为了能够让软件开发团队切实的落实 DDD,我决定自己亲身实践一次用 DDD 设计开发一个实际运行的系统,以便于在实际开发过程中积累相关的经验,进而能够将来指导开发团队落地 DDD 方法。很显然的,该实例系统要求既不能太简单以至于没有参考价值、也不能太庞大以至于我一个人在最多半年的业余时间内都搞不定。为此,我选择了本人之前做的一个“群买菜”生鲜电商小程序(你可以从微信小程序搜索到它)系统作为本专题的样例。因为该小程序的产品设计也是本人做的,所以比较熟悉也比较容易操刀。而且该系统也在实际应用过程中,也发现时不时的有业务需求变更,往往因为因为当时没有做架构设计、直接就开始事务脚本性质的编码(在本专题后面章节将会看到),所以导致变更需求也非常困难。为此,于公于私,我都应该将“群买菜”用 DDD 方法重构一遍设计。

在实际开始之前,正好我也看了张逸老师的一本书《解构领域驱动设计》。在该书中,张逸老师体系化地将自己理解的 DDD 很多方法和实践进行了梳理,并给出了自己的一套标准工作流程——DDDUP(领域驱动设计统一过程)。因此,在本专题后续的内容中,我将主要基于张逸老师的 DDDUP 来进行操作。在这里,对张逸老师致以深深的感谢!

同时,因为“群买菜”实际上还是一个相对比较大的系统,且 DDD 其实主要适用于大型软件应用系统的开发,所以我也引入了 scrum 敏捷开发过程,对整个“群买菜”系统分为 5~6 个 sprint(冲刺)来执行。

本质上,这个专题是我个人在实践 DDD 过程中的一些提炼和分享,不能算是培训教材,也不能算是专家经验,只能说是一个热爱分享的程序员对这个世界的输出吧!大家也不要当做这个专题为学习,而当做和我一起经历一次完整的 DDD 需求分析、架构设计、编码实现的旅程吧!

02

目标读者和预期收获

本专题的目标读者,主要是提升自己在应用软件架构设计方面能力的熟练程序员、开发组长、技术经理等。作为熟练的程序员,你应该已经满足以下列出来的一些要求:

  • 精通 java 开发,尤其需要熟悉 spring-boot 的开发;
  • 精通 1~2 个以上关系数据库和非关系数据库技术,如:mysql/oracle、redis/mongodb 等;
  • 有过 3 年以上应用软件的实际 coding 经验、有过带领 3 人以上程序员小组的开发经验;
  • 对常见的设计模式比较熟悉,在实际项目的 coding 中 ,至少熟练使用过 3 种以上设计模式;
  • 对架构分析模式有所了解,在实际需求分析中,至少使用过 1 种以上分析模式;

最后一条,也是最关键的,作为工程师,对学习新技术新方法有足够的动力,认可“加班就应该加在提升自身的稀缺性上”(这个理念来自于刘润老师)的理念,迫切希望成为架构师、或更优秀的架构师,有志于朝着技术线的资深专家(非管理线)发展;

下面说明经历本专题旅程后,您能得到什么。准确来说,我祝愿您能获得如下的收获:

能够理解 DDD 从需求分析、到架构设计、到编码实现的整个过程,以及其中的工作方法和实用技巧。我们这里所说的“理解”,指的是你能够在自己的团队内部分享、培训、甚至引导团队在项目中使用 DDD。

本专题还将实实在在建立一个全开源的“群买菜”生鲜电商系统,这个电商系统你将可以通过 github 或 gitee 获得全部源代码。你可以将这些源代码用于自己的任何用途,只需要遵守 Apache 开源许可证协议即可。

注(内容会随着专题进展而逐步完善):

github 代码仓库访问地址: https://github.com/beautautumn/starshop

gitee 代码仓库地址: https://gitee.com/samson-shu/starshop

03

DDD 能解决什么,不能解决什么?

根据我个人的项目经验、以及实际做 DDD 设计编码的感受,如果你在项目中遇到下面这 3 种情况,就考虑可以试试用 DDD 来解决问题了:

  • 频繁的业务需求变更导致对系统稳定性的影响不可控。需求修改频繁,而感觉每次修改涉及的范围千头万绪,不透明、不可控,经常因为需求给原来的功能带来不可预测的 BUG。这个问题,其实可能代表着两类需求(视软件产品化程度而不同):
    • 对于项目定制化软件,希望随着业务的发展,业务需求变更只会引起可控的、小范围的变更;
    • 对于产品化程度较高的软件,希望随着软件产品的发展,每个产品组件可相对独立地演进;
  • 30 人以上大项目团队职责划分很纠结。项目很大,团队怎么划分,感觉没有科学依据,凭直觉划分后,总发现一些不可控的耦合或重复开发;
  • 微服务怎么切分很纠结。云原生技术的发展,微服务切分的粒度无法把控。太粗没有意义,太细了又导致运维复杂失控;

上面说的 DDD 比较适合解决问题的场景,当然另一面就是 DDD 也有不适合解决的问题场景。我个人总结了一下,觉得下面这些问题是 DDD 不能解决的:

  • DDD 不能帮助团队决策如何更好的技术栈;
  • DDD 不能解决系统的性能相关的瓶颈问题;
  • DDD 几乎不涉及前端 UI 的设计方面;
  • DDD 不能帮助产品经理提升产品设计水平(虽然产品经理了解点 DDD 也有帮助),更不能代替产品经理做产品设计。因为产品设计更多是牵涉到心理、商业等非工程化思维,而 DDD 仅能解决软件在工程化方面的问题;
  • DDD 不会手把手的教你如何提升需求分析相关软技能,包括:如何和客户沟通需求、如何画业务流程图、如何识别业务用例、如何学习新的业务知识等。虽然它确实给出了一套相对有参考价值的“硬性”方法框架,但未给出任何关于个人如何提升这些“软”性技能的实际建议,它假设你自己去建立和发展这些技能;
  • DDD 不会手把手的教你如何提升软件架构设计相关基础知识和软技能,包括:如何区分哪些逻辑应该放前端实现、哪些放后端实现、前端目前主流技术框架有哪些、后端主要开发技术栈有哪些等等。虽然它确实有一套相对有参考价值的“硬性”方法框架,但同样未给出任何关于个人如何提升这些“软性”基础知识的实际建议,它假设你自己去建立和发展这些技能;
  • DDD 不能解决程序员个人自身的代码质量和规范性问题。虽然它确实能够很大程度上解决代码目录结构、模块划分的规范性问题,但解决不了程序员自身编程水平问题;

看我这里的介绍,看起来 DDD 能解决的问题很有限、而不能解决的问题却很多!我想要说的是:“是的,DDD 并不是万能药,几乎不能解决软件项目中遇到的绝大部分问题!”要知道,即使计算机发展到今天、很多冯.诺依曼体系架构下的开发技术已经发展到了极大丰富,但“需求分析、架构设计(往往同时决定了团队结构)、面向对象”这些技能,仍然是程序员圈子的高端技能,一个类似于 DDD 这样的方法体系,能够解答这些高端技能相关的核心问题,已经是很了不起的方法论。

所以说,无论怎样,DDD 都可以说是一个“有点伟大”的软件设计方法论!虽然,网上很多人都在说 DDD 有很多“伪创新”,但无论“伪”不“伪”,DDD 都是随着云原生微服务发展而迅速被重视的、也确实很有帮助的一套方法论。

04

能用一句话解释 DDD 核心理念吗?

根据我个人对 DDD 方法论的实践,让我最能记住的其核心理念,就两个字:同构!

说到“同构”,这跟我个人经常困惑的一个问题息息相关:既然代码世界是现实世界的一个“虚拟”映射,为什么我们在现实业务中,人们的直觉认识往往觉得某个业务其实没有太大变化,但是到我们的实际代码中,却要引起“伤筋动骨”甚至“开天辟地”般的变化呢?最后导致新需求的实现,要么被扭曲了不伦不类、甚至放弃业务需求,要么就付出巨大的建设成本、难以忍受的建设周期呢?

我个人理解,这其实是因为我们用代码实现的“虚拟世界”、跟真实业务的“现实世界”不“同构”导致的。说得粗俗一点,就是可能我们真实世界是“六边形”的,但被我们的软件团队映射成了“三角形”的“虚拟世界”,也就是产生了所谓的“异构映射”。那这样的“异构映射”是怎样产生的呢?有句话说得很好:正确的过程才能导致正确的结果、错误的过程一定导致错误的结果。这其实就是我们的软件需求分析师、架构设计师、程序员合起来对现实业务的“解构”错误导致的!

DDD 的核心理念,其实就是试图给出一套方法框架,告诉我们的需求分析师、架构设计师、程序员怎么去尽最大可能地将“真实物理世界”同构化映射为“虚拟代码世界”。

05

本专题解答什么?

说了这么多,我想你可能会问:如果我决定开始学习 DDD,你废话这么多的这个专题,到底能解答我哪些问题?

我想,我试图在这个专题中,回答下列的问题:

DDD 方法论下的软件工程完整视角是怎样的?我会回答这个问题,并且告诉你:有这样的完整工程视角,并且也并不是那么难以理解!虽然 Eric 和 Vaughn 没有给出一个完整的、可操作的软件工程框架,但我试图在“群买菜”这个软件的实现过程中,向你展示这个视角。这里特别强调一下:其实这个视角是张逸老师给的,我可能只是做了一些我自己认为有益的简化。

在这个软件工程视角里,我需要怎样一步一步来分析、设计、编码、测试软件?我也会回答这个问题,我会通过“群买菜”这个软件的一步一步的工作开展,来向你展示如何在每一步里来做、以及每一步我采用的方法、技巧和思考。

DDD 社区目前的最新发展情况。DDD 可以说目前还在逐步完善中,社区最新有哪些问题的争论、大师们又是怎样的观点?我本人其实对这方面的问题也很感兴趣,我会在编写本专题的过程中,一遍学习一遍和大家分享我个人的理解和体会。

06

本专题编写风格

为了方便你评估本专题是否值得继续看下去,我这里澄清下自己的编写风格,以供你选择是否继续——当然,如果你继续赏光阅读我下面的内容,我会非常感谢!也非常乐于随时与您交流你发现的我的错误、或其它任何您觉得需要讨论的问题。

我会尽可能的将理论体系浓缩和简化;

我会结合实际的软件实现案例(并且该软件的开源代码实现一定是可运行的)来讲解。在案例中贯穿 DDD 相关的方法、原则和技巧,而几乎很少大篇幅的介绍理论本身;

我可能会写得比较啰嗦,尤其是一些技术实现细节方面比较抠,希望您能够有耐心。因为我自己是个很笨的人,学习一个东西的速度很慢,而且我一向希望自己能够“但求甚解”,而不是“不求甚解”。我个人一直秉承“慢就是快”的理念,所以还请您稍微忍受这一点;

我会每周更新一篇,整个专题可能会有 20~30 篇。除了第一篇的大量没有太多技术含量的“废话”外,后面的每一篇,可能需要您每周花费 2 小时左右去阅读(1 小时)和理解(1 小时)。所以,还是上一句话说的:需要您有点耐心。

0 人点赞