为什么 Modular Monolith 适合独立开发者与 AI 协作开发

摘要

Modular Monolith 是一种“保持单一部署单元,但在内部强制清晰模块边界”的架构。对于独立开发者、小团队,以及越来越多和 AI 一起开发产品的人来说,它往往比过早引入 Microservices/MSA 更现实。

从经营公司、也亲自写代码的角度看,我最近明显感到:问题已经不再只是“以后会不会变大,所以要不要一开始就 MSA”,而是“能不能让 AI 和人都看得懂边界,同时保持部署简单”。这篇文章会比较 Monolith、Modular Monolith 和 Microservices/MSA,并整理实际选择标准。

目录

背景

过去一段时间,Microservices/MSA 经常被当成大型系统的标准答案。按业务能力拆分服务、独立部署、隔离故障、让团队独立推进。这些优点在合适规模下确实存在。

但小团队很快会感受到成本。哪怕只有五个服务,也会多出认证、网络、部署流水线、日志、Tracing、故障点和数据一致性问题。很多时候,真正拖慢速度的不是业务代码,而是服务之间的连接和运维。

Modular Monolith 不是回到没有结构的旧式 Monolith。它更像是:像设计 MSA 一样认真对待 domain boundary,但在业务真正需要分布式之前,保持部署和运维简单。

三种架构的基本区别

传统 Monolith

Monolith 通常是一个代码库、一个部署单元、一个运行时。启动很快,本地调试简单,数据库事务也直接。

问题出现在边界消失之后。Order 代码直接改 Member 表,Payment 代码知道 Shipping 的内部实现,最后变成“大家都不敢改”的大项目。

Modular Monolith

Modular Monolith 仍然是一个应用部署,但内部按 domain module 分开。比如 memberorderpaymentnotification,每个模块拥有自己的规则,并只暴露有意设计的入口。

src/
  member/
  order/
  payment/
  notification/
  shared-kernel/   # 尽量小

这样才是正常状态:运行时保持简单,但代码理解、测试和未来拆分都有边界。

MSA / Microservices

Microservices 会把系统拆成多个可独立部署的服务,通常按业务能力划分。每个服务倾向于拥有自己的数据,通过 HTTP、gRPC、Message/Event 进行通信。

它的优势是独立扩展、独立部署和更好的故障隔离。代价是分布式系统复杂度:timeout、retry、idempotency、observability、eventual consistency 和部署自动化。

Monolith vs Modular Monolith vs MSA 对比

标准 Monolith Modular Monolith MSA / Microservices
部署单元 一个 一个 多个服务
内部边界 容易变弱 通过 domain module 强制 通过 service boundary 强制
初期开发速度 快,但需要规则 容易变慢
运维复杂度 低到中等
数据一致性 本地事务简单 所有权清晰时仍然可控 需要处理分布式事务或最终一致性
故障隔离 代码隔离强,进程隔离弱 更强
团队适配 小团队 独立开发者、小团队、复杂 domain 按 domain 拆分的团队
与 AI 协作 项目变大后 context 困难 适合按 module 给 context 服务 context 小,但运维知识更多
未来扩展 无边界时拆分成本高 边界真实时更容易抽取服务 已经分布式,但持续支付分布式成本

为什么适合独立开发者 + AI

AI 更需要清晰的 bounded context

如果项目内部依赖混乱,prompt 会越来越长,修改范围也更危险。有了真实 module boundary,就可以明确告诉 AI:“只修改 order module;payment 只能通过 public interface 调用,不要改内部实现。”

单一部署能保护开发速度

独立开发者每多一个服务,就多一个要部署、监控、加密、排障的对象。AI 写代码很快,但生产环境仍然只有一个人负责。很多时候,单一部署单元反而是更好的速度保护。

测试仍然可以模块化

不拆服务也能按边界测试。最基本的层次可以是:

module unit test → module integration test → application smoke test

这样 AI 生成的修改也有安全网,而不必过早进入分布式运行时。

实际设计时要看的标准

先划分 domain boundary

