Package Structure
解决什么问题:目录结构 = 团队的心智地图——好的目录让新人 5 分钟找到代码,差的目录让 5 年老员工迷路。
它是什么
Package Structure(包结构) 是代码的物理组织方式——目录、模块、依赖方向的统一约定。它不是装饰,是工程纪律:
- 目录表达领域——看到
order/知道是订单相关 - 分层表达职责——
domain/vsapplication/vsinfrastructure/ - 依赖表达边界——领域层不依赖基础设施层(IDDD Ch 9)
IDDD Ch 9:"The choice of how to organize code... has profound impact on maintainability."
V2 视角(V2.7 B3 分解):包结构是"分解原则" 在代码层的体现——把单体系统分解为可独立演化的模块。
关键属性
| 属性 | 值/含义 |
|---|---|
| 三种风格 | 按层(layered)/ 按特性(feature)/ 混合(hybrid) |
| 依赖方向 | 内层(领域)不依赖外层(基础设施) |
| 粒度 | 一个 BC 一个 module / 一个聚合一个 package |
| 反模式 | 横向分层架构(横切所有 BC) |
| 核心约束 | 包结构 = BC 边界的物理映射 |
| 判错标准 | 改一个 BC 要碰另一个 BC = 包结构错位 |
| 演化 | 随 BC 数量和规模演化 |
怎么用
场景 1:单 BC 项目(小型)
按特性 + 分层混合(最常见):
com.example.order
├── domain # 领域层:实体、值对象、聚合、领域服务
│ ├── Order.java
│ ├── OrderItem.java
│ └── OrderService.java
├── application # 应用层:用例编排
│ └── PlaceOrderUseCase.java
├── infrastructure # 基础设施:DB、消息、外部 API
│ ├── OrderRepository.java
│ └── PaymentGatewayClient.java
└── interfaces # 入口:REST、GraphQL、CLI
└── OrderController.java关键:每个 BC 一个顶级包——BC 边界清晰可见。
场景 2:多 BC 项目(中型)
按 BC 切分顶级目录(BC 之间共享的不放在 BC 内):
com.example
├── order/ # 订单 BC
├── payment/ # 支付 BC
├── inventory/ # 库存 BC
└── shared # 共享 kernel(慎用!)
└── Money.javaV2 B3 视角:包结构 = 分解后的物理映射。每个 BC 一个 root——这就是控制论的"按对象分解"。
场景 3:微服务/模块化单体
独立构建单元——一个 BC 一个 gradle/maven module:
order/
├── domain # 独立 module
├── application # 独立 module
├── infrastructure # 独立 module
└── interfaces # 独立 module关键:domain module 无 Spring/无 JPA——纯领域逻辑,可独立测试。
常见误区
- "按层切所有包"——错。
controller/service/dao横切所有 BC = 改一个 BC 全工程编译 - "通用工具包"——错。
utils//common/经常变成垃圾场。IDDD Ch 9 警告 Shared Kernel 滥用 - "包按角色而不是按 BC"——错。BC 是业务边界,不是技术边界。技术边界是 L2 关注点
- "目录深 = 清晰"——错。5 层嵌套没人想点。深度 ≤ 4 层最佳
- "package-private 是过度封装"——错。IDDD Ch 9:用 package 表达 BC 内可见性边界
关键洞察
包结构 = BC 边界的物理镜像 + 分解原则的工程实现。
控制论视角:包结构是"按对象分解"——一个对象(BC)对应一个子系统(package)。 IDDD Ch 9 视角:包 = 模块 = Ubiquitous Language 在目录层的固化——目录名应当和业务语言一致。 SE@G Ch 16 视角:大仓(monorepo)的核心是 BUILD TARGET 与目录一致——目录 = 构建边界。 EDM 视角:异步事件的 producer/consumer 目录要分清——耦合是事件 schema,不是目录层级。
相关链接
- Coding Convention——目录命名约定
- Bounded Context——目录映射的源头
- [V3 涌现作为] · 分解——包结构 = 分解的物理形态
- [V3 涌现作为] · 抽象——共享 kernel 的取舍
- 源典:IDDD Ch 9——Modules 的命名容器
- 源典:SE@G Ch 16——大规模代码组织