02|迭代一概述:怎样开启一个麻雀虽小五脏俱全的项目?

你好,我是钟敬。今天咱们开始第一个迭代。

在开篇词中我们说过,为了让你更好地掌握DDD,咱们这门课设置了一个贯穿始终的案例。我们会模仿真实的敏捷开发过程,把案例分成三个迭代,每个迭代的需求规模逐渐扩大,复杂性也逐渐增加。为了满足变化的需求,就会出现新的问题,为了解决这些问题,咱们就会引入新的DDD模式和实践,或者深化之前学过的知识。

今天开始,咱们通过迭代一,实现一个“麻雀虽小、五脏俱全”的项目。打通从需求分析,到领域建模,再到架构设计,最后到数据库和代码实现的完整闭环。

学完迭代一,你就可以理解DDD实践中那些最基本的套路了,甚至还可以在自己实际工作的项目里,选择一个小的“切片”,开始尝试落地DDD。

当然了,在实践过程中,你可能也会遇到这样那样的问题,别急,这些问题的答案,很可能就在迭代二和迭代三的内容里。当然,你也可以把问题写在评论区,咱们一起讨论。

现在我们就来看一下这个迭代的具体需求。

这次迭代的需求

假设咱们俩要一起创业,经过了一轮市场调研,我们发现很多中小企业,都有诸如考勤管理、工时管理、项目管理、请假管理等通用的需求。我们姑且把这些应用统称为“企业管理系统”。

现在咱们顺便回顾一下领域驱动设计里“领域”这个词的含义。领域指的是软件要解决的那些业务问题,所以也可以叫业务领域,英文叫Business Domain。在这个例子里,“企业管理”就是咱们要处理的领域

过去,这些企业只能自建或购买软件系统,安装到公司内部的服务器上,甚至还要有自己的机房,软硬件以及运维成本都比较高。如果咱们能够把这些应用放在云上,那么企业就只需要有选择地购买我们提供的服务,按需付费就好了,不再需要自建机房,也不需要自己运维,可以有效降低企业的成本。

咱们这种系统,其实是基于SaaS的应用。所谓SaaS,英文全称是Software-as-a-Service,中文译作“软件即服务”。也就是说,软件不再像传统上那样交付并安装在客户本地,而是安装到云上,成为客户可以直接使用的服务。

SaaS应用往往有个特点,用户五花八门,需求也是复杂多变。有些应用,如果只针对一个企业开发,本来挺简单,一旦放到云上,需求复杂性就会急剧上升。所以这次迭代,我们先做最简单的需求,后面两个迭代中我们再逐渐增加更多的灵活性。

由于云原生是这两年的热点,所以咱们凭这个点子幸运地拉到了投资,成立了一个叫做“卷卷通”的公司,开始着手研发系统的第一个版本。

由于不同行业的需求可能有较大差别,我们决定先聚焦于一个细分市场,之后再扩大范围。这个细分市场是我们比较熟悉的软件服务企业。这些企业会向自己的客户提供软件咨询、软件开发等等服务。

我们发现,这些企业的员工一般都工作在各个项目上。企业为了满足管理诉求,希望员工每周在系统中填报自己在哪些项目上花了多少时间,也就是所谓的报工时。所以我们第一步先来满足这个功能。但是,为了完成报工时的功能,我们还要首先对组织、人员、项目等等进行管理

这里还要说一下,在领域驱动设计中有一个重要的角色叫做“领域专家”,叫业务专家也可以。领域专家需要对业务有总体性和本质性的把握,同时对业务发展也要有一定前瞻性,也就是说,心里要有一盘棋。

所以领域专家往往不是一线业务操作人员,在很多企业中,是那些干了很多年业务,逐渐成长起来的中级管理干部。还有一些企业,由产品经理担任领域专家。

那么,下面就由我暂时充当一下领域专家,详细说一下需求。

需求一:租户管理

