集装箱车队系统的DDD案例

板桥banq

  这是为上海某大型港口公司的运输系统实施的一个领域驱动设计DDD的咨询案例,通过一天时间的探讨,初步提炼出系统的领域模型,该文展示这个需求分析设计的大致过程和思路:

一、项目背景
提高车辆利用率和车队工作效率,提高堆场作业效率,提升车队的智能化管理水平,降低成本。

二、主要功能要求

  • 设立调度中心功能,对所有任务统一整理,集中派发,系统最大限度的提供相关信息以便于调度执行派发任务操作,监控任务执行状态,提高任务派发合理性,减少不合理用车及人为错误率
  • 能和堆场系统、仓库系统紧密衔接,充分考虑堆场、仓库及车队的合理作业效率,减少堆场、仓库集装箱的搬倒,减少车辆无谓等待时间
  • 能嵌入GPS监控功能,根据车辆运输任务,可以相应显示出车辆在GPS监控系统中的信息
  • 能实现车辆任务的短信派发,每次任务执行前都能将任务短信发送到司机手机上,司机可以回复不同信息表示任务执行状态,系统根据所收回复及时修改司机和车辆的当前状态
  • 能实现对车辆及司机管理,根据任务执行情况对司机进行考核、评估
  • 实现公司产值,司机产值,司机工资的核算
  • 能实现油耗、轮胎、道桥费、报销等管理,实现财务部门的核算要求,单车成本核算
  • 系统内各个操作时间点、操作人应有明确的动作记录,以便追溯和提供查询统计功能。

流程图如下:

 

需求了解

  根据这份需求文档,首先从流程图开始了解项目在整个大系统的定位,货代公司作为客户,通过业务受理提交运货要求,同时他也需要到管理集装箱公司的放箱公司申请集装箱,当这两个流程都完成后,将集装箱的情况比如处于上海哪个位置,哪个堆场或参考提供给运输公司,运输公司负责将符合货物要求的集装箱运输过来进行装箱,通过多次讨论,我们明白这个项目重点是:货运公司通过把集装箱运输到指定地点,从而赚取运输费,而接受的任务越多,利润越高,但是该运输公司也试图降低每次任务的运输成本从而提高利润,因此,如何提高运输效率,减少油耗和绕路等问题得到非常重视。

  运输公司对路线规划如此重视以至于专门成立两级调度员设计运输路线,初级我们了解到的是:一级调度员将接受到运输集装箱的任务分派到具体车队;然后,在每个车队的二级调度员再根据自己车队车辆情况将任务分配到具体卡车驾驶员,驾驶员拿到任务分配单出车,到达集装箱仓库后,将集装箱拉上卡车,然后再开到指定位置待装货,这个过程使用GPS定位,司机会实时反馈每一次事件动作。

  以上需求了解过程是通过上下文划分和用例图来逐步交流获得的,该系统分计划调度和车队调度两个部分,用例图分别如下:

 

  用例图基本是用于摸清需求的手段,因为告诉我们需求的人员有自己理解的偏向,导致我们的分析重点集中在“任务”上,好像整个公司的运作就是:任务的接受 任务的计划和任务的执行。而且运输公司的领导每天最关心的是任务完成情况,这涉及到车队的薪资等等所有重要计划。

  后来我们将“任务”定位在如同企业的“订单”上,运输公司接受到订单,提供的不是产品而是服务,把集装箱运到指定位置,这是其主要目标。

 

四色原型

  使用四色原型我们可以对需求进行归类,可以用:什么人做了什么事情产生什么结果来对系统需求进行初步的分析归类。我们对一级调度员和二级调度员两个角色做的事情用四色图进行归纳如下,下图主要是车队调度这个上下文模块中二级调度员的四色:

图中的Role MI和Des以及PPT分别代表四色的角色 活动 描述和PPT。

  在这个任务实施过程,也就是驾驶员出车拉集装箱的过程,由驾驶员车载终端输入其状态,其用例图很简单,只是输入反馈表一项,不再列出,总结四色图如下:

  在这个任务实施环节我们发现了大量细节,因为需求往往是公司管理人员提出,他们的位置和角度决定了提出的需求相对已经有抽象,可以算是半个领域专家,但是这个半瓶子水往往会误导我们,我们进行领域驱动设计是要找出领域中的规律,而很多客观规律因为管理原因掺入难以分辨,如同 任务这个实体,管理人员每天打交道的都是任务,但是驾驶员每天打交道的是“作业”这个实体,而一个任务可以分解为多个“作业”,我们想当然任务这两个上下文可以通过这个1:N的关系实现关联,从而导致蜘蛛网的模型图。

  而DDD是高聚合 低关联,任务和作业其实有不同含义,正如计划和执行是不一样的,虽然执行是按照计划要求,但是不是同一个概念,分析中,我们任务计划任务类似一种目标规格,正如产品有长宽高规格,服务也有其规格一样。

领域驱动设计

  DDD的核心是对模型进行实体和值对象分类,这种指定式和描述式的区别能够帮助我们隔离耦合,但是初学者也容易变成盲人摸象,无法看到整体,而领域驱动的目标恰是发现领域中的规律,到目前为止,我们是将系统划分为三个上下文:一级调度为核心的计划调度模块和二级调度为核心的车队调度以及以驾驶员为核心的任务实施。那么有没有贯穿于他们三者的统一模型,还是它们三者真的是三个有界上下文?

  能否寻找到跨三者的聚合根成为问题的焦点。而当前“任务”成为聚合根的呼声很高,那么我们首先按照任务作为聚合根来实施,聚合根作为一个实体,实体有唯一标识,那么任务的唯一标识是什么呢?经过讨论,发现任务主要核心是规划车辆运行的路线,如同我们出去旅游首先要规划路线一样,不同的是在一个公司规划路线和驾驶车辆是由不同人群分工协作,但是本质没有变,因此按照常理思考是面向对象分析设计的最基本原则。

  任务作为一个聚合根,其状态改变应该是反映系统的核心,我们按照动词结合原则,按照下面的Jdon分析法进行分析:

  我们使用任务作为聚合根,检查需求中"司机可以回复不同信息表示任务执行状态"的实现,场景是司机在运输过程中,发出一个装箱事件,也就是把箱子拉到卡车上了,发出一个领域事件,改变了任务聚合根的状态,什么状态?我们这时发现任务一般有开始 进行 完成状态,而司机发出的这个领域事件是任务进行状态中的一个环节,任务的三个状态更抽象,而司机要改变的状态够不着任务的状态,这时我们对任务这个聚合根产生怀疑,它可能只是在管理人员这个边界内的聚合根,不能算是整个公司领域中的聚合根。

  在寻找新的聚合根中,需要经过民主的充分讨论,发表意见,才能挖掘细节,才能结合多个盲人摸象的感受,合并成全面的大象的认识。有两个候选聚合根,集装箱和车,最后经过反复推敲,以及逻辑上一致,能够衔接统领整个公司业务领域的聚合根是“车”truck,车的描述影响着管理层的任务路线的指定,如果没有卡车这个特定的值对象描述,管理人员二级调度也可以对旅游社提供任务制定了,但是他们不是旅游公司的调度,而是运输集装箱的调度,两者区别就是车辆的种类不同,是卡车和客车的区别。

  其他细节不再描述,最后统一成的DDD设计图如下:

  当然,这个模型有待进一步完善其字段和方法,然后就能直接转变成代码,交给开发人员弥补上界面和持久层数据库就能运行,如果辅助以Jdon框架效率会更高,具体细节可见Jdon网站相关描述。