AI时代守住软件工程基础:TDD、代码审查与专业主义

AI时代守住软件工程基础:TDD、代码审查与专业主义 最近看了一场中文字幕版 Live 演讲主题是 Uncle Bob 谈 AI 时代的软件工程基础。主讲人 Robert C. Martin也就是 Uncle Bob是《代码整洁之道》作者也是 TDD、SOLID 原则最重要的布道者之一。这次 Live 的核心观点很直接AI 确实能写代码但软件工程的基础并没有变变化的是生产工具不变的是测试、纪律、设计原则和职业责任。这篇文章不打算做“逐字稿复述”而是把 Uncle Bob 长期坚持的工程观点和 AI 时代的新问题合并起来落到实际开发场景里。比如AI 编程提示词怎么写才不算玄学AI 幻觉怎么用工程手段拦截AI Agent 批量写代码时团队怎么治理AI 测试和 TDD 为什么在生成式编程时代反而更重要这些内容对后端、前端、测试岗位都有直接参考价值读完可以拿一套方法去团队里验证。1. 核心信息速览维度说明主题类型软件工程方法论解读不是开源工具或模型主讲人Robert C. MartinUncle Bob《代码整洁之道》作者核心主题AI 时代软件工程基础TDD、整洁代码、设计原则、专业主义关联热词AI 编程、AI Agent、提示词工程、AI 测试、AI 幻觉、软件工程银弹适合读者后端/前端工程师、测试工程师、技术管理者、AI 工具实践者前置知识有团队协作或写代码经验了解基本开发流程可落地内容AI 编程提示词模板、TDD 约束代码生成、AI 幻觉排查清单、代码审查规范有一点先说明AI 编程工具的门槛可以很低比如浏览器打开聊天窗口就能生成一段代码但要把 AI 生成的代码放进生产环境门槛反而很高。原因是它绕过了传统工程流程中“人写代码、人测试、人审查”的环节而工程基础恰恰是用来兜住这些环节的。2. 为什么 AI 时代还要谈“软件工程基础”很多人觉得 AI 时代“写代码”会变成自然语言对话工程基础似乎不再重要。但 Uncle Bob 这类老派工程师的核心立场恰恰相反工具越强基础越不能丢。2.1 软件工程没有“银弹”《人月神话》作者 Fred Brooks 提出过著名的“没有银弹”观点软件开发中的本质复杂度不会消失只能通过更好的工程方法去应对。AI 编程工具看似是“银弹”但它降低的是“把想法变成代码”的转换成本并没有降低“把需求变成正确系统”的认知成本。举个例子你用 AI 生成一个 Python 函数几秒钟就出来了。但如果需求本身是模糊的AI 只能根据你的提示词“猜”一个实现。猜出来的代码编译可以过、单测可以过不代表它满足业务逻辑。更麻烦的是这种代码一旦被大量合并进仓库后续维护者要理解的是“AI 当时为什么这样写”而不是“人类同事当时为什么这样写”。2.2 AI 提高了产出速度也放大了维护风险人工写代码每小时可能 20 到 50 行AI 生成代码在几分钟内可以产出几百行。产出量变大之后代码审查、测试、架构约束如果跟不上质量风险会成倍上升。解决问题的关键不是限制 AI而是把工程基础做扎实代码可读、可测试、可回滚。这也是 Uncle Bob 反复强调“整洁代码”的原因。整洁代码不是美学偏好而是让系统在长期迭代中仍然能被人理解。AI 生成代码如果命名混乱、函数过长、职责不清短期跑通长期就是技术债。2.3 工程基础的三个不变项可测试性没有测试AI 生成代码就是“看起来对”的代码。可维护性代码不是给机器看的是给下一个工程师以及下一个人工智能看的。可演进性今天 AI 能生成一个模块明天需求变了系统要能被局部修改而不崩塌。所以这篇文章所说的“AI 时代软件工程基础”不是让你去学某个框架而是重新强调那些一直在起作用、但在 AI 生成代码背景下容易被忽略的工程纪律。3. 从状态图和活动图看 AI 在软件工程流程中的位置软件工程课程里经常用 UML 状态图和活动图描述系统行为。这里换一个用法把“软件研发过程”本身当作一个业务流程用活动图视角拆解 AI 到底能切入哪些节点。3.1 软件工程核心活动活动节点传统方式AI 辅助方式AI 风险需求分析产品经理访谈、用户故事用 AI 整理会议纪要、生成初稿需求误解被隐藏系统设计架构师决策、架构评审用 AI 生成方案初稿架构权衡不充分编码实现工程师手写代码AI 生成代码、自动补全幻觉、依赖污染测试编写测试工程师手写用例AI 生成单测用例、测试数据断言错误、覆盖虚高代码审查人工 ReviewAI 辅助审查、静态扫描误报、漏报部署运维人工发布、监控AI 分析日志、生成脚本误操作风险从这张表可以看出AI 并不是“从需求直接跳到发布”的魔法而是在每个节点里作为辅助者进入。工程基础要做的事情是给每个节点设置“检查点”。3.2 AI 最适合切入的环节编码实现最成熟价值最直接。测试生成生成边界用例、重复性用例很有价值。脚本编写CI/CD 脚本、数据处理脚本效率提升明显。文档生成接口文档、README能节省大量时间。代码审查辅助定位疑似问题但最终判断要人来做。3.3 AI 不适合直接负责的环节需求抽象需求来源于业务复杂性和利益权衡AI 没有足够上下文。架构决策涉及长期演进、团队结构、成本权衡AI 无法担责。安全与合规判断数据隐私、权限边界、许可证检查必须有负责人。线上故障处理故障处理需要快速做价值判断AI 只能辅助查日志。把 AI 放在“活动图”的正确节点上工程基础就变成了节点之间的护栏。4. AI 编程提示词从“写代码”到“写规格”很多程序员用 AI 写代码方式是“帮我写一个用户登录接口”然后拿走代码。这种用法不稳定因为提示词缺少上下文和约束。Uncle Bob 那一套“需求规格”思想正好可以用来改进提示词。4.1 高质量提示词的本质是轻量级规格一段好的 AI 编程提示词应该包含角色AI 作为什么角色资深后端工程师。上下文现有项目技术栈、框架、目录结构。任务要实现的接口/函数/页面。约束不允许编造不存在的 API必须使用项目已有依赖。验收标准需要包含单元测试、错误处理、日志。输出格式只输出代码还是给出改动清单。4.2 提示词模板示例这里给一个可以直接改造的模板实际使用时替换方括号内容你是一名资深 Java 后端工程师在维护一个 Spring Boot 3 项目。 项目已经引入依赖spring-boot-starter-web、spring-boot-starter-validation、mybatis-plus。 请实现以下需求 1. 新增接口 POST /api/user/register 2. 入参字段username3-20位字母数字、password6-32位、email邮箱格式 3. 校验逻辑用户名不能重复密码需要加密存储使用 BCrypt 4. 返回结构{ code, message, data } 5. 添加对应的单元测试使用 MockMvc覆盖正常注册、用户名重复、参数校验失败三种场景 约束 - 只能使用项目现有依赖不要新增依赖 - 不要编造不存在的框架 API - 输出完整代码和测试代码不要省略 - 如果某个 API 不确定先说明不要猜测这个模板的核心不是“让 AI 一次写对”而是把需求边界和验收标准写清楚。这样就等于把提示词当成一份简化的需求规格文档来管理。4.3 小步生成而不是一次生成一个巨型模块建议一次只让 AI 完成一个函数、一个接口、一个测试文件而不是“请帮我写一个完整电商系统”。原因长提示词会稀释 AI 的注意力容易出现前后不一致。小步生成方便人工逐段审查。出现问题后可以精准定位是提示词问题还是 AI 问题。提示词要像需求文档一样做版本管理。同一个模块的提示词改进后可以复用到后续类似需求这就是“提示词资产化”。5. AI 幻觉把它当成工程质量问题来治理AI 编程最大的坑不是代码写不好而是“一本正经地编造”。这种 AI 幻觉在代码场景里表现非常具体。5.1 编程场景中的幻觉表现编造 APIAI 生成了框架里根本不存在的类或方法。编造依赖提示词里说要新增一个版本号不存在的依赖。错误逻辑代码看起来合理但业务逻辑和预期不符。虚假注释注释描述的“设计意图”和实际代码行为不一致。伪造数据测试数据看起来真实实际上是编造的导致测试失真。5.2 用工程手段拦截幻觉不要指望“换一个更大模型”或者“加一句不要编造”就能根除幻觉。更可靠的方式是建立防御链编译/语法检查 - 静态分析 - 单元测试 - 代码审查 - 运行验证每一步都能拦截一部分幻觉防御环节能拦截什么幻觉不能拦截什么编译/语法检查API 不存在、类型错误逻辑错误、业务偏差静态分析空指针风险、未使用变量、依赖问题需求理解错误单元测试输入输出不符合预期覆盖不到的边界代码审查设计偏差、命名问题、安全隐患大范围逻辑错误运行验证线上环境行为是否符合预期数据权限等问题仍需专项测试5.3 验证 AI 生成 API 是否真实存在一个实用方法让 AI 给出代码后用语言自带的反射或内省机制验证 API 是否存在。比如 Python 中AI 声称某个库有某个函数可以用这样一段代码验证import inspect import some_library # 替换为 AI 引用的库 func_name some_function if hasattr(some_library, func_name): func getattr(some_library, func_name) print(f函数存在签名{inspect.signature(func)}) else: print(f函数不存在{some_library.__name__}.{func_name})这种方式成本低能快速拦住“编造 API”这一类幻觉。把它写进代码审查清单团队里每个人都能用。6. AI 测试与 TDD先写测试再让 AI 实现Uncle Bob 是 TDD 的长期倡导者。传统 TDD 循环是红写失败测试- 绿写实现- 重构。AI 时代的 TDD 可以变成人写测试 - AI 生成实现 - 运行测试 - 失败则反馈修改。这比“AI 生成代码人再补测试”靠谱得多。6.1 为什么 AI 时代更适合 TDD测试是需求的可执行描述比提示词更精确。测试能给 AI 提供即时反馈信号。测试通过后代码重构有了安全网。测试记录沉淀下来形成回归保护。换句话说TDD 让“AI 生成的代码”从“看起来对”变成“有验证地对”。6.2 实践示例先写测试再让 AI 实现假设要实现一个计算订单折扣的函数。先不写实现而是先写测试文件test_discount.pyimport pytest from discount import calculate_discount def test_normal_order_no_discount(): # 金额小于 1000 不打折 assert calculate_discount(800) 800 def test_order_over_1000_gives_ten_percent(): # 金额大于等于 1000打九折 assert calculate_discount(1000) 900 def test_order_over_5000_gives_twenty_percent(): # 金额大于等于 5000打八折 assert calculate_discount(5000) 4000 def test_invalid_amount_raises_error(): # 负数金额应该抛异常 with pytest.raises(ValueError): calculate_discount(-100) def test_zero_amount(): # 金额为零折扣后还是零 assert calculate_discount(0) 0然后把这个测试文件发送给 AI并附上提示词这是项目里已有的测试文件 test_discount.py。 请实现 discount.py使所有测试通过。 要求 1. 只实现 calculate_discount 函数 2. 不要修改测试文件 3. 使用简单清晰的分支逻辑 4. 不引入任何外部依赖 5. 实现完成后你自己检查是否覆盖了所有测试场景运行测试python -m pytest test_discount.py -v预期输出是所有测试通过。如果某个测试不通过把失败信息回传给 AI让它修正实现。这个循环的本质是人负责定义“正确”AI 负责实现“正确”。6.3 AI 测试的边界提醒测试通过不等于业务正确。可能有测试本身的断言写错了。要关注异常路径、并发场景、安全测试AI 生成的测试往往偏向正常路径。性能测试、压力测试不能完全交给 AI 自动生成必须人工设计场景。测试代码本身也要做代码审查尤其要检查断言后面是否真的执行了被测逻辑。7. AI Agent 与批量任务工程治理比生成能力更重要AI Agent 可以自动完成“读取 Issue - 修改代码 - 跑测试 - 提交 PR”这类闭环任务。听起来很美但把它真正用到团队里会暴露出工程治理问题。7.1 批量任务的真实风险一致性风险Agent 可能在不同文件里采用不同风格和方案。审查淹没一次生成大量 PR人类审查者根本无法逐一认真看。依赖污染Agent 为了“完成任务”顺手新增依赖增加供应链风险。责任真空出了问题是 Agent 的责任还是提交者的责任权限失控Agent 如果被赋予了过大的代码库权限可能修改到不该改的地方。7.2 AI Agent 的工程护栏可以在使用规范里约定以下要求控制项建议要求分支策略所有 AI 生成代码必须走独立分支提交信息必须标注由 AI 生成注明使用的工具和提示词版本PR 大小单个 PR 改动文件数不超过 10 个便于人工审查CI 前置未通过编译、测试、静态检查的代码不允许合入人工审查至少一名工程师 Review线上变更必须有第二人确认权限隔离Agent 使用的令牌只授予指定仓库和指定目录权限回滚方案每次批量变更都要有对应回滚预案7.3 代码审查清单代码审查是 AI 时代的核心防线。建议清单至少包含API 是否真实存在依赖是否已声明错误处理是否覆盖异常会不会吞掉关键信息日志是否包含足够上下文有没有把密钥、连接串写进代码命名是否能表达意图还是“data、data2、data3”有没有不必要的新增依赖单测是否覆盖正常、异常、边界三种情况代码是否与现有架构一致这一条看上去朴素但把 AI 生成代码的出错率拦掉大半。Uncle Bob 说“专业主义意味着你不发布未经测试的代码”AI Agent 时代这句话要改成“你不发布未经人工审查的 AI 生成代码”。8. 在团队中落地 AI 编程环境、权限与合规团队引入 AI 编程不是“发一个账号让大家随便聊”就完了。需要考虑环境、权限、合规边界。8.1 工具选型判断标准判断维度建议关注点数据是否出域公司代码发送到外部 API 前必须评估是否支持本地部署内部代码敏感度高的团队优先考虑本地模型是否支持批量任务能否接入 CI/CD 或批量脚本可审计性是否记录会话、生成内容、使用人模型可替换性是否支持切换不同模型避免绑定权限制衡API Key 是否有最小权限、到期机制这里不推荐具体工具因为不同团队的安全要求差别很大。保守做法是先用辅助模式代码补全、单测生成跑通后再考虑自动 Agent 模式。8.2 合规与安全提醒不要把生产数据库连接信息、用户手机号、身份证号等真实敏感数据放进提示词。AI 生成的代码可能包含开源协议片段商用前要做许可证审查。涉及人脸、声音、版权素材的 AI 功能必须确认授权。生成代码如果来自外部模型服务要评估供应商的隐私政策和数据存储范围。内部研发规范里应明确谁提交代码谁对代码负责。8.3 灰度落地流程建议分三步走试点期选出 3 到 5 名工程师在低风险模块使用 AI 编程记录编译通过率、测试通过率、审查耗时。推广期把提示词模板、测试约束、审查清单沉淀为团队文档再扩大到更多团队。固化期将 AI 生成代码的规范接入 CI例如要求 PR 中标注“AI 生成”并自动触发额外审查任务。9. AI 时代常见工程问题与排查清单问题现象可能原因排查方式解决思路AI 生成的代码编译不过编造不存在的 API 或依赖查看编译错误确认 API 是否真实存在用反射/文档验证 API修正提示词测试跑不通需求理解偏差或实现逻辑错误查看失败断言和堆栈把失败信息回传 AI让其修正实现测试通过但线上行为错误测试断言不完整复盘业务场景补充边界用例增加集成测试和端到端测试代码风格混乱提示词缺少约束没有格式化工具运行静态检查工具接入自动格式化制定编码规范新增了一堆奇怪依赖模型为了“完成任务”盲目引入检查依赖变更提示词明确“禁止新增依赖”PR 中人工核对安全漏洞未做安全审查输入输出未校验运行 SAST 工具和依赖审计加入安全测试清单高危模块人工审查批量任务卡死长任务无超时、并发控制缺失查看日志和资源占用加入超时、重试、熔断机制审查者看不完 PR一次改动过大统计 PR 文件数设置 PR 大小上限强制拆分看到问题别急着怪 AI。先确认你给 AI 的输入是不是一份合格的“规格说明”。大多数时候问题出在提示词描述得不够清晰或者验收标准没有提前落到测试上。10. 最佳实践与合规提醒10.1 个人工程师建议先练基本功TDD、整洁代码、重构。AI 工具会把基本功差的人“包装”成高产开发者但代码质量会在半年后暴露。把提示词写成一个模板库按“接口实现”“测试生成”“脚本编写”“日志分析”分类保存。养成“先写测试再生成实现”的习惯不要把 AI 当成最终代码来源。学会审 AI 的代码而不是直接复制粘贴。在本地写代码时保持小步提交这样 AI 生成代码出问题后回滚成本低。10.2 团队层面的建议制定《AI 编程使用规范》明确哪些数据可以提交给外部 AI哪些不行。在代码仓库里要求 PR 标注“AI 生成”并强制执行代码审查。沉淀一套统一的提示词模板和验收标准减少个人风格带来的差异。建立质量度量AI 生成代码的编译成功率、测试通过率、缺陷修复周期。对 AI 生成代码保留人工责任制无论代码是不是 AI 写的提交者都要负责。10.3 合规底线涉及版权、隐私、人脸、声音的素材必须先确认合法授权。生成代码如果用于商用必须有许可证审查记录。内部敏感系统尽量采用本地化部署方案避免核心代码外传。任何 AI 工具接入生产环境都要做权限最小化和日志审计。11. 总结与下一步Uncle Bob 这场 Live 最值得记的东西不是某个具体技巧而是提醒大家AI 生成代码的能力越强工程师就越要守住工程基础。建议你先在团队里做一次最小实验挑一个不紧急的小功能先写测试再让 AI 生成实现再走一遍代码审查。这个实验能同时暴露三件事你的需求描述是否清晰、AI 生成代码的缺陷模式是什么、团队的审查机制有没有跟上。最容易踩的坑是“不审查就合并”一旦第一条 AI 生成代码绕过审查进了主干后续防线就会逐渐失效。后续可以继续扩展的方向包括把提示词模板接入内部 Wiki、将 AI 生成的测试用例回归到 CI、探索 AI Agent 在低风险任务中的自动执行。技术会变工具会变但“可测试、可维护、可演进”这三个工程基础还是会继续起作用。