这个系统可以给多家企业使用,每家企业的数据是隔离的。这些作为客户的企业,在云原生应用里,习惯上叫做“租户(tenant)”。咱们的系统就是要对这些租户进行增删改查等管理。这样的系统叫多租户系统。

假设我们做市场调研时,研究了一家叫“零零后科技有限公司”的企业,我们这个迭代,就先来满足这家企业的需求。

需求二:人员与组织管理

除了对租户进行增删改查等管理,我们还必须还有人员和组织管理

零零后公司有多个开发中心,每个开发中心下有多个开发组。此外,还有公司直属的人事部、财务部等部门,系统要能够管理这些部门。

而且,我们对员工也要进行增删改查,并且把员工分配到部门。每个员工只能属于一个部门,比如王小牛属于开发一组。

下面这个图说明了需求中的人员和组织结构:

需求三:项目管理

接下来的需求是项目管理。

首先,租户要向它的客户提供服务,就要和客户签订合同,然后完成合同下的项目。比如说,租户零零后公司的客户可能包括安安保险公司、开心电信等等。那么,租户零零后公司就得为安安保险公司,安排一堆程序员帮他们开发核心保险系统项目,也得为开心电信,安排几个咨询师帮他们的敏捷转型做咨询。

这里具体的需求是这样的:

  • 一个租户企业可以有多个客户,可以在系统里对客户信息进行增删改查,每个客户都有一个客户经理来跟进;
  • 租户可以和它的客户签订多份合同,在系统中对合同信息进行增删改查,每个合同都有一个销售人员负责,可以开始和结束合同;
  • 一个合同下可以有多个项目,系统可以对项目进行增删改查,每个项目有一个项目经理;
  • 可以在系统中开始和结束项目,需要记录开始和结束时间等信息。项目结束以后,很多事情就不能随便做了。

下图说明了客户、合同、项目等概念的关系:

需求四:人员分配

有了项目,我们就可以把员工分配到项目上,也可以让一个人退出项目。而且,一个项目可以有多个人参与,一个人又可以同时参与多个项目。

除了这些,我们在把人分配到项目上的时候,还要记录每个人预计的投入百分比。比如说,王小牛在A项目上准备投入自己30%的时间,同时在B项目准备投入40%的时间等等。

之所以要记录预计的投入时间,是为了让企业能够在总体上调配人力资源。比如说管理人员看到王小牛还有30%的空余时间,就可以把它同时再安排到另一个项目上,以便实现“内卷最大化”。

下图说明了人员和项目投入的关系:

需求五:工时登记

把人员分配到项目上以后,我们就可以登记工时了。

我们这里规定只有当一个员工分配到一个项目上以后,才能通过这个项目报工时。这样的规定,一来是为了符合公司的管理要求,一个员工不能随意参加一个项目;二来也可以防止员工不小心把工时填到错误的项目上。

而且每个员工每周都需要在系统中填报工时,登记自己哪一天在哪个项目上投入了多少时间。当然,员工可对工时进行查询和修改,还可以为每天的投入的时间填写备注。你可以看一看工时登记的界面原型,进一步理解需求。

另外,尽管咱们尽量采用接近真实的案例,但也无法面面俱到。为了突出重点,我们这个课程还是省略了一些需求,比如说人员登录和权限控制等等。

现在,第一个迭代的需求基本上就说完了。这些需求看起来简单,其实关键点还是挺多的。而且更重要的是,在实际项目里,这些需求未必会这么清清楚楚、白纸黑字地列出来给你,更多是隐藏在领域专家的脑子里,需要我们去挖掘。

还有一些需求,我故意没有说得很详细,而是要在后续的开发过程中逐步揭示。这也是为了模拟实际项目的场景。

DDD的基本开发过程

那么,我们怎么用一套系统化的方法,抽丝剥茧、一步一步地把需求落实到代码呢?咱们看看下面这张图,它表示了领域驱动设计中的主要流程。

