AI 时代,为什么我们更需要 Deep Module?
AI 时代,为什么我们更需要 Deep Module?
过去几十年,软件工程一直在追求一件事:
把复杂的软件拆开。
我们拆分函数。
拆分类。
拆分模块。
拆分服务。
拆分微服务。
拆得越来越细之后,我们通常会认为:
模块越小,职责越单一,系统就越容易维护。
但今天,当 AI 开始真正参与软件开发时,我越来越怀疑:
“拆得更细”真的是正确的方向吗?
也许,我们真正需要的不是更多模块。
而是:
更深的模块。
这就是 Deep Module。
一、什么是 Deep Module?
Deep Module 的概念来自 John Ousterhout 在《A Philosophy of Software Design》中提出的软件设计思想。
理解 Deep Module,可以先看一个非常简单的模型:
模块 = 接口 + 实现
一个模块对外暴露的是接口。
模块内部隐藏的是实现。
那么,一个模块的“深度”可以简单理解为:
它提供的能力,与它暴露的复杂度之间的比例。
可以理解成:
模块深度 = 模块提供的能力
─────────────
模块对外暴露的复杂度
一个模块能够提供大量能力,但只需要用户理解一个简单接口。
那么它就是一个 Deep Module。
相反,如果一个模块本身没有提供多少能力,却要求调用者理解大量细节,那么它就是一个 Shallow Module。
二、一个经典例子:Unix 的文件系统
文件系统是 Deep Module 的典型例子。
应用程序调用:
FileInputStream input = new FileInputStream("data.txt");
或者:
Files.readAllBytes(path);
接口非常简单。
但文件系统内部实际上隐藏了大量复杂性:
- 磁盘块管理
- 文件索引
- 缓存
- 文件描述符
- 权限控制
- 并发访问
- 文件系统结构
- IO 调度
- 异常恢复
调用者不需要理解这些东西。
它只需要知道:
我要读取一个文件。
这就是 Deep Module。
┌──────────────────────────────┐
│ 简单接口 │
│ │
│ read(file) │
├──────────────────────────────┤
│ │
│ │
│ 巨大的内部能力 │
│ │
│ 文件系统、缓存、磁盘、权限等 │
│ │
└──────────────────────────────┘
模块内部很复杂。
但是模块外部很简单。
这就是:
Deep Module 的核心价值:把复杂性藏在模块内部。
三、我们今天的软件,为什么越来越“浅”?
现代软件开发中有一个非常有趣的现象。
我们一直强调:
- 单一职责
- 高内聚
- 低耦合
- 小函数
- 小类
- 小模块
这些原则本身没有问题。
但它们经常被过度理解。
于是代码开始变成这样:
OrderController
↓
OrderApplicationService
↓
OrderDomainService
↓
OrderValidator
↓
OrderAssembler
↓
OrderRepository
↓
OrderMapper
一个“创建订单”的功能,可能只包含几百行代码。
但开发者却需要在:
7 个类、多个包、多个抽象层
之间不断跳转。
每一个类都很小。
每一个类都有自己的职责。
从局部来看,它们都很“干净”。
但从整体来看:
理解一个简单业务,却需要穿越大量模块。
这就是一个非常典型的问题:
局部简单,整体复杂。
四、Shallow Module 的真正问题
假设我们有两个设计。
设计 A:大量浅模块
CreateOrderController
CreateOrderService
CreateOrderValidator
CreateOrderAssembler
OrderRepository
OrderMapper
InventoryService
PriceService
每个模块都很小。
每个模块的接口也很简单。
但要完成一个任务,你必须理解:
模块 A
↓
模块 B
↓
模块 C
↓
模块 D
↓
模块 E
问题来了:
复杂性并没有消失。
它只是从模块内部转移到了:
模块之间。
于是开发者需要不断理解:
- 谁调用谁?
- 数据从哪里来?
- 为什么这里要转换 DTO?
- 这个逻辑应该放在哪一层?
- 为什么这个 Service 又调用了另一个 Service?
- 修改一个功能会影响哪些类?
代码虽然被拆开了。
但理解成本却增加了。
设计 B:一个 Deep Module
OrderModule
createOrder()
cancelOrder()
payOrder()
confirmOrder()
内部:
┌──────────────────────────────┐
│ Order Module │
│ │
│ createOrder() │
│ │
├──────────────────────────────┤
│ │
│ 参数校验 │
│ 商品校验 │
│ 价格计算 │
│ 库存检查 │
│ 订单创建 │
│ 数据持久化 │
│ │
└──────────────────────────────┘
外部调用者只需要知道:
orderModule.createOrder(command);
至于:
- 如何验证
- 如何计算价格
- 如何创建订单
- 如何保存订单
这些复杂性被隐藏起来。
这就是 Deep Module。
五、Deep Module 并不意味着“大模块”
这里非常容易产生一个误解。
Deep Module ≠ Big Module。
一个模块代码很多,并不代表它就是 Deep Module。
Deep Module 的核心不是:
代码多。
而是:
能力强,但接口简单。
例如:
orderService.createOrder(command);
这个接口可能非常简单。
但它内部可能协调:
- 商品
- 库存
- 优惠
- 价格
- 支付
- 风控
它仍然可以是一个 Deep Module。
相反,一个只有几十行代码的模块:
OrderDtoAssembler
可能只有一个:
convert()
看起来很简单。
但它提供的价值非常有限。
如果调用者还必须理解:
- 输入对象是什么
- 输出对象是什么
- 为什么需要转换
- 转换应该发生在哪里
那么它可能就是一个典型的 Shallow Module。
所以:
Deep 和代码规模没有直接关系。
真正重要的是:
模块对外的复杂度,是否远小于它内部承担的复杂度。
六、为什么 Deep Module 在 AI 时代更加重要?
这才是我认为最值得讨论的部分。
过去,软件主要是给人开发和维护的。
但今天的软件正在出现一个新的参与者:
AI。
AI 不只是帮我们自动补全代码。
它开始参与:
- 阅读代码
- 理解业务
- 修改功能
- 修复 Bug
- 重构代码
- 编写测试
- 创建新模块
这意味着:
软件架构开始需要考虑 AI 的理解成本。
七、AI 最怕的东西:上下文碎片化
AI 与人类开发者有一个非常重要的区别。
一个经验丰富的开发者长期在一个项目中工作。
他会逐渐形成:
项目的心智模型。
他知道:
- 订单逻辑在哪里
- 库存逻辑在哪里
- 哪个 Service 是核心入口
- 哪些代码只是 DTO 转换
- 哪些类只是技术层
但 AI 每次进入一个任务,都需要重新建立上下文。
例如:
“修改创建订单逻辑。”
AI 需要找到:
Controller
↓
Application Service
↓
Domain Service
↓
Validator
↓
Assembler
↓
Repository
↓
Mapper
然后还可能需要:
Product Service
Inventory Service
Coupon Service
Payment Service
AI 必须不断:
搜索 → 阅读 → 推理 → 搜索 → 阅读 → 推理
模块越碎。
上下文越分散。
AI 的理解成本越高。
八、AI 时代真正重要的是:上下文局部性
对于 AI 来说,一个非常重要的概念是:
Context Locality(上下文局部性)。
一个功能相关的信息,最好尽可能集中。
例如:
order/
│
├── CreateOrder.java
├── CreateOrderHandler.java
├── Order.java
├── OrderRepository.java
├── OrderPolicy.java
└── OrderModule.java
AI 想修改订单。
它进入:
order/
大部分相关上下文就在附近。
而不是:
controller/order/
service/order/
repository/order/
mapper/order/
domain/order/
到处寻找。
这就是为什么我越来越认为:
AI 时代的软件架构,应该从“技术分层优先”转向“上下文完整性优先”。
九、Deep Module 的真正价值:压缩复杂性
Deep Module 对 AI 最大的价值,并不是“模块更少”。
而是:
它可以压缩 AI 需要理解的复杂性。
假设一个模块内部有 1000 行复杂代码。
但是它对外只暴露:
OrderResult createOrder(CreateOrderCommand command);
那么对于其他模块来说:
这 1000 行代码不需要理解。
它们只需要理解:
输入是什么?
输出是什么?
模块保证什么?
失败会发生什么?
这实际上是在做:
Complexity Compression(复杂性压缩)。
内部:
1000 行复杂逻辑
库存
价格
优惠
校验
事务
↓ Deep Module
外部:
createOrder(command)
复杂性没有消失。
但它被压缩到了一个明确的边界之后。
十、AI 不需要理解整个系统
传统软件开发经常存在一种隐性假设:
开发者最终应该理解整个系统。
但对于大型系统来说,这越来越不现实。
而 AI 时代,我们应该接受一个新的事实:
任何一次任务,都不应该要求理解整个系统。
修改订单:
理解 Order Module
修改库存:
理解 Inventory Module
修改支付:
理解 Payment Module
模块之间通过稳定接口协作。
这意味着:
系统复杂,但任务上下文可以简单。
这正是 Deep Module 最重要的价值。
十一、Deep Module 与 Domain Module
Deep Module 并不是要求把整个系统塞进一个巨大模块。
更合理的方式是:
系统先按照领域拆分。
例如:
system
│
├── order
│
├── inventory
│
├── payment
│
├── product
│
└── user
每一个领域模块:
都是一个相对独立的自治单元。
例如:
Order Module
│
├── 对外能力
│ ├── createOrder
│ ├── cancelOrder
│ └── queryOrder
│
└── 内部实现
├── 订单规则
├── 状态机
├── 数据访问
└── 技术实现
这样形成一个非常重要的架构思想:
领域模块之间保持明确边界。
模块内部可以拥有复杂实现。
模块外部只需要理解能力接口。
这就是:
Domain Autonomy + Deep Module
领域自治单元 + 深模块。
十二、这与传统分层架构有什么区别?
传统架构通常是:
Controller Layer
Service Layer
Repository Layer
Infrastructure Layer
系统按照:
技术职责
进行组织。
Deep Module 更强调:
Order Module
Inventory Module
Payment Module
系统首先按照:
业务能力
进行组织。
然后模块内部再组织技术结构。
例如:
order
│
├── interfaces
│
├── application
│
├── domain
│
└── infrastructure
这两者最大的区别是:
传统横向架构
Controller
├── OrderController
├── PaymentController
└── InventoryController
Service
├── OrderService
├── PaymentService
└── InventoryService
理解订单,需要跨越整个系统。
领域自治架构
Order
├── Controller
├── Application
├── Domain
└── Infrastructure
Payment
├── Controller
├── Application
├── Domain
└── Infrastructure
理解订单,只需要进入:
Order
这对于 AI 非常重要。
十三、AI 时代的软件架构,需要新增一个指标
过去我们评价架构时,通常关注:
- 可维护性
- 可扩展性
- 性能
- 可测试性
- 解耦程度
但 AI 时代,我认为应该增加一个新的指标:
AI Understandability
AI 可理解性。
一个架构应该让 AI 能够快速回答:
这个功能在哪里?
这个模块负责什么?
修改这个功能需要看哪些代码?
这个模块依赖谁?
谁可以调用这个模块?
修改这里可能影响什么?
如果这些问题需要跨越几十个目录、上百个文件。
那么即使架构理论上非常优雅:
它可能也不是 AI 友好的架构。
十四、未来的软件模块,应该像“能力黑盒”
我认为未来一个好的模块应该越来越像:
┌──────────────────────────────┐
│ │
│ Order Module │
│ │
│ 我能够做什么? │
│ │
│ ✓ 创建订单 │
│ ✓ 取消订单 │
│ ✓ 查询订单 │
│ │
├──────────────────────────────┤
│ │
│ 内部如何实现? │
│ │
│ 不需要外部关心 │
│ │
└──────────────────────────────┘
外部系统只关心:
你能提供什么能力?
而不是:
你内部有多少 Service?
有多少 Repository?
使用什么 ORM?
如何组织 DTO?
这些都应该尽可能隐藏。
十五、Deep Module 并不是“隐藏一切”
当然,Deep Module 也不能被理解成:
把所有代码藏起来。
真正需要隐藏的是:
实现复杂性。
但不能隐藏:
业务语义。
例如:
createOrder(command)
这个接口很好理解。
但是:
executeProcess(command)
虽然也隐藏了实现。
但语义不明确。
所以好的模块接口应该:
隐藏实现复杂性,但暴露清晰的业务能力。
这是非常重要的原则。
十六、AI 时代的 Deep Module 设计原则
我认为可以总结成五条原则。
1. 按能力组织,而不是按技术组织
优先:
order/
payment/
inventory/
而不是:
controller/
service/
repository/
2. 对外接口尽可能少
模块不应该暴露:
OrderRepository
OrderMapper
OrderEntity
OrderAssembler
而应该暴露:
OrderFacade
或者:
OrderModule
例如:
orderModule.createOrder(command);
orderModule.cancelOrder(command);
orderModule.getOrder(id);
3. 内部实现可以复杂
不要为了:
“每个类必须很小”
而无限拆分。
如果几个逻辑:
- 强相关
- 总是一起修改
- 属于同一个业务能力
那么它们可能应该放在一起。
4. 一个任务尽可能只进入一个领域
理想情况下:
修改订单逻辑 → 进入 Order Module。
而不是:
修改订单逻辑 → 搜索整个项目。
5. 模块之间通过能力协作
例如:
Order Module
│
│ reserveStock()
↓
Inventory Module
而不是:
Order Module
↓
直接访问 InventoryRepository
模块应该依赖:
能力。
而不是:
内部实现。
十七、真正的变化:软件架构开始服务于“理解”
过去的软件架构主要解决的是:
如何组织代码。
未来的软件架构可能越来越关注:
如何降低理解成本。
因为未来参与软件开发的,不再只有人。
还有:
AI。
于是架构的目标可能发生变化。
从:
如何让代码运行?
变成:
如何让系统更容易被理解?
从:
如何让开发者维护?
变成:
如何让开发者和 AI 都能够维护?
结语:Deep Module,也许正在成为 AI 时代的重要架构思想
我并不认为 Deep Module 是一个全新的概念。
事实上,它已经存在很多年。
真正发生变化的是:
AI 让我们重新意识到了模块边界的重要性。
当软件越来越复杂。
当代码越来越多。
当 AI 开始参与开发。
一个问题会变得越来越重要:
AI 需要理解多少上下文,才能完成一次修改?
如果答案是:
整个系统。
那么这个系统一定会越来越难维护。
但如果答案是:
一个清晰的领域模块。
那么复杂系统就可以被拆成一个个:
人和 AI 都能够独立理解的自治单元。
这也许就是 Deep Module 在 AI 时代最大的价值:
不是减少代码。
不是减少模块。
而是把复杂性关进正确的边界里。
让系统整体可以很复杂。
但让每一次理解,都尽可能简单。
未来的软件架构,也许会越来越从:
技术分层驱动的软件结构
转向:
领域自治单元驱动的软件结构。
而 Deep Module,将成为这些自治单元最重要的设计原则之一。
好的模块,不是内部没有复杂性。
而是能够承担巨大的复杂性,却不把复杂性转嫁给外部。
这,就是 Deep Module。
更多推荐



所有评论(0)