你养出了一支 AI 研发团队,可下一步呢?这支团队在什么"秩序"里交付——交付什么、不能交付什么、谁来验收、按什么标准验收?这一篇我们专门讲这件事。
这事关 AI 编码能力越强,我就越焦虑——不是为它焦虑,是为我自己焦虑。
你想啊,AI 写代码的速度肉眼可见地变快。三个月前还得一行一行喂,现在丢一份需求下去,它能刷刷刷给你整出一个完整模块。你看着 PR 列表一路绿灯,心里是开心的,可隔两天回头再看,发现某个角落它悄悄把领域实体混进了基础设施层;或者某个接口的命名风格飘到团队之外没人认识;又或者文档跟代码早就对不上号,它按文档写、按代码写、按自己"觉得合理"写,三套逻辑互相对不上。
这不是 AI 干得不够多,是秩序给得不够多。
AI 不是不需要规矩,AI 是更需要规矩——因为它能放大所有好事,也能放大所有坏事。你给它一份乐谱,它能演奏出交响乐;你不给它乐谱,它只能即兴发挥。即兴发挥的代价,是你看着它跑得飞快,结果架构一天天往泥潭里陷。
这一篇就把"AI 时代工程师该用哪三件秩序乐器"讲清楚。DDD、TDD、SDD——三个老朋友,过去是加分项;今天在 AI 面前,它们集体变成必选项。
不是教你 DDD 是什么(你早就会了),也不是教你 TDD 红绿蓝怎么循环(你早就不陌生),而是讲一件事:这三件乐器在 AI 时代怎么重新组合,怎么从"加分"变成"保命"。
更关键的是,我会讲清楚一个初版规划里漏掉的洞察——秩序不是锁死,秩序里有留白。焊死的是边界,放开的是选择。这两层合起来,才是 AI 时代完整的秩序。
下面我们一段一段拆。
一、AI 写代码越快,架构腐化越快——一个反直觉的现场
你可能觉得这标题反了——AI 越强,交付效率越高,架构应该越干净才对吧?
不是。真实现场的剧本,往往是这样演的:
第一周,AI 接进来。PR 哗哗地合,每个 PR 都有测试,都有文档。你心里乐开花:"这不就是我想要的 AI 工程师吗。"
第三周,某个看似无关的 PR 改了 User 实体的字段命名——userName 改成 name。它说"这样更符合英文习惯"。你皱了皱眉,但想着"反正有 P1 审查挡着",就让过了。
第六周,另一个 PR 把 OrderService 的 place() 方法换了一个新名字 submitOrder()——因为它"觉得读起来更通顺"。place() 是和 PaymentService.place() 对齐的语义约定,这一改,下游调用方全乱了。
第三个月,你打开代码库,发现五个领域实体的字段命名风格各不相同,三个服务的方法签名对不上 interface 层的约定,文档里有两套"领域服务"的定义,其中一套是 AI 自己造的——DomainUserService,跟 framework 六模块分层里 domain.UserDomainService 是两个完全不同的东西。
你回头看 PR 列表,三个月里没有任何一条 P0 红线被触发。每一条都是"看起来合理的小改动"。但合起来,架构已经悄悄腐化到了你想重构都不知从哪下手的地步。
这不是 AI 太笨,这是秩序太弱。
AI 没有"业务直觉"。它不知道这个项目的 User 是为 SaaS 多租户设计的,不知道 place() 是和支付链路语义对齐的,不知道 framework 六模块分层的硬规矩是"domain 零 Spring、common 零框架"。它只看到代码里现有的命名风格有几种、PR 历史里大家改过什么、上下文里你最近一次提的偏好是什么——它把"现在的样子"当成"应该的样子"。
更扎心的是,它不是在犯错,它是在学得过于认真。它在用最快的速度模仿你项目里的所有不规范,然后用同样的速度放大它们。
所以这个反直觉的结论你得先吞下去——
AI 编码能力越强,秩序越贵。
过去你写代码慢,三件事不写也不会让整个项目崩;现在 AI 写代码快,不写就崩给你看。这不是 AI 的问题,是你给它的秩序边界没跟上它扩张的速度。
那到底需要什么样的秩序?下面三节把 DDD、TDD、SDD 三件乐器一个个拆给你看。
二、失控的三个现场——根因不是 AI 太强,是秩序太弱
我们刚才说的"架构腐化"不是抽象的,是有具体现场的。我把过去一年 FDE 现场最常见的三种失控列出来,你看哪一个最扎心。
第一个失控:AI 凭印象写实体。
你跟它说"加一个 Tenant 实体吧",它没问你这个 Tenant 落在哪个限界上下文里、有没有现成的聚合根、值对象要不要拆、是不是已经有 TenantUser 这个上下文。它就照着它"印象里"的 Tenant——可能是某个开源项目里的,可能是别的语言里的——给你整出一个 id + name + createTime 三字段的贫血模型。
你打开一看:字段命名跟现有 User 不一致、缺租户成员关系、缺审计字段、连主键命名都没跟你项目的 TenantId 值对象对齐。你问它"为什么这么写",它说"我参考了项目里其他实体的风格"——但它的"参考"是它从几百个文件里提炼的"平均",不是项目真正的规范。
这不是 AI 的"业务理解"有问题,是它没有业务边界感。它不知道"租户成员关系"是另一个限界上下文(tenant-center)的核心,不是当前实体的字段。这种判断,靠"模型更聪明"是解决不了的——你给它 GPT-5、Claude 4.5、Qwen3-Max,它依然不知道你项目里"租户成员关系"该归谁。
第二个失控:AI 跳过测试直接交付。
你给它一个"加个新接口"的任务,它吭哧吭哧写完 controller、service、repository、dto,整整齐齐一坨。你打开 PR 一看——测试是空的。
你问它"测试呢",它说"我跑了现有测试都通过,没破坏既有功能"。你再问"新接口的测试呢",它说"这个比较简单,我就没专门写"。
简单还是不简单,不是它能判断的。是人定的——覆盖率门槛、P0/P1/P2 分级、Given-When-Then 结构,是人写进项目规矩里的。它没看到这些,所以它按它"觉得合理"的尺度交付。
更糟的是,它跳过测试不是偷懒,是它没有验收意识。它不知道"测试是 AI 干完活自己查'有没有干对'的护栏"——这件事必须由人把它焊死在规矩里。
第三个失控:AI 把文档当摆设。
你跟它说"顺便把文档更新一下"。它给你更新了一版,看着挺像样——把 readme.md 里的 API 列表补全了,把 AGENTS.md 里的检查项顺手扩了几条。
可你打开 readme.md 对照代码一看:readme 里写"控制器必须显式声明 @RequestMapping",但它刚写的 UserController 偏偏没声明。你打开 AGENTS.md 对照一下:上面写着"DomainEvent 子类必须 @NoArgsConstructor + 字段非 final",但它刚写的 UserDeletedEvent 给字段加了 final 修饰。
你问它"为什么不遵守文档",它说"我看了文档,但这个改动是临时的,等会儿就改回来"——它把文档当成"目标描述",不是"硬约束"。
这三件事表面上看是 AI 的三个毛病,根子上是同一件事——你给它的秩序太软。秩序没有边界感,AI 就凭印象;秩序没有验收门槛,AI 就跳过测试;秩序没有硬约束力,AI 就当摆设。
接下来三节我们就把 DDD、TDD、SDD 三件乐器一件一件拿出来,看它们怎么把秩序从"软"补到"硬"。
三、DDD:业务边界 = AI 边界——AI 没有业务直觉,只有"按规矩干"
先把 DDD 这件乐器摆到桌上。
你可能会说:"DDD 我熟啊,限界上下文、聚合根、值对象、领域事件、通用语言……这套我十年前就看过。" 是的,你看得很熟。但 AI 不熟。
AI 没有业务直觉。
你看到"租户成员关系"四个字,脑子里立刻会跳出"这是 tenant-center 的领域,不是 user-center 的字段;如果 user-center 要查租户成员,应该走事件同步或 Feign,不能直接连表"——这一整套判断是多年业务建模经验堆出来的。
AI 没有这堆经验。它看到的是字符、命名、文件位置、上下文里出现的提示。它能写出语法正确的代码,但它写不出"业务上的对"。
所以 DDD 在 AI 时代的价值,不是教你写更漂亮的领域代码,是给 AI 一张它能照着走的"业务地图"。
这张地图怎么画?关键是三个东西——限界上下文、聚合根、值对象。
限界上下文(Bounded Context)——业务语言的边界。在 auth-center、user-center、tenant-center 这三个仓里,每个仓都有自己的"业务语言"。auth-center 说 accessToken、refreshToken、authCode;user-center 说 user、account、accessKey、tenantRole;tenant-center 说 tenant、tenantUser、tenantRole。
AI 在 auth-center 里看到的是认证这一套语言,在 user-center 里看到的是用户这一套语言。如果你不切限界上下文,它会把 auth-center 里的"用户"和 user-center 里的"用户"当成一个东西——然后给你写出一个跨上下文的 UserAuthService,把认证逻辑塞进用户表里。
焊在规矩里就是一句话:业务边界 = AI 边界。AI 在哪个限界上下文里干活,它就只能说那个上下文的语言;出了边界,停下来问人。
聚合根——一致性的边界。在认证这个领域里,核心的东西就三样:访问令牌(AccessToken)、授权码(AuthCode)、访问密钥(AccessSecret);在用户这个领域里,核心的东西有用户(User)、账号(Account)、访问密钥(AccessKey)、角色(Role)、租户成员关系(TenantUser);在租户这个领域里,核心的是租户本身(Tenant)和租户里的成员(TenantUser)。这些"领域里最关键的那几个东西"就是聚合根——AI 改任何一个聚合根时,只能在这个聚合根内部改,不能顺手把别的东西也改了。
AI 改 AccessToken.create(),它只能在这个聚合根内部改,不能顺手把 AuthCode 也改了——那是另一个聚合根的一致性问题。让它守住这个边界,靠的是分层依赖:domain 层只能依赖 common 层,绝不能跨到 infrastructure、interfaces、Spring 框架。
值对象(Value Object)——身份的边界。TenantId 是值对象,UserId 是值对象。AI 改一个值对象的定义时,必须同时改所有用它的地方,而不是悄悄换一种等价类型。
这套边界不是抽象的——有一支开源团队(ArchAIHarness)把 DDD 的"分层依赖"做成了一份现成的代码骨架,叫 framework。它把每个工程切成六块,每块职责焊死、依赖方向单向。这份骨架最大的价值不是它本身,是它给 AI 立了一份看得见、读得懂、能遵守的秩序。
common(零框架) → domain(领域) → application(用例编排)
→ infrastructure(仓储 / Feign / Kafka) → interfaces(Controller / 切面) → bootstrap(启动)
依赖方向只有一条线:bootstrap → interfaces → application → domain → common(或者 infrastructure → domain → common)。逆着走 = P0 红线,PR 直接阻塞。
这套分层焊死了,AI 才能守住。没有这套分层,AI 写代码就是凭印象;有了这套分层,AI 写代码就是按规矩干。
下面这层我想强调一下,因为你可能有个误会——
限界上下文是 DDD 的"业务边界",不是"部署边界"。三个限界上下文可以部署在三个独立进程里,也可以部署在同一个进程里——怎么部署是工程选择,限界上下文是建模选择。这两件事别混。
讲到这里你大概有感觉了:DDD 切出的边界,就是 AI 干活的边界。AI 在边界内才有"业务直觉"(其实是按规矩干得出来的样子),出边界它就是瞎子。
那 AI 在边界内干得好不好,谁来审?下一节 TDD 上场。
四、TDD:测试 = 体系审计——覆盖率不是装饰,是 AI 干完活的护栏
把 TDD 摆上桌面之前,先把一个常见误会破了——
TDD 在 AI 时代不是"开发流程",是"体系审计"。
什么意思?传统 TDD 是"红→绿→重构"的开发节奏——先写测试看它红,再写实现让它绿,再回头重构。AI 时代这个节奏还在,但它的价值升级了:测试不是"开发过程的副产品",是AI 干完活自己查"有没有干对"的护栏。
AI 写了一坨代码,它自己不知道写对了没有。它可以跑一下编译,能过;它可以跑一下现有测试,也能过;但这不证明新代码是对的——只是证明它没破坏旧代码。
测试覆盖率门槛干的就是这件事:给 AI 一个它必须达到的硬指标。比如 framework 仓的规矩就是"领域层单元测试覆盖率 ≥ 90%"——这不是装饰,是 AI 接 PR 时的阻塞线。覆盖率不达标,PR 阻塞,必须补测试。
我看到一份真实现场的工程妥协——这套骨架的文档写"领域层测试覆盖率必须 ≥ 90%",但配置里实际只卡到 70%。文档和代码打架,是工程师对现实的让步。但底线是:数字必须存在。哪怕 70% 卡在那里,AI 也不敢全跳过测试。你把它调到 90% 还是 80%,那是工程选择,不是"有没有规矩"的选择。
除了覆盖率门槛,测试本身的结构也是规矩的一部分——Given-When-Then。
@Test
void shouldThrowDomainExceptionWhenUsernameTaken() {
// given
when(userDomainService.isUsernameUnique("zhangsan", null)).thenReturn(false);
// when & then
assertThatThrownBy(() -> userAppService.createUser(command))
.isInstanceOf(DomainException.class)
.hasFieldOrPropertyWithValue("code", "USERNAME_TAKEN");
}
这不是什么花架子,是 AI 写测试时结构上不能省的三个块——前置条件、动作、断言。命名也讲究:shouldXxxWhenYyy,一眼就知道在测什么行为、在什么条件下。
第三个规矩是P0/P1/P2 分级阻塞。
- P0:违反核心规范、影响架构正确性的——必须立即修复、禁止合并。比如 domain 层引入了 Spring 框架。
- P1:违反一般规范、影响代码质量的——必须修复、禁止合并。比如没清理 ThreadLocal、Feign 调用没降级。
- P2:不符合最佳实践、不影响功能的——建议修复、可合并。比如 unused import、命名不规范。
AI 写完一段代码,提交前自动跑一遍 P0/P1/P2 检查。P0 命中 = 阻塞,必须改;P1 命中 = 阻塞,必须改;P2 命中 = 警告,可以合并。
这套机制不是空想,有一份真实的审查报告做证据——AI 给一份骨架做了一次自动审查,结果是 3 个轻微建议、零严重问题、零警告。AI 不是不能审代码,它能审——但它只能审"已经写进规矩里的东西"。
所以 TDD 在 AI 时代的真正含义是:
测试不是 AI 的负担,测试是 AI 的护栏。
测试覆盖率是门、Given-When-Then 是台阶、P0/P1/P2 是红灯。你把这套护栏立好了,AI 不会跳过去;你没立,AI 当然不会自己装。
但你光有测试还不够——边界怎么画、规矩怎么写、AI 怎么知道这些规矩?下一节 SDD 上场。
五、SDD:规范 = 人机协作协议——同一套秩序,两种表达
SDD 在这一篇里不是三个字母的缩写游戏——它是 AI 时代工程文档体系的根本变化。
过去的规范是写给人看的。readme.md 写得图文并茂,新人照着 onboarding;架构图用 Mermaid 画得漂漂亮亮,技术评审时拿出来论证;命名规范、检查清单、避坑指南,全按人的阅读节奏排。
AI 时代这套文档体系裂变成了两层:
readme.md——给人看。架构说明、快速开始、代码示例、避坑指南、Mermaid 流程图。AGENTS.md——给 AI 看。结构化检查清单、P0/P1/P2 优先级、可机器解析。
同一套秩序,两种表达。
这件事为什么重要?因为 readme.md 写得再漂亮,AI 也读不出 P0/P1/P2 的优先级;AGENTS.md 里写着"P0 命中阻塞",AI 才能在 PR 阶段自动拦截。
这两个文件不是替代关系,是互补关系——readme.md 解释"为什么这么定",AGENTS.md 规定"必须怎么守"。前者是哲学,后者是法律。
具体到工程落地,AGENTS.md 的硬规范至少要包括这几条:
P0 红线——比如认证中心有一条特别有意思的线:单点登录的 Cookie 必须用浏览器的 JavaScript 写,不能用服务端的 Java 接口写。乍一听这不是技术偏好?其实是前几年团队踩过一个 Tomcat 的坑:服务端 Java 接口写带前导点的跨子域 Cookie,会被 Tomcat 的新版协议处理器拒绝,最后用户登录不上。这条线现在焊死在 AGENTS.md 里——用错 = 立刻阻塞 PR。
依赖方向——比如 domain 层不能 import 任何 Spring 框架。这是 framework 六模块分层的硬约束,逆着走 = P0 命中。
Header 命名——比如 x-user-id 全小写,不能 X-User-Id。这是 auth-center / user-center / tenant-center / gateway 四仓横向交叉遵守的共享规范,任何上下文私自扩展 = P0 命中。
覆盖率门槛——比如领域层 ≥ 90%。不达标 = P0 命中。
Controller 路由——比如所有 Controller 必须显式 @RequestMapping。漏掉 = P0 命中(这条 tenant-center 守得很死,user-center 还没全跟上,是同体系不同仓执行力度有差异的真实证据)。
这些规范有个共同特点——AI 不能自主决策。它不能因为"觉得 X-User-Id 看起来更标准"就把 x-user-id 改了;它不能因为"觉得现在写个 Cookie 用 Servlet API 更顺手"就把 JS 写入的规矩绕了。
这些是硬规范。硬规范焊死在 AGENTS.md 里,AI 只能遵守,不能改写。
但光有硬规范,秩序就够了吗?AI 在硬规范内,是不是就必须按某个固定模板照抄?不一定。
下面这节是这一篇的关键——初版规划里我漏掉了的洞察:秩序里有留白。
六、留白设计:秩序不是锁死 AI,是给 AI 画好赛道——边界焊死、选择放开
上一节我们把 SDD 的硬规范焊死了——P0 红线、依赖方向、Header 命名、覆盖率门槛,AI 一条都不能动。
但你想想,光有硬规范,AI 在规矩里能"自由"吗?
我先问你一个问题:你给一个新人一份写满硬规范的工作手册,他会怎么干活?
十有八九是——抄手册。手册写什么他干什么,手册没写的他不敢动。
AI 也是这样。如果 AGENTS.md 里把每件事怎么实现都写死了,AI 写出来的代码就是 100% 的模板——千篇一律、毫无章法、连错都错得一模一样。
更糟的是——你不给空间,AI 只能抄模板。它不知道这个项目 AuthService 该用 Redis 还是 Caffeine 缓存,不知道这个团队偏好用 MapStruct 还是手写 DTO 转换。这些"实现细节"在硬规范里没写,AI 就随便挑一个——挑错了你难受,挑对了也没觉得它聪明。
反过来——你给空间太大,AI 就会失控。你不规定 x-user-id 全小写,它下次给你写个 X-User-Id;你不规定 Controller 必须 @RequestMapping,它就跳着写;你不规定 P0 红线,它每条都敢越。
那中间的"刚刚好"在哪?
答案是:边界焊死、选择放开。
焊死的是"AI 不能越的界"——分层、Header、P0 红线、覆盖率。这些是秩序的骨架,不许动。
放开的是"AI 怎么实现"——SPI 接口的实现选型、技术栈的具体选型、可选依赖的引入。秩序划到边界就停,边界内随便跑。
我给你看一组真实例子就懂了。
gateway 仓的 6 个 SPI 接口——每个接口职责都焊死了:
- 提 token(
TokenExtractor); - 校验 token(
TokenIntrospector); - 缓存校验结果(
AuthenticationCache); - 校验租户权限(
TenantAccessValidator); - 透传 Header(
HeaderEnricher); - 续期 token(
TokenRenewer)。
但每个 SPI 的实现是松的——默认有 DefaultTokenExtractor、InMemoryAuthenticationCache、MultiTenantAccessValidator,你嫌默认实现不行?一个 @Bean 就能换:
@Bean
TokenIntrospector myTokenIntrospector() {
return bearerToken -> Mono.just(...); // 比如本地 JWT 验签
}
@Bean
AuthenticationCache redisAuthCache(RedisTemplate<...> redis) {
return new RedisAuthenticationCache(redis); // 集群级共享缓存
}
为什么能这么换?因为 GatewayAutoConfiguration 里的 8 个 @Bean 全部标了 @ConditionalOnMissingBean——你提供一个,框架就不提供默认的。
这就是软秩序——边界焊死(接口签名不能改)、选择放开(实现想怎么换怎么换)。
我再给你一组对比——
framework仓告诉你不能做什么:domain 层不能 import Spring、覆盖率不能低于 90%、Header 不能用X-User-Id、Controller 不能漏@RequestMapping。全是 P0 红线。gateway仓告诉你可以怎么做:token 校验可以本地 JWT、可以远程 introspect、可以走 Redis 缓存、可以走本地缓存;缓存可以 LRU、可以 FIFO、可以 Caffeine、可以 Redis。技术栈你说了算。
framework 告诉你不能做什么,gateway 告诉你可以怎么做。
两层合起来,才是 AI 时代完整的秩序。
秩序不是锁死 AI 的手,是给 AI 画好赛道——边界内随便跑,边界外一步都越不了。
这个洞察你得记牢——它是这一篇的"关键密钥",也是 28 篇要在 gateway + auth + user + tenant 真实链路上验证的核心命题。
到这里,三件乐器都摆上桌面了。DDD 划边界、TDD 做审计、SDD 立规矩——但 SDD 又分两层:硬规范(不能越界)+ 软秩序(实现可换)。两层合起来才是完整的"AI 时代秩序乐器"。
下面我把这一篇收个尾,然后把下一篇带进去。
七、写在最后——秩序不是 AI 的负担,是 AI 的翅膀
让我们回到开头那个反直觉的判断——AI 编码能力越强,秩序越贵。
你可能还在想:以前没这么麻烦啊。规则是给"不靠谱的工程师"准备的,AI 应该比人更靠谱才对吧?
这是把 AI 当人看了。AI 不是"更靠谱的工程师",AI 是另一种执行者——它没有业务直觉,但它的执行力、放量速度、模仿能力都远超人类。你不给它规矩,它不会"自己学会"——它会用最快的速度放大项目里所有不规范。
所以 DDD、TDD、SDD 这三件乐器在 AI 时代的角色,不是给 AI 立更多规矩,是给 AI 立"刚刚好"的规矩。
"刚刚好"是什么?
- DDD:业务边界 = AI 边界。AI 在哪个限界上下文,就说哪个上下文的话;出边界,停下来问人。
- TDD:测试 = 体系审计。覆盖率门槛 + Given-When-Then + P0/P1/P2 分级阻塞,AI 干完活自己查"有没有干对"。
- SDD:规范 = 人机协作协议。readme 给人看,AGENTS.md 给 AI 看——同一套秩序两种表达。
- 秩序里有留白:边界焊死、选择放开。硬规范不许越,软秩序可以换。
四件事合起来,给 AI 画一条赛道——边界内随便跑,边界外一步都越不了。
这件事往深了想,它其实是一个关于"作曲家与乐团"的隐喻。
架构师不是 AI 的甲方,架构师是 AI 的作曲家——你写乐谱,它演奏。
- DDD 划旋律线——告诉 AI 这首曲子在哪个调上、有什么主题。
- TDD 把每个音钉在调上——告诉 AI 每个音对不对、稳不稳。
- SDD 是乐谱本身——音符是硬规范,表情记号是软秩序。
AI 不是不需要规矩,AI 是更需要规矩;秩序不是锁死 AI 的手,是给 AI 画好赛道。
未来真正会用 AI 的工程师,不一定是写代码最快的那一批,而是把秩序立得最清楚的那一批。
光说不练假把式。下一篇,我们到 gateway + auth + user + tenant 这套正在跑着的多租户 SaaS 工厂里去看一份完整的乐谱长什么样——它怎么把"边界焊死、选择放开"落到认证链路的每一步上,AI 在这份乐谱里是怎么不越界地自主开发的。
关于 ArchAIHarness
这篇文章是「看懂 AI 与智能体」专栏的一部分,由 ArchAIHarness 持续输出。
ArchAIHarness 是一套面向 AI 时代软件工程的人机协同架构哲学与公开工程资产,主张:
架构师定义秩序,AI 在秩序中生长。人立法,AI 执行,体系审计。
如果你也希望 AI 在明确的架构边界内协作,而不是在混沌中碰运气,欢迎到 GitHub 上看看我们在做什么:
- 组织主页:github.com/ArchAIHarne… — 了解完整理念与资产全景
- 本专栏:
zhuanlan-ai-and-agents— 所有文章的源码与发布记录 - 实践指南:
docs— 架构哲学、工程方法和落地指南 - 开源工具:
agent-workflows— 可复用的 AI 协作 Agents、Skills 与 Tools - 工程样例:
framework— DDD + AI 协作的工程底座,展示如何在开发中融合 AI
Engineered by Architects · Empowered by AI · Audited by Discipline