你可以看到,在整个开发流程中,首先是要捕获行为需求,也就是传统软件工程里的“获取需求”。这一步,我们要识别需求里有哪些流程、哪些功能,每个功能由什么人操作,会产生什么结果。

在传统软件工程中,这一步常用的方式是用例建模,也就是用Use Case来建模。在这套课程里面,我们会用DDD中比较流行的一种方法,叫做“事件风暴”。

接下来,我们就可以进行领域建模了,也就是通过建立领域模型,把需求里的主要业务知识描述清楚。DDD的领域模型,大体上相当于传统软件工程中的分析模型。

基于领域模型,我们就可以做架构设计,包括进程间和进程内的架构。比如说微服务设计、中台设计都属于进程间架构。而DDD分层架构,通常说的是进程内架构。

然后就可以根据领域模型进行数据库设计,最后是代码实现

这样,就形成了一个基于DDD的开发闭环。其实,在实践中,尤其是对敏捷软件开发来说,这些步骤不是线性的,而是反复迭代、互相穿插的。

DDD是以领域模型为核心的。所以,我们可以把上面说的步骤分成模型的建立模型的实现两部分。

模型的建立阶段,使用的都是业务术语,归根结底来自业务人员,业务人员不仅能听懂,而且负责评价建模的正确性。而模型的实现,则是业务人员不需要理解也不关注的,会包含技术实现方面的内容。这两者的边界很重要,我们在后面还会反复提到。

总结

好,今天就讲到这里,我们来总结一下。

这节课,我们概述了迭代一的目的和需求,并且介绍了DDD的基本开发过程。

咱们要开发的是一个基于SaaS的企业管理系统,它的需求主要包括租户管理、人员与组织管理、项目管理、人员分配和工时登记这几部分。

在介绍需求的同时,我们也穿插着介绍了领域和领域专家的概念。领域就是软件要解决的业务问题。领域专家则是十分了解业务知识本质的人。

DDD开发的基本流程是以领域模型为核心的。整个流程可以分为模型的建立和模型的实现两部分。其中模型的建立一定要使用业务语言,而模型的实现则增加了技术语言。模型的建立,是通过领域专家和开发人员的协作共同完成的。

最后,今天讲的所有需求我都汇总到了下面这张表里,你可以看一下,方便后面的实战。

思考题

1.如果这是一个真实的项目,你觉得还缺少哪些需求?
2.希望在你自己的项目里,选择一个不太复杂的部分,然后跟着后续的课程,按照DDD的方法尝试实践。

好,今天的课程结束了,有什么问题欢迎在评论区留言,下一节课我们将通过事件风暴的方式,理清系统的行为需求,并为进一步的领域建模打下基础。

