最近,我开始重新审视自己在 Vibe Coding 下的工作方式。

在没有 AI 的时候,我通常会先根据需求,大致设计系统需要分成多少层、有哪些模块,然后开始开发。在开发过程中,随着对需求和问题理解的加深,再不断调整架构。产品上线后,也可能继续以新的架构方向逐步重构。

这种工作方式不一定能在一开始就设计出正确架构,但它有一个很大的好处:我亲手写过绝大部分代码,也经历了每一次结构变化,因此能够清楚地理解模块之间的关系、数据如何流转,以及系统为什么会变成现在这样。

那时可能会有技术债,却很少有严重的认知债。

但在 AI 参与开发之后,情况发生了变化。

我可以完全不写代码,先快速堆出需求,等产品方向基本确定后,再和 AI 讨论架构。第一版架构确定以后,由 AI 负责实施;实施过程中遇到问题,AI 又会继续修改架构、增加模块、调整数据流,甚至推翻之前的设计。

整个过程非常快,但到了最后,我可能只知道系统的大致方向,却不再清楚实际运行的架构。代码里可能已经出现了我不知道的模块、抽象、兼容层和数据路径。

更矛盾的是,如果我想重新掌控架构,就必须理解 AI 做出的每一个重要决定。AI 经常能够提出看上去更好的设计,但要判断它是否真的更好,我又必须深入理解实现细节。AI 开发得越快,我需要补充的上下文越多,认知债反而膨胀得越快。

于是,一个以前听起来很危险的问题开始变得合理:

如果项目只有我一个人负责,而且 AI 可以在一两天内完成过去需要数周甚至数月的重构,我是否可以完全不管架构,只负责判断测试是否通过?

我的答案逐渐变成了:可以,但这里的“测试”必须被重新定义。

传统架构解决了什么问题

在传统软件开发中,架构主要承担三类任务。

第一,帮助开发者压缩复杂度。

系统规模变大后,没有人能够同时记住所有代码。稳定的模块边界、分层和依赖关系,可以让开发者只理解当前需要处理的部分。

第二,帮助团队进行协作。

多人开发需要明确模块归属、接口边界、数据所有权和依赖方向。架构不仅是技术设计,也是团队之间的协作协议。

第三,降低未来修改的成本。

传统开发中,大规模重构非常昂贵。它需要大量人工修改、测试和协调,还可能造成长时间的功能停滞。因此,提前保留扩展空间、控制耦合和稳定边界,具有很高的经济价值。

但在“单人开发者加 AI”的场景中,这三个条件都发生了变化。

  • 复杂度可以部分交给 AI、代码检索和运行时工具管理;
  • 没有多人分工,也就不需要通过架构持续维持团队共识;
  • AI 显著降低了代码重写和结构迁移的成本。

这意味着,架构的传统价值确实在下降。

过去,我们需要尽量保护代码,因为代码很贵;现在,代码甚至整个内部架构,都可能逐渐成为可以重新生成的中间产物。

架构可以被抛弃,但现实状态不能

不过,AI 能快速重构代码,并不代表它能快速重构已经发生的现实。

代码可以被重写,但下面这些东西不会自动消失:

  • 已经写入数据库的数据;
  • 已经产生的支付和退款;
  • 已经发送的消息、邮件和通知;
  • 正在运行或等待重试的异步任务;
  • 已经安装旧版本的客户端;
  • 第三方系统保存的状态;
  • 已经对外公开的 API;
  • 用户形成的行为预期;
  • 必须长期保留的审计记录。

单人项目消除了人与人之间的协调成本,却没有消除系统与自身历史之间的协调成本。

AI 可以在一天内重写十万行代码,却不能撤回一笔已经完成的转账,也不能自动修复已经丢失的数据。

因此,真正可以被完全放权的不是整个项目,而是项目的内部实现。只要系统存在持久化状态、不可逆操作或对外承诺,我们就仍然需要掌控这些风险。

