Skip to content

Package Structure ​

解决什么问题:目录结构 = 团队的心智地图——好的目录让新人 5 分钟找到代码,差的目录让 5 年老员工迷路。

它是什么 ​

Package Structure(包结构) 是代码的物理组织方式——目录、模块、依赖方向的统一约定。它不是装饰,是工程纪律:

  • 目录表达领域——看到 order/ 知道是订单相关
  • 分层表达职责——domain/ vs application/ vs infrastructure/
  • 依赖表达边界——领域层不依赖基础设施层(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.java

V2 B3 视角:包结构 = 分解后的物理映射。每个 BC 一个 root——这就是控制论的"按对象分解"。

场景 3:微服务/模块化单体 ​

独立构建单元——一个 BC 一个 gradle/maven module:

order/
├── domain         # 独立 module
├── application    # 独立 module
├── infrastructure # 独立 module
└── interfaces     # 独立 module

关键:domain module 无 Spring/无 JPA——纯领域逻辑,可独立测试。

常见误区 ​

  1. "按层切所有包"——错。controller/service/dao 横切所有 BC = 改一个 BC 全工程编译
  2. "通用工具包"——错。utils/ / common/ 经常变成垃圾场。IDDD Ch 9 警告 Shared Kernel 滥用
  3. "包按角色而不是按 BC"——错。BC 是业务边界,不是技术边界。技术边界是 L2 关注点
  4. "目录深 = 清晰"——错。5 层嵌套没人想点。深度 ≤ 4 层最佳
  5. "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,不是目录层级。

相关链接 ​

从名家方法论与工程化思路中蒸馏出自己的工程体系。