尧图建网站 尧图建网站 YAOTU WEB BUILD 免费咨询
ARTICLE DETAIL

资讯详情

深耕网站建设与建站编程的一线实战洞察。

AI时代,为什么软件工程基础反而更重要?

AI时代,为什么软件工程基础反而更重要? 好的今天想跟你认真聊一个话题当 AI 能自动生成代码、能解释报错、能重构逻辑之后我们还需要学软件工程吗这个问题不是凭空冒出来的。最近几年AI 编程助手已经从“能补全一行代码”进化到“能独立完成一个功能模块”很多开发者开始产生一种感觉软件工程的那些方法论、设计原则、测试规范是不是正在变成束缚效率的旧规则但偏偏在这个时间点被誉为“软件工匠精神”代表人物之一的 Uncle BobRobert C. Martin却在公开分享里反复强调一个看似反潮流的观点AI 写得越多软件工程基础反而越重要。这篇文章就从 Uncle Bob 这次关于 AI 时代软件工程基础的分享展开聊聊为什么 AI 没有取消软件工程而是把软件工程推到了更关键的位置。同时我会结合真实开发场景谈谈 AI 时代下仍然不能丢的那些工程基本功以及实际落地时应该怎么调整工作流。如果你正在用 AI 辅助编程或者你的团队正在推广 AI 开发工具这篇文章应该能帮你少踩一些坑。1. 为什么 Uncle Bob 的这句话值得认真听先解释一下为什么我们单独把 Uncle Bob 的观点拿出来聊。Uncle Bob 是软件工程领域的老牌实践者也是《代码整洁之道》Clean Code、《代码整洁之道程序员的职业素养》The Clean Coder等经典著作的作者。他在职业生涯里推动过很多到今天仍然在用的工程实践比如 TDD测试驱动开发、SOLID 设计原则、敏捷开发方法论。可以说你今天在团队里用的很多代码规范、评审标准、测试要求背后都有他的影响。在 AI 编程工具爆发式增长的这两年技术圈出现了一种声音既然 AI 能写代码那么开发者是不是只要会“提需求”就够了代码风格、设计原则、测试覆盖率这些东西是不是都不再重要了Uncle Bob 的判断恰好相反。他从多个角度论证AI 生成代码的速度越快工程师对代码质量的责任就越大而软件工程基础恰恰是控制这种“高速生产”质量下限的唯一手段。这个观点的现实意义在于AI 编程工具本质上是一个“高效率的代码生成器”它不关心代码在真实环境里是否可维护、可扩展、可测试。它生成代码的速度越快团队里 Review、测试、重构的压力就越大。如果没有扎实的软件工程基础AI 带来的不是效率提升而是混乱加速。2. 基础概念软件工程基础到底包含什么在展开讨论之前先把“软件工程基础”这个说法具体化。很多人把软件工程等同于“写代码的流程”但它是更完整的一套体系。从实际工程角度看通常包含以下几个层面第一个层面需求与问题分解。这是最容易被 AI 时代忽视的一层。AI 能写代码但它不能替你判断“你真正要解决的问题是什么”。把业务需求拆成清晰的、可验证的功能点仍然是人的工作。第二个层面设计与架构。包括模块边界、依赖方向、接口设计、数据流规划。这一层决定了代码能不能长期演进。AI 生成函数可能很快但如果模块之间没有清晰的边界后续每个功能改动都会变得异常艰难。第三个层面编码规范与代码整洁度。命名、函数粒度、重复代码、注释和可读性。这些看似表面的东西直接决定了代码能不能被团队理解和修改。第四个层面质量保障与测试。包括单元测试、集成测试、回归测试、验收测试。质量保障不只是“找 bug”更是给未来修改代码建立安全网。第五个层面工程流程与协作。版本管理、代码评审、持续集成、部署流程、线上监控。这些流程保证一个团队可以稳定、可预测地交付软件。第六个层面职业素养与责任意识。这是 Uncle Bob 特别强调的一点工程师要为自己的代码负责而不是把责任推给工具。表格总结层面核心问题AI 能替代吗需求分解要解决什么问题不能需要业务理解和判断设计架构模块怎么划分、依赖怎么管理部分辅助决策仍需人编码规范代码是否可读可维护能生成代码但不保证质量质量保障怎么证明代码是对的能生成测试但测试策略需人设计工程流程团队怎么协作交付不能流程是组织能力职业素养谁为质量负责不能这个框架是理解 Uncle Bob 观点的基石AI 只是把“写代码”这个环节变得更快但软件工程的每一个其他环节仍然是决定成败的关键。3. AI 时代软件工程真正发生的改变如果你只看表面会以为 AI 对软件工程的冲击是“写代码不再需要人了”。但实际上变化发生在更具体、更细分的环节上。3.1 变化一编码工作量下移质量责任上移过去一个功能从需求到上线大量时间消耗在“手写代码”上。现在 AI 可以把写代码的时间压缩到很小但这部分节省下来的时间并没有消失而是转移到了需求分析、代码评审、测试设计、架构取舍上。举个例子你让 AI 生成一个订单状态机它可以在 30 秒内给出完整代码。但你需要判断它的状态流转是否正确、异常分支是否覆盖、与支付回调的交互是否可靠。这个判断的难度远高于自己照着文档写一遍代码。所以真正发生变化的是简单编码变容易了但“知道自己要什么”和“判断代码是否正确”这两件事的权重显著上升。3.2 变化二AI 生成的是代码不是软件这里要区分“代码”和“软件”两个概念。代码是文本软件是运行在真实环境里、被真实用户使用的交付物。AI 能生成大量代码文本但把代码变成可靠软件需要经过集成、测试、部署、监控、运维。这个体系性的工程能力和 AI 生成单个函数的能力是完全不同层级的事情。换句话说AI 让“代码生成”这个环节无限趋近于零成本但“把代码变成可用软件”的成本依然很高甚至因为代码量的膨胀而变得更高。3.3 变化三开发者的瓶颈从“写”转移到“读”一个 AI 辅助编程的团队代码产出速度会明显提升但代码量也会迅速膨胀。大量 AI 生成的代码进入代码库后团队花费在阅读、理解、评审上的时间会显著增加。这意味着未来的软件工程能力更突出地体现在“读代码”的能力上——快速理解一段代码的意图、判断它的边界、找到它的缺陷。这种读代码的能力依赖的仍然是对命名、结构、设计模式、测试覆盖的判断力。这和 Uncle Bob 长期强调的“整洁代码”理念完全一致代码是给人读的顺便给机器执行。AI 时代这个原则不但没失效反而更关键了。4. AI 时代软件工程基础的正确工作流既然变化发生在这些环节那么一个使用 AI 辅助开发的正规流程应该是什么样我观察到的很多团队现在有两种极端做法一种是不让用 AI怕代码质量失控另一种是完全交给 AIreview 都省了。实际上更合理的方式是把 AI 嵌入到软件工程的每一个环节但每一环节都保留人的判断和验证。下面是一个适用于大多数业务项目的实践路径。4.1 需求阶段用 AI 整理清单人来判断边界这个阶段可以让 AI 帮你从一段需求描述中提取功能点、角色、边界条件甚至帮你生成初步的验收标准。但人要做的是确认这些理解是否正确、有没有遗漏业务规则、有没有超出范围的幻想功能。示例命令如下这是给 AI 的提示词你是一个资深业务分析师。以下是产品经理给出的原始需求 “用户可以在订单列表页面筛选订单支持按订单号、订单状态、创建时间范围筛选。筛选结果按照创建时间倒序展示。点击某条订单可以进入订单详情页。” 请提取 1. 明确的功能点列表 2. 每个功能点的验收标准 3. 你认为需要产品经理确认的模糊点这一步的价值是把 AI 当思维外脑而不是当决策者。4.2 设计阶段用 AI 生成候选方案人来定架构设计阶段AI 可以扮演一个快速出方案的助手。你把自己的约束条件、业务背景、已知难点告诉它让它给出设计选项。但架构选型、模块边界、依赖方向必须由人来最终拍板。一个常见的做法是让 AI 生成一个模块划分的候选方案然后你手动检查依赖方向是否符合项目的整体架构约束。我们正在开发一个电商订单中心。请基于领域驱动设计的思路给出订单模块、支付模块、库存模块的边界划分标注每个模块的核心领域对象和对外接口。注意订单模块不能直接依赖库存模块只能通过领域事件或接口解耦。然后你要审视 AI 给的方案检查模块之间是否存在循环依赖领域对象是否被过度暴露接口设计是否符合现有团队规范4.3 编码阶段AI 生成代码 单元测试先行这是最核心的阶段。Uncle Bob 多年的主张是 TDD测试驱动开发在 AI 时代这个原则有了一个全新应用让 AI 按测试来写实现而不是直接生成实现。传统方式是请帮我写一个计算订单总价的函数。更稳健的方式是请先写出以下需求的单元测试 函数 calculateOrderTotal(order) 计算订单总价。 规则 1. 基础价格 单价 * 数量 2. 满 100 元打 9 折 3. 优惠券金额从总价中扣除最低为 0 4. 订单商品为空时返回 0 请先用 JUnit 写出测试用例先不要写实现。这样做的好处是测试用例定义了行为契约AI 按契约补实现Review 时就只需要核对实现是否符合测试意图。即使 AI 生成的实现有缺陷测试也能在早期暴露问题。4.4 评审阶段用 AI 做第一次 Reviewer人做最终判断代码评审是质量保障的关键环节。对 AI 生成的代码更要严格执行 Review而不是默认“AI 写的应该没错”。可以先用 AI 做一轮初步检查让它在提交前过滤掉低级问题以下代码是 AI 生成的订单号生成器请检查 1. 是否存在并发问题 2. 是否可能生成重复订单号 3. 异常处理是否合理 4. 命名是否符合项目规范 public class OrderNoGenerator { public String generate(String prefix) { long timestamp System.currentTimeMillis(); int random new Random().nextInt(1000); return prefix timestamp random; } }AI 会发现随机数冲突、时间戳并发的问题。然后人工 Reviewer 再去做更深入的检查业务逻辑是否正确、是否满足非功能需求、是否与其他模块接口兼容。这里的原则是AI Review 可以提高效率但人的责任不能被替代。4.5 验证阶段自动化测试 持续集成完整运行无论是 AI 生成的代码还是人写的代码最终都要靠自动化测试和持续集成管线来验证。这个环节在 AI 时代尤其重要因为 AI 生成的代码可能表面正确但副作用很多。完整的验证链路应该包括单元测试验证每个函数行为符合预期集成测试验证模块间交互正确端到端测试验证核心业务流程可用静态分析检查代码规范、潜在缺陷构建验证确认可以成功打包部署在这个流程里AI 是“提效工具”不是“免测理由”。5. 一个完整的示例用 AI 辅助实现订单状态机为了让上面的方法论更具体我用一个实际例子演示如何用软件工程基础 AI 辅助完成一个订单状态机的开发。5.1 需求描述订单状态机是电商系统里很常见的功能模块但状态多、流转复杂很容易出错。我们先明确状态定义待支付PENDING_PAYMENT已支付PAID已取消CANCELLED已发货SHIPPED已完成COMPLETED售后中REFUNDING允许的状态流转PENDING_PAYMENT → PAID支付成功PENDING_PAYMENT → CANCELLED未支付取消PAID → CANCELLED支付后取消需退款PAID → SHIPPED发货SHIPPED → COMPLETED确认收货COMPLETED → REFUNDING申请售后5.2 先用 AI 生成测试用例我们按照 TDD 的思路先让 AI 写测试。我们要实现一个订单状态机类 OrderStateMachine。它管理订单状态流转非法流转会抛出 IllegalStateException。下面是允许的状态流转表 PENDING_PAYMENT - PAID PENDING_PAYMENT - CANCELLED PAID - CANCELLED PAID - SHIPPED SHIPPED - COMPLETED COMPLETED - REFUNDING 请用 JUnit 5 写完整的测试类覆盖 1. 所有合法流转 2. 所有非法流转 3. 从已终态COMPLETED、CANCELLED出发的流转 4. 空状态输入的异常处理 要求测试代码先写不写实现。5.3 AI 生成的测试代码示例下面的代码是 AI 辅助生成的测试类放在src/test/java/com/example/order/OrderStateMachineTest.javapackage com.example.order; import org.junit.jupiter.api.Test; import static org.junit.jupiter.api.Assertions.*; class OrderStateMachineTest { private final OrderStateMachine stateMachine new OrderStateMachine(); Test void shouldMoveFromPendingPaymentToPaid() { OrderState current OrderState.PENDING_PAYMENT; OrderState next stateMachine.next(current, OrderEvent.PAY_SUCCESS); assertEquals(OrderState.PAID, next); } Test void shouldMoveFromPendingPaymentToCancelled() { OrderState current OrderState.PENDING_PAYMENT; OrderState next stateMachine.next(current, OrderEvent.CANCEL); assertEquals(OrderState.CANCELLED, next); } Test void shouldAllowCancelAfterPaidWithRefund() { OrderState current OrderState.PAID; OrderState next stateMachine.next(current, OrderEvent.REFUND); assertEquals(OrderState.CANCELLED, next); } Test void shouldMoveFromPaidToShipped() { OrderState current OrderState.PAID; OrderState next stateMachine.next(current, OrderEvent.SHIP); assertEquals(OrderState.SHIPPED, next); } Test void shouldMoveFromShippedToCompleted() { OrderState current OrderState.SHIPPED; OrderState next stateMachine.next(current, OrderEvent.CONFIRM_RECEIPT); assertEquals(OrderState.COMPLETED, next); } Test void shouldMoveFromCompletedToRefunding() { OrderState current OrderState.COMPLETED; OrderState next stateMachine.next(current, OrderEvent.APPLY_REFUND); assertEquals(OrderState.REFUNDING, next); } Test void shouldThrowExceptionForIllegalStateTransition() { OrderState current OrderState.PENDING_PAYMENT; assertThrows(IllegalStateException.class, () - { stateMachine.next(current, OrderEvent.SHIP); }); } Test void shouldThrowExceptionFromFinalState() { assertThrows(IllegalStateException.class, () - { stateMachine.next(OrderState.COMPLETED, OrderEvent.PAY_SUCCESS); }); assertThrows(IllegalStateException.class, () - { stateMachine.next(OrderState.CANCELLED, OrderEvent.SHIP); }); } Test void shouldThrowExceptionForNullState() { assertThrows(IllegalArgumentException.class, () - { stateMachine.next(null, OrderEvent.PAY_SUCCESS); }); } }这里的关键点是测试用例不是随便写的它对应了需求里明确的功能点也补上了需求里没有直接明说、但软件设计上必须处理的边界条件。测试用例写得好不好决定了 AI 实现代码时能不能做对。5.4 让 AI 补实现测试写好之后再让 AI 写实现请根据以下 JUnit 测试类 OrderStateMachineTest实现 OrderStateMachine 类、OrderState 枚举和 OrderEvent 枚举。实现要求 - 状态流转表与测试一致 - 非法流转抛 IllegalStateException - 空状态抛 IllegalArgumentException - 使用枚举和 Map 或 switch 实现逻辑清晰5.5 AI 生成的实现代码示例下面是 AI 生成的实现代码放在src/main/java/com/example/order/OrderStateMachine.javapackage com.example.order; import java.util.EnumMap; import java.util.Map; public class OrderStateMachine { private final MapOrderState, MapOrderEvent, OrderState transitions; public OrderStateMachine() { transitions new EnumMap(OrderState.class); transitions.put(OrderState.PENDING_PAYMENT, Map.of( OrderEvent.PAY_SUCCESS, OrderState.PAID, OrderEvent.CANCEL, OrderState.CANCELLED )); transitions.put(OrderState.PAID, Map.of( OrderEvent.REFUND, OrderState.CANCELLED, OrderEvent.SHIP, OrderState.SHIPPED )); transitions.put(OrderState.SHIPPED, Map.of( OrderEvent.CONFIRM_RECEIPT, OrderState.COMPLETED )); transitions.put(OrderState.COMPLETED, Map.of( OrderEvent.APPLY_REFUND, OrderState.REFUNDING )); } public OrderState next(OrderState current, OrderEvent event) { if (current null || event null) { throw new IllegalArgumentException(current and event must not be null); } MapOrderEvent, OrderState stateTransitions transitions.get(current); if (stateTransitions null) { throw new IllegalStateException(No transition allowed from state: current); } OrderState nextState stateTransitions.get(event); if (nextState null) { throw new IllegalStateException( Illegal transition from current on event event); } return nextState; } }5.6 运行验证在项目根目录执行测试mvn test -DtestOrderStateMachineTest预期输出应该包含类似下面的内容[INFO] Tests run: 9, Failures: 0, Errors: 0, Skipped: 0 [INFO] BUILD SUCCESS如果测试失败不要着急改实现。先看是哪个用例失败了再判断是测试本身的问题还是实现的问题。这就是测试驱动开发的好处失败点就是问题点不需要靠人去读完整段代码猜。6. 验证与评审AI 时代代码质量怎么把关上面的示例跑通了只是完成了功能开发的第一步。真实项目里还需要经过下面的验证关卡。6.1 单元测试覆盖率不是目标行为验证才是很多人有一个误区以为 AI 生成了测试覆盖率跑得高质量就有保障。实际上覆盖率只能说明“有多少代码被执行了”不能说明“这些代码在真实场景里行为是否正确”。一个更有效的检查方法是对每个核心规则至少有一个正向测试和一个反向测试对状态机、支付计算这类有复杂分支的逻辑用边界值补充测试对并发、幂等、重试这类非功能要求单独设计测试场景6.2 人工 Review 的侧重点AI 生成代码后Review 时可以重点关注这些点命名是否准确函数名、变量名是否真正表达了意图副作用是否被隐藏比如状态机里是否偷偷改了其他对象状态异常处理是否完备空值、非法参数、资源释放是否处理了是否有隐藏的性能问题循环里是否调用了外部接口是否符合团队既有规范代码风格、分层约束、异常体系建议把 AI 生成的代码当成“外包代码”来看待。外包代码你会 Review 吗大概率会。AI 生成的代码也是一样的逻辑。6.3 增加持续集成检查在团队协作中建议把下面的检查集成到 CI 管线里# .github/workflows/ci.yml 简化版 name: CI on: push: branches: [ main ] pull_request: jobs: build: runs-on: ubuntu-latest steps: - uses: actions/checkoutv4 - name: Set up JDK uses: actions/setup-javav4 with: java-version: 17 - name: Run tests run: mvn test - name: Run static analysis run: mvn checkstyle:check这里的原则是AI 生成代码没有议价能力但规则有。用自动化规则去约束 AI 生成的质量比每次人肉审查更可控。7. 常见问题与排查思路在使用 AI 辅助编程的过程中团队和个人经常会遇到下面这些问题。问题现象可能原因排查方式解决方案AI 生成的代码编译不过提示词给的上下文不足依赖信息不完整查看编译错误检查缺失的 import 或依赖在提示词中补充项目使用的框架、版本、依赖坐标AI 生成代码能跑但逻辑错误需求描述不完整AI 猜错了业务规则用测试用例验证行为检查测试覆盖先写测试再要求 AI 实现把验收标准写进提示词测试覆盖很高但线上仍有 bug测试用例本身和需求不一致人工复核测试用例的逻辑断言需求评审时把验收标准与测试用例对齐AI 频繁输出重复代码提示词中没有强调复用现有函数检查项目已有工具类、公共组件提示词里注明“优先使用 com.example.common 下的工具类”Review 耗时越来越长AI 生成的代码太多太杂分析 AI 代码在 PR 中的占比限制单次 AI 生成的范围一次只生成一个函数或一个类AI 生成的代码与现有架构风格不一致没有给 AI 提供现有代码示例检查现有模块的写法在提示词中粘贴一个现有模块的代码片段作参考AI 无法处理复杂的业务状态流转状态机的业务规则数量超出 AI 单次处理能力把状态流转拆成多个子问题分批生成先定义状态枚举再定义流转表最后写实现遇到 AI 生成的异常代码时一个稳妥的顺序是先看报错信息再检查测试用例是否合理最后才动手修改逻辑。尽量不要让 AI 反复“瞎猜”把错误信息作为新的上下文重新提问效果会好很多。8. 最佳实践与工程建议把前面的内容收敛成几条可以立刻执行的建议。8.1 把测试前置这件事坚持到底AI 时代TDD 的价值被放大了。过去写测试要花时间现在你可以让 AI 先快速生成测试骨架你只需要确认测试用例是否符合需求。这是成本最低、收益最高的方式。8.2 为 AI 的使用建立边界规范团队层面可以约定什么场景允许用 AI、什么场景不允许。比如工具类、模板代码、单元测试生成可以用 AI核心交易逻辑、状态机、支付回调等高风险模块AI 只做辅助必须由资深工程师设计并由测试完整覆盖。8.3 给 AI 足够上下文但不要给全部上下文给 AI 的信息太多它会迷失给得太少它会瞎猜。比较稳妥的做法是给需求描述、关键约束、允许使用的函数签名同时告诉它领域相关的基础概念。8.4 代码评审要有“AI 作者”概念PR 模板上可以增加一个字段本次代码由 AI 生成的比例是多少。这样 Reviewer 在评审时会用不同的关注度。100% AI 生成的代码需要更严格的测试验证人机协作的代码重点是看人的判断部分是否符合软件设计原则。8.5 保持对基础知识的长期投入AI 可以帮助你写出很多代码但评估一个函数是否优雅、一个设计是否合理、一个状态机是否覆盖了所有边界仍然需要人的知识和经验。这个能力只能靠持续学习、Review 优秀代码、深入理解业务来积累。9. 总结与后续可以继续深入的方向这篇文章的核心其实就一句话AI 是提高编码速度的放大器但软件工程基础是保证工程质量的下限。没有扎实的基础AI 带来的效率提升会很快被质量债吞掉。从 Uncle Bob 的分享出发我们聊了软件工程基础的几个层面重点讨论了 AI 对编码、测试、评审、架构这几个环节的真实影响并且用一个订单状态机的完整示例演示了“先测试后实现”的正确 AI 辅助姿势。希望这个例子能帮你在自己的项目里把 AI 从“写代码工具”转变为“工程流程的一部分”。如果你对下面这些方向感兴趣可以继续深入如何用 AI 辅助做架构重构而不是只生成新代码状态机之外策略模式、责任链模式等设计模式在 AI 辅助下的实现方式在团队里推广 AI 编程工作流时如何设计 Review 和测试规范如何评估 AI 生成代码的质量建立可量化的指标不管 AI 工具怎么迭代有一点不会变软件是工程师用专业能力构建出来的产物工具可以增强能力但不能替代责任。
返回列表