目录
为什么重新讨论 Modular Monolith
过去很多团队在系统变大时,会自然想到 Microservices/MSA。独立部署、独立扩展、团队各自负责服务,这些听起来都很合理。但 Architecture 不只是代码结构,也包括运维方式。
现在很多产品是个人或小团队借助 AI coding tools 快速开发出来的。在这种情况下,Microservices 可能会过早带来成本:多个 repository、多个 pipeline、日志、监控、网络故障、服务契约、数据一致性等问题。
Modular Monolith 的做法是:部署仍然是一个应用,但内部按照业务模块清晰拆分。它保留 Monolith 的运维简单性,同时避免代码变成 Big Ball of Mud。
Monolith、Modular Monolith、Microservices 的区别
Monolith
Monolith 通常是一个部署单元。早期开发、测试、debug、发布都很简单。问题是系统增长之后,边界容易消失,任何修改都可能影响全局。
Modular Monolith
Modular Monolith 仍然是一个可部署应用,但内部用明确的 module 或 bounded context 分隔。例如会员、订单、支付、结算、通知分别作为模块,只通过公开接口或事件交互。
Microservices / MSA
Microservices 把应用拆成多个可独立部署的服务,通常围绕 business capability 组织。它适合多个自治团队和独立扩展需求,但需要 DevOps、observability、自动化部署和分布式系统经验。
对比表
| 类型 | Monolith | Modular Monolith | Microservices/MSA |
|---|---|---|---|
| 部署 | 一个应用 | 一个应用 | 多个服务 |
| 边界 | 容易变弱 | 明确的 module/bounded context | 网络/服务边界 |
| 运维 | 简单 | 简单到中等 | 复杂 |
| 扩展 | 整体扩展 | 整体扩展 | 按服务扩展 |
| 适合 | MVP、小工具 | 个人开发 + AI、小团队、领域还在变化 | 多团队、成熟平台、边界清晰 |
个人开发 + AI 的变化
AI Agent 工作时依赖有限的 context window。如果系统被拆成很多服务、repository、部署规则和数据库,人和 AI 都需要处理更多上下文。Modular Monolith 可以让你把任务限制在某个 module 内,同时仍然保持本地运行简单。
这并不是说 AI 一定要求 Modular Monolith,而是说对于个人开发者和小团队来说,它常常在结构清晰和运维成本之间取得更好的平衡。
设计要点
- 按业务能力拆 module,而不只是 controller/service/repository。
- 限制对其他 module 内部类的直接访问。
- 即使先共享数据库,也要定义表和数据的归属。
- 为 module 建立测试,让 AI 修改代码时更安全。
常见误区
Modular Monolith 不只是文件夹整理
如果模块之间可以随意 import 内部实现,那只是换了文件夹名字的 Monolith。
MSA 是运维分离,不只是代码分离
服务通过网络通信之后,就必须处理 latency、timeout、retry、monitoring、部署顺序和数据一致性。
第一天不需要找到完美边界
业务边界会变化。Modular Monolith 允许你先在代码层调整边界,再决定是否变成独立服务。
什么时候应该拆成 Microservices
当独立扩展、团队发布冲突、故障隔离、稳定服务契约、成熟的监控和部署体系带来的价值超过成本时,再把某个 module 拆成服务会更安全。
结论
如果是个人开发者和 AI 一起开发,我通常会先选择 Modular Monolith,而不是一开始就做 Microservices。这不是只看理论得出的结论。实际使用 Claude Code、Codex、Gemini 等工具,在 MSA 风格的系统里消耗大量 token 开发之后,我确实感受到了一堵很现实的墙。
一开始会觉得,有了 AI,Microservices 应该更容易。把职责按 service 拆开,让 AI 分别处理每个 codebase,看起来会更清晰。但实际做起来,context 很快就分散了。你需要反复解释 API contract、数据库归属、message/event 名称、环境变量、认证流程、部署规则和日志位置。人会累,AI 也会漏掉细节。
对个人开发者来说,成本往往不是写代码本身,而是持续记住并对齐这些被拆散的部分。改一个 service,要确认另一个 service 的契约;本地复现完整流程,要启动多个进程和依赖;AI 在单个 repository 里改得看似合理,但跨服务集成时很容易出现微妙的不一致。最后,即使花了很多 token,集成验证的压力还是回到开发者身上。
所以我最后更倾向于 Modular Monolith。运维保持简单,但代码里严格管理 module 边界。你可以明确告诉 AI:“只看订单 module”,“不要修改支付 module 的公开接口”。本地运行和测试仍然在一个应用里完成,只有当独立部署或独立扩展真的有价值时,再把某个 module 抽成 service。对我的场景来说,这更像是个人开发者和 AI Agent 能长期合作下去的结构。
你怎么看? 在 AI 辅助开发越来越普遍的现在,小团队应该一开始就选择 Microservices,还是从 Modular Monolith 开始更现实?
参考资料
- Microsoft Learn — Common web application architectures: https://learn.microsoft.com/en-us/dotnet/architecture/modern-web-apps-azure/common-web-application-architectures
- AWS — What are Microservices?: https://aws.amazon.com/microservices/
- Martin Fowler / James Lewis — Microservices: https://martinfowler.com/articles/microservices.html
- Martin Fowler — Monolith First: https://martinfowler.com/bliki/MonolithFirst.html
- Martin Fowler — Microservice Prerequisites: https://martinfowler.com/bliki/MicroservicePrerequisites.html
- Spring Modulith Reference: https://docs.spring.io/spring-modulith/reference/
- microservices.io — Monolithic Architecture: https://microservices.io/patterns/monolithic.html
- microservices.io — Microservice Architecture: https://microservices.io/patterns/microservices.html
- Kamil Grzybek — Modular Monolith: A Primer: https://www.kamilgrzybek.com/blog/posts/modular-monolith-primer
- Anthropic Docs — Context windows: https://docs.anthropic.com/en/docs/build-with-claude/context-windows.md