包图是什么
包图用包(Package)与其间的依赖关系组织模型元素,包相当于命名空间,包之间用虚线箭头表示依赖:«import» 引入对方公开的可见元素,«access» 只引入私有元素。它在工程实践里最主要的用途不是画完整模型,而是检查分层依赖方向与循环依赖:包之间出现环时编译照样通过,但演进会被卡住,任何一方的改动都可能牵动另一方。因此很多人直接把包图当成架构约束的可视化表达。
基本信息
| 包 | 对模型元素的分组,形成命名空间,可嵌套 |
|---|---|
| 依赖 | 虚线箭头;«import» 引入公开元素,«access» 引入私有元素 |
| 划分依据 | 按业务能力或职责划分,避免按技术层平铺 |
| 主要用途 | 分层评审、循环依赖检测、模块边界约定 |
| 自动化检查 | 用依赖规则工具在构建期扫描包引用,违反即失败 |
典型使用场景
- 分层评审:确认接口层、应用层与领域层的依赖方向正确
- 循环依赖排查:发现互相引用的包并决定下沉公共部分或反转依赖
- 模块拆分:把大单体拆成模块前,先用包图理清边界与依赖
- 新人上手:一张包图就能说明代码结构与改动落点
- 架构守护:把允许的依赖关系写成规则,在流水线中持续校验
- 技术债治理:标记不合理依赖并排期重构
依赖检查示例
| 关系 | 是否允许 | 说明 |
|---|---|---|
| ui → application → domain | 允许 | 依赖单向向内,符合分层原则 |
| infrastructure → domain | 允许 | 基础设施实现领域定义的接口 |
| domain → infrastructure | 禁止 | 领域层引入框架与驱动依赖,破坏可测试性 |
| order → user | 视约定 | 跨业务能力引用需要显式评审,避免边界模糊 |
| module-a ↔ module-b | 禁止 | 双向依赖形成环,改动无法独立进行 |
约束落地方式
约束落地方式
# 1 把包图写成规则:允许的依赖关系逐条列出,其余默认禁止
# 2 构建期扫描:用依赖规则工具(如 ArchUnit 类方案)检查包引用
# 3 失败即阻断:违反规则的提交不允许合并,规则随架构决策一起更新
# 4 例外管理:确需放行的依赖写明原因与到期时间,定期复查
# 5 变更同步:包结构或分层调整时,先改图再改代码包之间出现环状依赖时,编译能通过但演进受阻:任何一方的改动都可能牵连另一方,且很难单独测试与替换,发现环后应尽快下沉公共部分或反转依赖方向。
按技术层平铺划分包(controller、service、dao)会让同一业务改动散落各处;按业务能力划分包,再在包内部做技术分层,通常更利于演进。