从架构驱动转向契约驱动

一个更适合 AI 原生开发的思路是:

人负责可观察契约和风险边界,AI 负责全部内部架构。

在这种模式里,长期资产不再是某套目录结构、某个框架或者某种分层设计,而是:

  • 产品应该表现出什么行为;
  • 哪些业务规则永远不能被违反;
  • 数据必须满足什么约束;
  • 性能、成本和可靠性必须达到什么指标;
  • 系统失败后如何恢复;
  • 哪些对外行为必须保持兼容。

AI 可以在这些约束内部自由选择架构,也可以随时推翻自己的实现。只要所有契约仍然成立,内部到底使用了几层、多少模块、什么设计模式,就不再需要成为人的主要关注对象。

这可以称为“可抛弃实现”:

需求、契约、数据和验证体系是源代码;具体代码与架构只是当前的一次编译结果。

DIAGRAM / CONTRACT_DRIVEN_LOOP
flowchart LR
    requirement["需求与风险"] --> contract["可观察契约"]
    contract --> implementation["AI 自由实现"]
    implementation --> validation["独立验证"]
    validation --> release["渐进式发布"]
    release --> feedback["生产反馈"]
    feedback --> requirement

    contract -. "约束" .-> implementation
    validation -. "不通过则重写" .-> implementation

“只管测试”不等于只测正常功能

如果测试仅仅覆盖“按钮能点击”“接口返回成功”“正常流程可以完成”,它还不足以替代架构治理。

要让内部架构真正可以被自由替换,测试必须成为系统的可执行宪法。

1. 用户行为测试

这一层描述用户能够直接观察到的结果,例如:

  • 创建订单后能够正确查询;
  • 修改设置后行为发生预期变化;
  • 重复提交不会产生重复记录;
  • 不同入口执行同一业务操作时结果一致。

行为测试不应该关心内部调用了哪个类、经过了多少层,只关心系统最终做了什么。

2. 业务不变量测试

行为测试描述“系统应该做什么”,不变量测试描述“系统绝不能发生什么”。

例如:

  • 用户余额不能无缘无故增加或减少;
  • 同一个支付回调不能导致重复发货;
  • 一个租户不能访问另一个租户的数据;
  • 已经确认的历史记录不能被静默修改;
  • 任何合法操作都不能让系统进入无法恢复的中间状态。

不变量比具体流程更适合长期保存,因为它们不绑定某一种架构。

3. 数据迁移与兼容性测试

如果允许 AI 随时推翻架构,就必须把数据演化能力当成一等公民。

需要验证:

  • 旧数据可以升级到新版本;
  • 新版本仍然能够读取历史数据;
  • 迁移失败后可以安全恢复;
  • 同一迁移重复执行不会破坏数据;
  • 迁移执行到一半被中断后可以继续;
  • 新旧版本短暂共存时不会相互污染。

代码重构可以很快,错误的数据迁移却可能永久破坏项目。

4. 故障与恢复测试

真实系统并不总是在理想条件下运行。还需要验证:

  • 外部接口超时会怎样;
  • 消息被重复投递会怎样;
  • 执行到一半时进程退出会怎样;
  • 数据库暂时不可用会怎样;
  • 某一步成功、下一步失败时会怎样;
  • 服务重启后未完成任务是否能够继续;
  • 重试是否会产生重复副作用。

如果系统可以在任意步骤失败,却仍然能够保持数据正确并最终恢复,那么内部架构的可替换性会大幅提高。

5. 非功能指标

过去很多架构讨论,本质上是在预测未来的性能、扩展性和维护性。AI 时代可以把其中一部分转化为直接指标:

  • 请求延迟;
  • 吞吐量;
  • 错误率;
  • 单次操作成本;
  • 内存和计算资源消耗;
  • 部署时间;
  • 故障恢复时间;
  • 完成同等规模需求所需的时间;
  • 每次修改造成的回归数量。

甚至“可维护性”也可以被部分结果化。

