本文 首发于 🌱 煎茶转载 请注明 来源

来源:Vibe Coding Is Not Engineering - Phroneses

作者:Jh Evans

说明:本文为 AIGC 辅助翻译版本,已进行简单人工校对,具体细节请自行甄别。

Vibe Coding 不是工程

Vibe coding 能产出代码。工程则产出系统,因为工程会定义那些位于生成代码之外、却能让解决方案长期在生产环境中持续运行的要素。

这并不是反对 AI 的论证,而是支持工程的论证。

模型可以在几秒钟内生成一个登录系统。但它不会主动询问:邮箱是否应该唯一?如果邮箱应该唯一,而生成的代码没有强制保证这一点,那么这一个缺失的需求就可能导致生产环境停机。

LLM 看不见那些让软件保持安全的问题类别。

Vibe coding 能给你什么

这里所说的 vibe coding,指的是由非软件工程师通过提示词自动生成代码。

Vibe coding 会给你代码,但不会给你长期在生产环境中运行代码所需的一致性。

代码会被部署到运行时生产系统中,而这个系统构成了代码运行时的上下文。大型语言模型无法知道这个正在运行的系统究竟是什么,因此也无法提供具备系统感知能力的代码。此外,LLM 看不到业务需求,所以生成的代码也不会覆盖这些需求。

缺少业务与运行时上下文意识,被遗漏的需求就会造成失败。

在任何代码出现之前,工程师已经在做那些让系统保持安全的决策。

主题描述
问题界定定义问题、用户、约束和预期结果。
需求工程引出行为、不变量、边界情况和验收标准。
系统建模状态模型、数据流、序列图与因果推理。
架构设计边界、职责、接口、故障模式与权衡。
非功能需求定义性能、可靠性、安全、合规、可运维性与成本。
风险识别未知项、依赖、故障点与缓解措施。
接口与契约设计定义 API、模式与行为保证。
计划与排序将工作拆分为连贯且可交付的单元。

工程实际上是什么

当工程师写代码时,他们并不只是在敲字。他们在:

  • 消除歧义;
  • 定义边界;
  • 建模行为;
  • 决定系统在压力下如何表现。

其中大多数工作发生在第一行代码出现之前。这些工作让系统保持连贯。

Vibe coding 跳过的工程工作

LLM 会跳过工程学科中的这些部分。

领域工程师决定什么LLM 生成什么
不变量什么必须始终为真假设一切正常的代码
身份与唯一性什么让一个实体被视为“同一个东西”把所有东西都当作可互换对象的代码
约束系统绝不能允许什么没有意识到越界的代码
故障模式系统在压力下如何表现只在顺利路径上有效的代码
耦合与顺序什么依赖什么,以及以什么顺序依赖完全忽略顺序的代码
状态与转换状态如何改变,以及由什么触发没有规则地修改状态的代码
接口与契约每个部分向系统其余部分承诺什么暴露模型随手编出的接口的代码
边界系统不做什么不断扩张直到崩溃的代码
错误处理系统如何恢复遇到第一个意外输入就崩溃的代码

这些工作是 LLM 不会主动询问的。若不关注这些工作,生成的代码长期来看就会失败。

系统不只是文本

这一点很重要,因为从长期看,系统安全依赖于:

  • 必须始终成立的不变量;
  • 不能被违反的约束;
  • 塑造业务逻辑和用户行为的耦合与顺序规则。

LLM 并不理解这些。

为什么 AI 生成的代码会停滞并制造脆弱性

AI 生成的代码之所以长期会停滞,是因为必要的工程决策没有被做出。

当这些决策缺失时:

  • 功能彼此冲突并相互破坏;
  • 系统状态变得不可预测;
  • 部署变得脆弱而缓慢;
  • 错误信息开始失去意义;
  • 添加简单功能也变得越来越困难。

人们对系统的信心会崩塌。

系统不是你生成出来的代码。系统是这些代码在某个环境中运行时形成的组合体。

演示很容易,产品并不容易

给定一个简单提示词:

编写 Python 代码:“给网站添加用户账户,让人们能够登录。”

模型生成了一个小型、可运行的 Flask 和 SQLite 示例。作为演示,这可以接受;但它没有询问以下五个需求:

  • 邮箱是否应该唯一?
  • 账户是否应该经过验证?
  • 用户是否应该能够重置密码?
  • 是否应该存在角色?
  • 安全模型是什么?

解决办法并不是写出更好的提示词。非软件工程师很可能并不知道上面这些问题本来就应该被提出。

未被提出的问题会带来什么后果

如果代码没有确保邮箱唯一,那么两个人就可以用同一个邮箱注册。如果他们同时登录,用户登录身份就会变得含糊不清。代码无法区分他们。

当用户使用重复邮箱登录时,从数据库中检查该用户注册信息会返回多个值。任何用于检查注册用户的代码,都必须安全处理可能出现多个结果的情况。

缺少对邮箱唯一性的考虑,意味着如果某个使用重复邮箱的用户重置密码,vibe coding 生成的实现可能会重置所有共享该邮箱用户的密码。这在生产环境中是不可接受的。如果其中一个用户删除账户,多个账户也可能被删除。没有任何生产系统能容忍这种情况。

Vibe coding 背后的误解

Vibe coding 假设 AI 拥有类似工程师的“智能”。如果这是真的,缺失需求、含糊规则和隐藏约束就会被自动捕获。

但 LLM 不会做这些事。它们不会围绕你的系统进行推理。它们不会建立领域模型来帮助推理你的系统。它们不会追踪变更的后果,也不会确保不变量不被破坏。

LLM 会生成能够运行的代码,却不会完成为了让这些代码在你的系统中长期、安全使用所必需的分析。

因为生成的代码解决了眼前问题,人们便以为必要分析已经完成。他们会假设结果系统是连贯的,只因为当前代码看起来能正常执行。

Vibe coding 在生产环境中失败,是因为那些缺失的决策会在之后以故障、不一致和脆弱性的形式重新出现。模型看不到本该被询问的那类问题,而进行 vibe coding 的人则以为模型已经看到了。

应该怎么做

在生成任何代码之前,先决定:

  • 什么必须始终为真,即不变量;
  • 什么让某个东西成为“同一个”实体,即身份规则;
  • 系统绝不能允许什么,即约束;
  • 当事情出错时,系统如何表现,即故障模式。

LLM 生成代码。它们不会做工程决策。这项工作仍然存在。

底线

Vibe coding 能给你一个演示,而这个演示是一次性的。

要把这个演示推进到生产环境,需要工程。

相关阅读

  • The Big AI Gains Come From Teams, Not Individuals
  • Agents Cannot Maintain Systems
  • What Software Engineers Need to Know About LLMs
  • Latency Is Architectural