AI时代重拾软件工程基础:测试、审查与重构

📅 2026/8/27 4:52:17
AI时代重拾软件工程基础:测试、审查与重构
先从一个问题开始如果你已经用过 Cursor、Copilot、通义灵码、Codex 这类 AI 编程工具大概率会有同样的感受——代码生成速度确实快但“生成得快”和“质量能用”是两回事。AI 能在几秒内铺出几百行代码也能在几秒内给你塞进一个没见过的 API、一个越权漏洞、一段没人看得懂的嵌套逻辑。Uncle BobRobert C. Martin近期围绕“AI 时代软件工程基础”做过专题讨论态度很直接AI 不会取消软件工程反而会把软件工程的基础能力变成更稀缺、更值钱的东西。这篇文章不聊“AI 会不会取代程序员”这类情绪化话题而是把 Uncle Bob 在这次讨论中强调的观点拆开落到我们日常写代码、审代码、跑测试的真实场景里。你会看到为什么 AI 时代反而要重新重视测试、设计、重构和代码整洁怎么用“先测试、后实现”的流程约束 AI 生成的代码以及团队在引入 AI 编程工具时应该补哪些工程治理动作。如果你正在用 AI 辅助写业务代码、做项目脚手架或者你是带团队的技术负责人这篇文章建议直接收藏。文章没有平台绑定、没有私有配置所有思路都可以在现有开发流程里逐步落地。1. Uncle Bob 是谁以及这场讨论的视角Uncle Bob 是 Robert C. Martin 的圈内称呼。他是《代码整洁之道》Clean Code、《架构整洁之道》Clean Architecture的作者也是 SOLID 设计原则的提出者软件工艺运动的代表人物之一。过去几十年他一直在强调专业主义、测试驱动开发TDD、小步提交、持续重构这些基础动作。这次讨论的标题已经点明了矛盾点AI 时代大家都在追新框架、新模型、新提示词技巧Uncle Bob 反而把话题拉回“软件工程基础”。他的视角不是反对 AI 编程而是认为 AI 工具解决的是“代码产出速度”没有解决“软件能否长期维护、是否可靠、是否可验证”的问题。更准确地说AI 让“写代码”这个动作变便宜了但软件工程里真正昂贵的东西没有变确认需求是否正确验证代码行为是否符合预期处理边界条件和异常控制技术债务的增长让代码在几个月后仍能被团队理解。这些恰恰是软件工程基础要解决的问题。AI 生成代码量越大这些问题就越突出。如果基础不牢AI 只是把问题从“写代码慢”转移成“审查量大、返工多、线上故障爆炸”。2. 核心观点速览AI 时代仍需软件工程基础结合这场的讨论方向Uncle Bob 关于“AI 时代软件工程基础”的核心观点可以整理成一张速览表观点维度核心主张落到日常开发的含义专业主义开发者必须对自己交付的代码负责不能拿“AI 生成的”当免责理由合入前必须审查、测试、验证测试纪律自动化测试是验证代码行为的唯一可靠手段没有测试的 AI 代码视为未完成清晰设计代码要容易被人类阅读和修改而不是只追求能运行提示词生成的长函数、大函数必须拆分重构小步迭代小步提交、快速反馈、频繁集成不要让 AI 一次性生成整个模块拥抱变化AI 是工具工程原则不会失效把 AI 当作结对程序员而不是免检代码源这张表其实把 Uncle Bob 过去几十年的主张原封不动地搬到了 AI 场景。它并不新鲜但在 AI 生成代码大量进入仓库的今天这些“老规则”反而成了唯一的防线。这里有个问题值得认真想以前我们写代码每次敲键盘都受到物理速度限制所以代码量是可控的。现在 AI 几分钟就能生成几千行代码仓库的膨胀速度远超人类维护能力。如果团队没有测试基线、没有审查流程、没有重构习惯AI 带来的不是效率而是债务。3. AI 带来的四个真实变化AI 编程工具普及后软件开发过程实际上发生了四个变化。理解这些变化才能明白为什么“基础”比“技巧”更重要。3.1 需求澄清成为瓶颈以前写代码需求不清晰时程序员会因为写代码成本高而反复追问。现在 AI 写代码几乎零成本很多开发者直接拿模糊需求去生成代码出来的结果自然偏得离谱。Uncle Bob 一直强调“软件开发的真正困难是确定什么是想要的以及确认做出来了什么”。AI 时代提示词本身就是需求描述。你写不清提示词AI 当然写不清代码。这意味着需求分析、任务拆分、验收标准定义这些基础能力变成了“提示词工程”的上游。3.2 代码审阅成为最高频动作AI 生成代码之后团队的主要工作从“写”变成“读和判断”。判断代码是否满足需求、是否引入安全风险、是否破坏了既有设计、是否埋了隐藏状态。审阅能力以前是资深开发者的加分项现在是所有使用 AI 工具的开发者的必备项。如果一个团队习惯了“AI 生成 - 直接合入”那就等于把质量决定权交给了模型这是高风险操作。3.3 依赖与供应链风险放大AI 模型很容易根据训练数据中的模式推荐第三方依赖甚至生成不存在的包名。如果团队不做依赖审查轻则编译失败重则引入恶意包。AI 生成代码越猛依赖注入的面就越宽供应链风险也随之变大。3.4 技术债务加速累积AI 生成代码时没有“历史包袱”的概念。它不会因为你现有代码结构去主动适配只会针对当前提示词生成一个局部最优解。多个局部最优解拼在一起往往就是全局的大混乱。所以AI 时代的技术债务不是在减少而是在加速。清理债务的能力——重构、梳理依赖、统一设计风格——决定了团队能不能消化 AI 带来的增量。4. 基本功没有消失只是载体变了很多人误以为“AI 会写代码了所以我不用学设计模式、不用写测试、不用做重构了”。这个判断恰恰反了。拿测试来说。以前写测试是为了防止自己改坏代码。现在写测试除了回归保障还有一个新作用作为 AI 生成结果的验收器。你给 AI 一个需求描述它给你一堆代码怎么判断它写对了最靠谱的方式就是跑测试。测试不只是质量保障它已经变成你和 AI 之间的“合同”。拿设计原则来说。以前自己写代码会不由自主地考虑模块边界。现在 AI 生成代码是面向提示词的它不会想“这个函数放这个类里合不合适”。如果开发者不理解单一职责、不理解依赖方向AI 生成的代码会迅速腐化成一个巨型类网络。再拿代码整洁度来说。AI 生成的分支判断、异常处理经常是叠加式增长一个函数几十行 if-else 嵌套是常态。整洁代码的能力就是把这些内容拆回人类能理解的样子。它没有过时而是变成了 AI 代码合入前的必修课。所以结论是软件工程基础没有消失只是从“编代码的手艺”变成了“判断、约束、修正 AI 结果的能力”。工具越强人的判断力越贵。5. 落地把“先测试”变成 AI 辅助开发的主流程Uncle Bob 是 TDD 的坚定倡导者。在 AI 时代TDD 的价值反而更好理解TDD 天然就是一个把“需求”转化为“可执行验收条件”的流程。传统 TDD 流程是写测试 - 看它失败 - 写实现 - 测试通过 - 重构。AI 辅助开发时只需要把“写实现”这个动作交给 AI剩下的过程完全不变明确一个小的行为目标比如“结算时普通用户满 100 减 20会员一律 9 折不叠加满减”。先用测试框架把这个行为描述成测试用例。把测试用例丢给 AI让它生成能通过测试的最小实现。运行测试根据失败信息要求 AI 修正。测试通过后人工阅读代码检查设计和边界。合入前重构把 AI 生成代码整理成可维护的结构。这个流程的价值在于AI 的“想象力”被测试用例死死框住。它不需要理解业务全貌只需要满足测试描述的行为。而开发者则保留了最重要的验收权和判断权。6. 用测试用例框住 AI 生成的代码下面用一个订单金额计算的例子演示这个流程。假设业务规则是普通用户满 100 减 20会员一律 9 折不与满减叠加金额不能为负数。先写测试文件# tests/test_order.py import pytest from order_service import calc_total def test_normal_user_below_threshold(): assert calc_total(80, is_memberFalse) 80 def test_normal_user_full_reduction(): assert calc_total(120, is_memberFalse) 100 def test_member_discount_no_full_reduction(): assert calc_total(100, is_memberTrue) 90 def test_member_high_amount_no_stack(): assert calc_total(300, is_memberTrue) 270 def test_negative_amount_raises(): with pytest.raises(ValueError): calc_total(-1, is_memberFalse)把这组测试作为提示词材料发给 AI要求它生成实现。AI 给出的可能如下# order_service.py def calc_total(amount: float, is_member: bool False) - float: if amount 0: raise ValueError(amount must be 0) if is_member: return round(amount * 0.9, 2) if amount 100: amount - 20 return round(amount, 2)运行测试pytest tests/test_order.py -v预期结果5 passed in 0.02s这样AI 生成代码是否合格不是由感觉决定而是由测试结果决定。如果 AI 第一次没写对我们可以把失败信息贴回去让它继续改。整个迭代过程可控、可回溯。这个例子虽然简单但它展示了 AI 辅助开发的正确姿势先有验收标准再让 AI 生产代码。业务规则再复杂只要能被拆成可验证的行为都可以用同样的方式约束。7. AI 生成代码的人工审查清单测试通过不代表可以直接合入。AI 代码经常有测试覆盖不到的问题所以人工审查不能省。下面是一份 AI 生成代码审查清单可以直接复制到团队代码评审流程里。审查项关注点风险等级边界条件负数、空值、超大值、零、空字符串是否处理高异常处理异常类型是否准确会不会吞掉真实错误高安全性SQL 拼接、命令执行、文件路径、越权访问高依赖来源是否引入不存在的包、版本是否锁定、许可证是否可商用高隐式副作用函数是否只做声明的事会不会修改外部状态中并发与状态全局变量、共享内存、竞态条件中性能是否存在明显 O(n^2)、N1 查询、循环内调用慢操作中可读性函数长度、命名清晰度、分支嵌套层次中测试覆盖是否为新增逻辑补充了对应测试高与既有架构一致性是否沿用团队既有模式还是另起一套风格中注意这份清单里风险等级为“高”的项必须逐条人工确认不能依赖 AI 自查。AI 生成代码的“自信感”很强即使错了它也会给出完整解释所以审查者需要带着怀疑去看而不是带着确认去看。8. 团队落地建议规范、基线、培训与合规如果你不是个人开发者而是带团队引入 AI 编程工具以下四个动作值得优先做。8.1 建立 AI 代码合入规范团队要明确AI 生成的代码不是免检代码。到达合入门禁前必须满足和人类代码相同的检查要求包括测试通过、评审通过、静态检查通过。可以在 CI 里增加一条规则不附带测试的 AI 生成代码不允许合入主分支。8.2 守住测试基线没有测试基线的团队先不要大规模引入 AI 生成代码。因为 AI 代码一旦进入一个没有保护网的仓库任何一次“看起来对但实际错”的生成结果都可能变成线上事故。测试覆盖率不求一步到位但核心业务链路必须有自动化测试。8.3 培训内容要增加“审查”和“重构”团队引入 AI 工具后培训不应该只教“怎么写提示词”更要教“怎么审查 AI 生成的代码”和“怎么重构 AI 生成的大函数”。从实际经验看提示词能力提升带来的收益很快会触及天花板而审查与重构能力决定团队能消化多少 AI 代码量。8.4 注意合规与授权使用 AI 编程工具时需要关注几点训练数据是否包含受版权保护的代码、生成代码的许可证是否合规、公司代码是否被发送到第三方接口、生成结果能否用于商业项目。这些问题没有统一答案取决于你使用的工具和部署方式。稳妥的做法是敏感项目用私有化部署模型外部工具只处理非敏感任务合入前检查依赖许可证。9. 常见误区与排查AI 辅助开发在落地过程中有几个高频误区单独列出来提醒。误区表现实际情况建议做法让 AI 一次生成整个模块代码量越大错误越难定位审查成本越高拆成小任务逐个验证不加测试就让 AI 写实现没有验收标准AI 经常“编得很像但对不上需求”先写测试再让 AI 实现测试通过就合入测试只能证明部分行为正确覆盖不到设计和安全问题测试之后加上人工审查发现 AI 生成了不存在的依赖模型根据训练模式推测包名可能写错手动确认依赖存在且版本正确AI 反复修改仍不通过测试提示词里缺少约束或需求本身有歧义回到需求澄清更新测试用例生成代码风格和项目不一致模型不了解项目既有风格在提示词中给出项目风格规范或合入前统一格式化排查 AI 生成代码问题时最有效的思路不是“继续追问 AI”而是“回到测试用例”。测试通过但行为不对说明测试写错了测试失败但实现看起来合理说明需求描述和实现理解不一致。两种情况都需要人工介入而不是让模型再猜一轮。10. 总结先做三件事Uncle Bob 这次讨论最值得带走的不是某个具体技巧而是一个判断AI 降低的是“写代码”的成本不是“做软件”的成本。软件工程里的需求、测试、设计、重构、审查每一项都不会因为 AI 消失反而会因为代码生成量暴增而变得更加关键。如果你想知道从哪里开始建议先做三件事。第一为你最常用的一条业务链路补一套自动化测试。这是你判断 AI 生成代码是否正确的最低成本工具。第二把“AI 生成 - 直接合入”改成“AI 生成 - 测试验证 - 人工审查 - 合入”。哪怕流程慢一点也比上线后返工强。第三每周挑一段 AI 生成的代码做一次重构练习。拆长函数、改命名、清理嵌套分支练的是你在 AI 时代最需要的判断力。旧工程基础在 AI 时代没有过时它只是换了一种方式在筛选开发者真正理解需求、掌握测试、懂得设计、愿意对代码负责的人会借助 AI 走得更远把这套基础扔掉的人只会被 AI 生成的代码量淹没。建议收藏备用。下次让 AI 帮你写代码之前先问一句这堆代码的测试在哪