不要先追求漂亮的目录。先问:哪部分业务因为什么原因变化?Member、Order、Payment、Settlement、Notification 经常因为不同原因变化,所以是常见 module 候选。

规定 module 访问规则

最常见的失败是目录分开了,但仍然随意 import 其他 module 的内部 repository。更好的方式是只开放 application service、facade 或 event。

一个数据库可以,但所有权不能模糊

Modular Monolith 可以从一个数据库开始。关键是 table ownership。Order module 如果随意 update Payment 表,未来拆服务会非常痛苦。

shared code 要小

巨大的 common package 会变成隐藏的 Monolith。共享代码只放稳定类型和工具函数,业务规则留在拥有它的 domain module。

开发与运维上的差异

Observability 要提前设计

即使是单一应用,日志也应该带 module name、request id 和 domain id。

module=order request_id=... order_id=... event=OrderCreated

这个习惯会让未来抽取服务更容易。

单一部署不等于大版本发布

可以用小 PR、feature flag、module changelog 和 smoke test。一个部署产物也可以小步安全发布。

拆服务前先测量

不要因为“以后可能要单独扩展”就先拆服务。先确认瓶颈是否真实,cache 或 query tuning 能否解决,独立部署是否真的值得。

从 Modular Monolith 迁移到 Microservices

健康策略不是“为了未来先 MSA”,而是“现在建立边界,等有真实理由时再抽取”。

1. 在代码中强制边界

可以使用 package dependency check、architecture test,或 Spring Modulith 这类工具,让规则进入 CI,而不是靠团队记忆。

2. 整理数据所有权

准备抽取的 module 应该拥有自己的表。其他 module 应该通过 public API 或 event 交互,而不是直接写表。

3. 先使用内部事件

第一天不需要 Kafka。可以先在内部表达 “OrderCreated”、“PaymentCompleted” 这样的事实。以后转到外部消息系统会更自然。

4. 只抽取有强理由的 module

独立扩展、独立部署、故障隔离、独立团队所有权,这些才是强理由。没有这些理由,留在 Modular Monolith 里通常更好。

常见误区与失败场景

“只分目录就是 Modular Monolith 吗?”

不一定。判断标准是依赖方向,不是目录名称。如果每个 module 都能随意调用别人的内部 repository,边界就不存在。

“MSA 一定更现代吗?”

Microservices 很强,但不是免费的。Service discovery、gateway、monitoring、tracing、deployment automation 和 data consistency 都会变成产品工作的一部分。

“一个数据库会阻止未来拆分吗?”

不一定。更危险的是没有所有权。一个数据库但 table ownership 清楚,往往比多个服务共享同一批表更健康。

“AI 会让架构不那么重要吗?”

不会,反而更重要。AI 在清晰边界内很快;没有边界时,它也可能快速做出大范围、高风险修改。

什么情况下选哪一种

适合传统 Monolith 的情况

Prototype、短期内部工具、简单 CRUD 系统,可以直接 Monolith。只要产品可能长期存在,建议早期就加一点 module boundary。

适合 Modular Monolith 的情况

独立开发者、小型 startup team、AI-assisted product、domain 已经变复杂但组织还没有按 service 拆分时,很适合 Modular Monolith。这也是我现在对很多新项目更倾向的默认值。

适合 MSA 的情况

团队已经按 domain 分开,确实需要独立部署,有明确扩展或故障隔离需求,并且具备分布式系统运维能力时,MSA 才更合适。

结论

我的实际结论是:对于独立开发者 + AI,以及很多小团队来说,Modular Monolith 是更现实的默认选择。 它保持部署简单,同时让人和 AI 都能理解系统边界。

但这并不是说永远不要 Microservices。当组织、流量、部署节奏和故障隔离需求足以抵消成本时,MSA 当然可以是正确选择。关键不是一开始有多少服务,而是一开始有没有清晰边界。

你怎么看?在 AI-assisted development 时代,独立开发者和小团队的默认架构应该是 Modular Monolith 吗?

参考资料

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注