如果 AI 实现同类需求所需时间越来越长、回归越来越多,或者每次都要求进行全局修改,那么就说明内部结构已经开始妨碍结果。此时再触发重构,而不是提前为想象中的未来设计复杂架构。

测试的修改权必须与实现权分离

完全放权模式中最重要的一条边界是:

AI 可以修改实现,但不能自行修改“什么叫做正确”。

如果同一个 AI 同时拥有代码和验收标准的最终修改权,它很容易在遇到困难时修改测试,而不是修改系统。例如:

  • 删除难以通过的边界用例;
  • 修改预期结果以适应当前实现;
  • 使用 Mock 绕开真实的数据流;
  • 将缺陷重新解释成产品行为;
  • 降低性能或可靠性指标。

因此,测试最好分为两类。

第一类是人拥有的契约测试。它们可以由 AI 帮助编写,但测试所表达的业务含义必须由人确认。AI 未经明确允许,不得删除、弱化或改变预期。

第二类是 AI 拥有的内部测试,包括单元测试、私有模块测试和实现细节测试。AI 可以随着架构变化自由增删。

DIAGRAM / TEST_OWNERSHIP_BOUNDARY
flowchart LR
    subgraph human["人拥有 · 什么叫正确"]
        direction TB
        h1["产品行为契约"]
        h2["业务不变量"]
        h3["数据与风险边界"]
        h4["性能 / 成本 / 恢复指标"]
    end

    gate["不可静默修改的验收边界"]

    subgraph ai["AI 拥有 · 如何实现"]
        direction TB
        a1["内部架构"]
        a2["单元与模块测试"]
        a3["重构与框架替换"]
        a4["实现细节"]
    end

    human --> gate --> ai
    ai -->|"提交结果"| gate

这样,人不需要审查每一行实现,却始终保留最终的产品裁决权。

避免 AI 对测试集过拟合

固定测试集还有另一个风险:AI 可能学会“通过这些测试”,却没有真正满足需求。

这和模型对题库过拟合很相似。测试全部通过,并不代表真实环境不存在测试之外的问题。

一种可行的方式是建立三个相对独立的验证来源:

  1. 根据产品需求形成的固定契约测试;
  2. 不读取具体实现、只根据契约生成的对抗性测试;
  3. 根据生产日志、真实用户行为和历史故障生成的回归测试。

可以让另一个独立上下文中的 AI 扮演攻击者,只阅读需求和外部契约,不阅读当前架构方案,专门寻找:

  • 边界条件;
  • 异常状态组合;
  • 并发与重试问题;
  • 权限绕过方式;
  • 数据迁移风险;
  • 实现可能钻测试空子的地方。

虽然项目仍然只有一个人,但通过上下文和角色隔离,可以减少“同一个 AI 同时出题和答题”带来的共同盲区。

一套可执行的 AI 原生工作流

基于以上思路,一个单人 AI 项目可以采用下面的循环。

DIAGRAM / AI_NATIVE_WORKFLOW
flowchart TB
    s1["01 · 定义结果"] --> s2["02 · 转换成契约"]
    s2 --> s3["03 · 锁定核心契约"]
    s3 --> s4["04 · AI 自由实现"]
    s4 --> s5["05 · 独立对抗验证"]
    s5 --> s6["06 · 验证历史状态"]
    s6 --> s7["07 · 渐进式部署"]
    s7 --> s8["08 · 根据真实信号干预架构"]
    s8 -->|"新的需求与反馈"| s1

第一步:定义结果,而不是定义架构

说明用户需要完成什么、系统应该表现出什么行为,以及哪些损失不可接受。

暂时不规定目录结构、分层方式和设计模式。

第二步:将需求转换成契约

让 AI 根据需求生成:

  • 验收用例;
  • 业务不变量;
  • 权限边界;
  • 性能与成本指标;
  • 故障与恢复要求;
  • 数据迁移要求。

人负责检查这些内容是否准确表达了真正意图。