精选留言

  • 麋鹿麋鹿迷了路²º²º

    2022-12-10 23:07:49

    关于思考题:
    1. 如果这是一个真实的项目,你觉得还缺少哪些需求?
    回答:至少还缺少数据报表等分析、项目管理中的审批管理、流程监控等。

    此外,我还有一个疑问:DDD中的领域模型,与MVC中的M、ORM中的M相比,三者有哪些异同?
    作者回复

    关于模型的问题非常好,很多同学可能都有类似的疑惑。首先,是层面不同。DDD的领域模型,属于我们说的“(领域)模型的建立”层面,如果对标传统软件工程的话,大体属于“分析模型”,里面的概念都是业务概念,没有技术概念。而MVC和ORM都是架构模式,属于“模型的实现”层面,按传统的说法就是设计层面,这里面就有业务人员不需要理解的技术术语甚至代码了。ORM里的M,其实就是(分析层面)领域模型转化成代码后的形态,处在代码的领域层。MVC的解释会复杂一点,因为传统的MVC始自SmallTalk语言,而现在一般说的MVC是为了Web应用而改过的。对于Web应用而言,粗略地说,领域层和应用层,都可以归为MVC里的M,而其中的领域层代码,就是ORM里的M。这里我用的“领域层”和“应用层”两个术语,会在我们的课程后面讲分层架构的时候详细介绍。

    2022-12-11 11:08:13

  • 业余草

    2022-12-08 13:16:24

    大家的关注点都在需求,我来总结一下本文的核心知识点。

    DDD 是以领域模型为核心的。所以,我们可以把上面说的步骤分成“模型的建立”和“模型的实现”两部分。

    模型的建立:事件风暴 -> 领域建模。

    模型的实现:架构设计 -> 数据库设计 -> 代码实现。

    DDD 的基本开发过程:事件风暴 -> 领域建模 -> 架构设计 -> 数据库设计 -> 代码实现。

    后面所有的需求,我相信应该都是围绕整个开发过程来讲述的。

    期待后面大家轮流来总结,收获满满!
    作者回复

    您的总结很漂亮。提前说一下,等学到后面的课程会发现,事件风暴只是获取行为需求的方法之一,还可以采用别的方法。所以可以把第一步改一下:获取行为需求 -> 领域建模 -> 架构设计 -> 数据库设计 -> 代码实现,这样可能更好些。不过这仍然是为了讲课简化了的流程,有时间我们可以再更全面的讨论一下DDD和开发过程的关系。

    2022-12-08 22:26:18

  • aoe

    2023-07-10 11:41:03

    第二次学习总结:

    1. 从全局视角找出「大功能模块」
    2. 在「大功能模块」中找出「子功能」
    3.「子功能」推荐以一级列表平铺呈现,可以降低复杂度(反例见需求二),更利于分析问题

    详见文章末尾「图例说明」https://wyyl1.com/post/23/06/
  • 大厨程序员吾真本

    2022-12-08 09:19:11

    钟老师前面把ddd对于复杂系统的分析的价值和开发人员的痛点讲得很透彻,很赞。另外,在“咱们的系统就是要对这些租户进行增删改查等管理”里的“增删改查”的提法,会不会让一部分听众认为crud不算复杂,为何要用ddd? 另外,并不是所有业务场景把crud都用上。比如只有管理员才可以做对租户进行remove,但租户不可以。是否把“增删改查”改为“根据业务需要对租户信息进行管理”好一些?
    作者回复

    谢谢道长的建议!这个问题我在写这节课的时候也考虑过,所以您可以看到,目前有些地方用的是“管理”,有些地方用的是“增删改查”。之所以这么写,是考虑两点,第一从课程设计角度出发,第二从实际情况出发。
    首先,从课程设计角度,这门课故意模拟实际情况,在真实情况下,业务说需求时可能就是比较随意,这里缺一点,那里漏一点,这里又不一致一点。所以这节课中的需求就显得没那么完善,在后面的课程会逐渐丰满和严格化。
    其次,从实际情况角度,当业务说“增删改查”的时候,一定意味着简单需求吗?可能客户目前只想到增删改查,但深挖下去,其实还有别的,可能有的增删改查背后,有复杂的业务校验逻辑等等。这些都要继续挖掘。这节课只是开始,后面的课会继续深挖。总之,还是希望模拟一种真实的开发过程。
    至于这种写法是不是有效,我们还可以听听其他朋友的意见。

    2022-12-08 22:01:39

  • hopez

    2022-12-08 21:54:07

    1、个人觉得还缺少数据统计需求;
    2、多租户的数据隔离和权限管理不知道属于业务需求还是技术需求;
    作者回复

    没错。
    区分业务需求和技术需求,可以这么想,如果没有开发背景的业务人员能明白的就是业务需求,否则就是技术需求。数据隔离和权限,整体而言,业务人员应该能明白,而且开发人员必须和业务达成一致,所以算业务需求。而数据隔离具体采用哪种技术手段,则不是业务需求,是技术决策。

    2022-12-09 11:36:06

  • Jaising

    2022-12-30 22:47:26

    请教下钟老师,对于需求本身的讨论是不是也要纳入到DDD最小闭环之中,一是不一定能保证业务对需求的把握是准确自洽适合,除了领域专家也需要研发一起参与,二是需求直接影响后面模型建立与实现,哪怕多一条业务规则可能都会影响到建模,更有甚者需求本身就没有充分调研可行导致产研做了无用功,这里就有问题怎么把握需求的真伪、质量、价值这些,DDD有没提供这方面的方法论?
    作者回复

    准确的说,需求应该包含在软件开发流程的最小闭环中。而DDD的重点其实只覆盖了整个软件开发流程的一部分,也就是从系统分析(不是需求分析)到代码的部分。需求管理本身就可以写一本书了。本课程里的事件风暴,是需求管理的一部分。

    2023-01-07 19:06:46

  • aoe

    2022-12-08 13:32:09

    现在工作中都使用 MVC,代码结构类似 Controller、Service、DAO。
    开发时没有体会过“模型的实现”-架构设计这一步,而是:直接根据需求设计数据库 -> 代码实现。

    以我现在的水平,看到文末的需求列表就可以直接实现功能了:
    1. 划分功能模块:多租户、人员与组织管理、项目管理、人员分配、工时登记
    2. 根据功能描述设计数据库
    3. 编码实现

    感觉到的问题:
    1. 这是一门 DDD 的课程,我这样的写出的代码会无比僵硬,没有《DDD》书中提到的有些地方是柔软的
    2. 因为代码僵硬,就算使用 TDD 进行开发,有利于后期重构,但也会因代码简陋(没有设计)给重构工作带来很大的工作量
    3. 请教钟老师,推荐哪种方法实践:
    A. 是先按自己的想法实现需求汇总里列出的所有需求,再跟着后续课程迭代功能(我能吃苦,但希望不要走弯路)
    B. 选一个功能点实现,但是担心选中的这个功能点后续文章直接省略了,重点讲别的功能点(这就有点尴尬了)
    C. 或者您有更好的建议
    作者回复

    每个人都有不同的学习习惯,我只能说一下个人的看法供您参考。建议您先忘记代码,跟着课程尽量先吃透领域建模。到了后面的代码实现部分,我其实只写了一个功能为例,你看了以后,可以用类似的方法尝试写其他功能。然后和自己头脑中原来的做法做比较,应该就可以了。

    2022-12-08 22:20:39

  • Jxin

    2022-12-10 12:50:01

    1.有点顺便给自家公司搞个项目管理(包含工时,人员)系统的味道。
    2.可以增加的功能 项目工作台,项目仪表盘,项目自动关联,工时缺省填报,工时未填告警等等一系列功能,能做的太多,不罗列了。
    3.需要考虑的功能 跨租户业务。 比如商机分销,比如顾问跨租户支援。 这些需要刻画租户模型 租户间协作合同 以及发生跨租户业务后双边的履约刻画以及之间的履约映射 财务结算。


    5.少了一个很重要的过程,如何做需求确认。 在未知领域采集业务知识(发散),提炼业务模型/功能点(收敛),评估功能点的必要性(依赖关系)和性价比(按量化价值和成本打分)(发散),制定mvp和演进路线(收敛)。 虽然ddd没写,但这个过程得做,必然可能在开始就凉了。 演进规划一定会有变化,无论是方向还是功能集,可以逐步调整,但不能没有。
    作者回复

    感谢补充,确实还有一个从愿景,到产品设计,到需求获取,项目规划等的过程。这些足以独立写一本书了

    2022-12-12 08:33:31

  • 沐瑞Lynn

    2022-12-08 17:12:35

    一、从功能需求和非功能需求的角度讲,目前,还没有描述非功能需求;

    二、从用户+场景+行为动机+目标来拆解需求,目前,有些场景也欠缺,譬如:如何分配管理权限等

    作者回复

    是的,说的很全面。

    2022-12-08 22:30:00

  • 骆驼、

    2022-12-08 09:41:57

    还缺少工时统计,包括各个项目下参与人员的投入时长以及每个人员参与项目的投入时间
    作者回复

    是的,缺少这个。可能在迭代三会加上 :)

    2022-12-08 22:05:35

  • leesper

    2022-12-08 08:26:04

    缺少审批功能,真实企业中是需要流程引擎做各种审批的,比如请假,人员进场离场
    作者回复

    没错,真实情况下一般要有。

    2022-12-08 22:04:12

  • 6点无痛早起学习的和尚

    2022-12-09 10:05:27

    在这里发现一个细节问题,在捕获行为需求阶段,我们梳理了:
    1. 需要提供的功能(这里就为后期提供接口功能做铺垫,也算是为功能架构设计做铺垫)
    2. 功能下面一些数据之间的关系(这里就为后期做数据库设计做铺垫),比如一个合同下面可以多个项目,这里就是 1:N 的关系
    不知道这样理解是否正确
    作者回复

    基本是正确的,我再补充一下:
    1.关于捕获行为需求,这一课只是开了一个头,下两节课讲事件风暴才是主要部分,在那里,会对后期接口设计起到更具体的作用。
    2.按照DDD,这里的需求和数据库设计之间还差了很重要的一步,就是领域建模,领域建模以后,才数据库设计。这是DDD和之前开发方法的主要不同之一。

    2022-12-09 11:45:42

  • aoe

    2022-12-09 00:26:28

    刚看到《DDD》第 4 章 分离领域
    发现了第一版需求汇总还来得急没分层
    作者回复

    分离领域属于“模型的实现”层面,含在分层架构里面,我们后面会专门讲。现在还在需求层面,离后面还差着几步 :)

    2022-12-09 09:41:12

  • Geek_0052b7

    2024-11-14 22:03:28

    获取行为需求 -> 领域建模 -> 架构设计 -> 数据库设计 -> 代码实现
  • Geek4329

    2023-10-13 14:30:38

    这里提到领域模型相对于传统软件工程的分析模型,那么除了分析模型,传统软件工程的开发流程是什么样子的?
    作者回复

    需求(需求获取、需求分析、需求文档)、设计(架构设计、详细设计)、编码、测试、交付、运维

    2023-11-04 14:16:45

  • 黑夜看星星

    2023-08-05 23:14:42

    老师,我看现在的其他DDD,一般分两大阶段:战略设计和战术设计
    作者回复

    所以你的问题时什么?

    2023-08-06 19:45:41

  • 黑夜看星星

    2023-08-05 23:00:42

    老师,特性,功能,能力,业务,需求之间有什么区别和联系?
    作者回复

    这些都是大词,在不同场合,意义会有所不同。你可否再问得具体些?

    2023-08-07 17:51:56

  • 6点无痛早起学习的和尚

    2023-04-25 08:37:23

    二刷回来再看这节内容,这个需求有点复杂啊,内容很多啊
    作者回复

    是的,扩展一下,就更复杂了。

    2023-05-06 19:39:44

  • yoon404

    2023-02-10 10:56:12

    如果这是一个真实的项目,你觉得还缺少哪些需求?
    1、菜单权限、数据权限控制,
    2、审批流程
    作者回复

    是的

    2023-03-16 22:08:42

  • 仲弈

    2023-01-27 22:52:47

    回答下思考题,功能其实比较简单,讲的也比较清楚,但是需求中缺少很重的一些信息,特别是项目管理这个地方
    1、客户、合同、项目
    2、客户经理、销售、项目经理
    他们都缺少了说明什么事件让这些过程向下流转,或者说触发了什么事件到达了什么程度就可以到下个环节
    缺少了这些说明感觉开发很难做