DDD项目目录(包、模块)结构

注:此文转载自领域驱动设计(DDD):项目目录(包、模块)结构

DDD项目目录(包、模块)结构

在项目的开发阶段,目录结构的划分往往被看做是迈向成功的第一步。这一步的迈出往往伴随着很多方面的权衡(考量),总的来说是两个方面的考量:业务方面和技术方面。

  • 业务方面的考量包括:限界上下文、子域、业务模块。
  • 技术方面的考量包括:软件架构(分层架构、六边形架构)、构造型分类。

目录结构的分层

常见的项目的目录结构基本上由:领域名(domain)、层名(layer)、构造型名(stereotype)、业务模块名(module)这四个部分组成。

1. 领域(业务域、子域)名称

在《领域驱动设计》中的领域通常是指一个业务域,是一个特定的业务范围。对于大多数的业务(问题)来说不会超出所在业务域的范围,因此业务域的名称在项目的目录(包、模块)结构中能起到限界作用。比如:产品目录子域(Catalog)、订单子域(Order)、物流子域(Shipping)、发票子域(Invoice)等等。

2. 层名称

在项目的目录结构中显式的引入层名是一种技术考量,更具体一些是编码的考量。分层架构是一种从混乱到有序的解决方案(架构模式)。它的做法是将一个应用程序(流程)划分为多组子任务,其中每组子任务都位于特定抽象层中。例如:分层架构在应用系统的后端开发中,常将一个应用系统划分为三层架构或者四层架构。

三层架构:
表现层(Presentation)
业务逻辑层(Business)
持久层(Persistence)

四层架构:
表现层(Presentation)
应用(逻辑)层(Application)
领域层(Domain)
基础设施层(Infrastructure)

在四层架构中的基础设施层要比三层架构中的持久层的功能多一些。

在应用系统开发中的分层架构并不是严格意义上的分层架构。真正的分层表示为上层只能依赖下层,是单向依赖,不能存在双向依赖。具体来说有以下特点:

J 层依赖 J - 1 层,J + 1 层依赖 J 层。
J - 1 层不会依赖 J 层,J 层也不会依赖 J + 1 层。
J + 1 层也不会依赖 J - 1 层。
层与层之间通过数据的封装、转换或者直接使用来做到隔离。

在追求性能和灵活性方面,出现了两种分层变种:宽松的分层系统(Relaxed Layered System)和通过继承进行分层(Layering Through Inheritance)。我们将简要讨论 宽松的分层系统,因为普遍地应用系统采用的就是宽松的分层系统。
宽松的分层系统表示:每层都可以使用它的下层服务,而不仅仅是下一层的服务。每层都可能是半透明的,这意味着有些服务只对上一层可见,而有些服务对上面的所有层都可见。

就算是严格地分层架构或者宽松的分层架构,都表明是上层依赖下层。但在实际地应用系统的架构中并没有完全遵循这种依赖关系,因为架构人员需要在整体架构与分层架构之间进行摇摆球式思考。比如:在领域(Domain)层中的 Repository 接口的实现类往往会放在基础设施(Infrastructure)层中,这显然违反了分层架构中的单向依赖关系。这样的问题有两种解决方案:一是诚然接受。二是将领域层中的 Repository 接口的实现类放置在领域层内。

3. 构造型名称(stereotype)

构造型使用书名号(《》)来表示,用于区分不同地建模元素。
如:实体(entity)、枚举(enumeration)、异常(exception)、查询(query)、事件(event)、资源库(repository)、服务(service)、控制器(controller)等等都是常见的构造型。
有些项目在划分目录结构时,会将构造型显式的引入到目录结构中,这是一种归类的组织方式。
如entity包,service包等。

4. 业务模块(module)

在分析一个业务(问题)域时,会将一个业务域划分为多个业务模块。比如在商店(Store)子域中会被划分为:商店员工(Staff)、商店会员(Member)、商店角色(Role)等等。
看到这里,如果你还迷茫,那我再来举个例子:
商品领域 划分成 商品品牌模块、商品类目模块、商品模块等
所以,领域是业务界限,业务模块是按抽象出的概念。