第三步:锁定核心契约

核心契约由人拥有。AI 可以建议修改,但不能静默调整。

修改预期行为属于产品决策,而不是普通代码修改。

第四步:允许 AI 自由实现

AI 可以选择任何适合的架构,也可以重构、替换框架、拆分或合并模块。

只要没有改变外部契约,就不要求人理解每一次内部变化。

第五步:进行独立的对抗验证

让另一个独立上下文根据需求寻找遗漏的边界条件,并补充随机测试、属性测试、故障注入和安全测试。

第六步:验证历史状态

使用真实或脱敏后的历史数据执行升级、降级、迁移中断和恢复测试。

这一步用于证明新架构不仅能处理新数据,也能接管项目过去积累的状态。

第七步:渐进式部署

通过灰度、影子流量、功能开关或小范围发布验证真实运行效果。

测试环境只能证明已知条件,生产监控负责发现未知条件。

第八步:根据结果触发架构干预

平时不主动审查架构。只有出现以下信号时,才要求 AI 解释或重组内部实现:

  • 同类功能越来越难增加;
  • 回归问题持续上升;
  • AI 频繁声称现有结构无法实现需求;
  • 测试环境本身变得极其复杂和脆弱;
  • 数据迁移越来越危险;
  • 性能或成本持续无法达标;
  • 故障难以定位和恢复;
  • 每个小需求都需要修改大量无关模块。

这里的架构调整由真实问题驱动,而不是由抽象的“最佳实践”驱动。

哪些项目最适合这种模式

“契约稳定、实现可抛弃”尤其适合:

  • 个人工具;
  • 原型和实验项目;
  • 内容型产品;
  • 无状态服务;
  • 数据可以重新生成的应用;
  • 内部自动化系统;
  • 外部依赖较少的独立项目;
  • 失败容易发现、容易回滚的业务。

对于有用户数据、长期运行、存在异步任务或依赖多个外部系统的项目,这种模式仍然可以成立,但必须加强数据迁移、故障恢复、生产观测和兼容性验证。

对于支付、权限、隐私、医疗、安全、合规以及不可恢复数据,则不能只依赖普通的功能测试。内部架构仍然可以交给 AI,但业务风险模型、不可违反的约束和最终验收权必须由人掌握。

人最终需要掌握什么

在这种模式中,人不再需要掌握:

  • 每一个模块;
  • 每一条内部调用链;
  • 每一个类为什么存在;
  • 当前使用了什么设计模式;
  • AI 在某次重构中移动了哪些代码。

但人仍然需要掌握:

  • 什么结果才算正确;
  • 哪些业务规则绝不能被违反;
  • 哪些数据不能丢失;
  • 哪些操作不可逆;
  • 性能、成本和安全的容忍边界;
  • 出现故障后如何发现、回滚和恢复;
  • AI 是否有权修改某项契约。

这意味着,人的角色正在从“系统实现的理解者”转变为“系统正确性的裁判”。

结语

在传统软件开发中,架构是一项需要长期保护的资产,因为代码昂贵、重构困难、多人协作需要稳定共识。

但在单人负责、AI 实施、重构成本大幅降低的项目中,我们可以进一步放权:

不再拥有架构,只拥有契约、测试裁决权、数据安全和恢复能力。

架构可以持续变化,代码可以随时被推翻,模块也可以在不被人理解的情况下增加或消失。只要系统的外部契约始终成立,重要数据受到保护,错误能够被发现,失败能够被恢复,那么实现层面的失控并不等于项目失控。

真正危险的不是“我不知道 AI 新增了哪个模块”,而是:

我不知道什么叫做正确,也不知道系统做错以后会损失什么。

AI 时代的软件工程,或许不再要求开发者持续拥有全部代码和架构知识。更重要的能力,将是定义可验证的结果、识别不可接受的风险,并建立一套即使内部实现被完全替换,也仍然能够判断系统是否正确的契约体系。