常见的目录结构

在分别对目录(包)结构的构成元素做了简单介绍后,下面要开始具体探讨由这些元素组合而成的目录结构了。

业务域名.层名.*
业务域名.层名.业务模块名.*
业务域名.构造型名.*
业务域名.构造型名.业务模块名.*
业务域名.(层名 & 构造型名).*
业务域名.(层名 & 构造型名).业务模块名.*
业务域名.业务模块名.*
业务域名.业务模块名.层名.*
业务域名.业务模块名.构造型名.*
业务域名.业务模块名.(层名 & 构造型名).*
业务域名.(业务模块名 & 层名 & 构造型名).*
(构造型名 || 层名).业务域名.业务模块名.*
补充说明:

省略包(package)的反向域名(org.mallfoundry.*)前缀的部分。
领域看作是业务域,其中业务域名是业务域 名,而不是业务 域名。
(层名 & 构造型名)是一种混合,表示在同一级别的目录(包)结构上同时存在按层和按构造型划分的两种方式。

我的理解

我的理解是:

  • 领域名一般在最上
  • 剩余三个,综合考量,谁最重要谁在前,不重要的也可以省略。
  • 层名中的应用层(Application)是很重要的一个考量点,如果应用层编排时会用到多个模块,则应用层不能低于模块名。本人做的项目大多是这种情况,一般层名为领域名下。
  • 如果模块清晰,且便于解耦,则分层结构中至少包含模块,模块越清晰,则越靠前,如:
业务域名.层名.业务模块名.*
业务域名.构造型名.业务模块名.*

//如果模块很清晰
业务域名.业务模块名.*
业务域名.业务模块名.层名.*
业务域名.业务模块名.构造型名.*
业务域名.业务模块名.(层名 & 构造型名).*
  • 层名更偏向于流程清晰,一般位于领域名下, 如果综合考量,模块的重要性 > 流程的重要性,那么层名也可位于模块名下,如:
业务域名.层名.*
├─catalog            // 商品领域层
│  ├─application        // 应用层
│  ├─domain             // 领域层
│  ├─infrastructure     // 基础设施层
│  └─presentation       // 表现层

业务域名.层名.业务模块名.*
├─catalog            // 商品领域层
│  ├─application        // 应用层
│  │  ├─brand
│  │  ├─category
│  │  └─product
│  ├─domain             // 领域层
│  │  ├─brand               // 商品品牌模块
│  │  ├─category            // 商品类目模块
│  │  └─product             // 商品模块
│  ├─infrastructure     // 基础设施层
│  │  └─persistent          // 持久化
│  │      ├─jpa
│  │      ├─mybatis
│  │      └─redis
│  └─presentation       // 表现层
│      ├─graphql
│      ├─grpc
│      ├─rest
│      ├─view
│      └─websocket

业务域名.业务模块名.层名.*
├─catalog
│  ├─brand
│  │  ├─application
│  │  ├─domain
│  │  ├─infrastructure
│  │  └─presentation
│  ├─category
│  │  ├─application
│  │  ├─domain
│  │  ├─infrastructure
│  │  └─presentation
│  └─product
│      ├─application
│      ├─domain
│      ├─infrastructure
│      └─presentation
  • 项目越简单,构造型名越靠前,对于比较复杂的项目,一般位于层名或模块名下
简单项目
├─catalog
│  ├─controller
│  ├─exception
│  ├─model
│  ├─query
│  ├─repository
│  └─service


参考:解读DDD中的包结构

©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 218,451评论 6 506
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 93,172评论 3 394
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 164,782评论 0 354
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 58,709评论 1 294
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 67,733评论 6 392
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 51,578评论 1 305
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 40,320评论 3 418
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 39,241评论 0 276
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 45,686评论 1 314
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 37,878评论 3 336
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 39,992评论 1 348
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 35,715评论 5 346
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 41,336评论 3 330
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 31,912评论 0 22
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 33,040评论 1 270
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 48,173评论 3 370
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 44,947评论 2 355

推荐阅读更多精彩内容