摘要
过去几个月,我越来越多地使用 AI 编写真实的产品代码。我的感受有些复杂:它确实很快、很实用,有时甚至好得出人意料。但“功能做出来了”和“系统设计好了”,从来不是一回事。
问题通常不在于 AI 不会写代码,而在于我们只给了它功能需求,却把可靠性、可维护性、可观测性、可测试性、安全性和可运营性留在了工程师脑中。DFX,也就是 Design for X,正是把这些质量目标重新放回需求和设计。代码生成越便宜,这些约束反而越值钱。
AI Coding 的目标不应该只是更快地产生更多代码,而应该是在更清晰的约束下,产生更好的代码。
第一部分 · 功能能跑,系统呢?
01功能做完了,系统却越来越不敢碰
过去几个月,我越来越多地让 AI 直接写代码。表面上看,它已经非常厉害:让它做一个页面、写一条 API、增加一个定时任务、连接数据库,或者修复一个小 Bug,它通常都能完成得不错。很多时候,结果不只是“勉强能用”,而是真的很快、很实用,偶尔还会让人惊喜。
但在真实产品代码里用了一段时间后,我逐渐注意到另一个问题:AI 很擅长实现功能,却不会自动替我们设计出一个好系统。
一开始,一切看起来都很正常。功能能跑,API 返回了正确数据,前端也接通了,任务执行成功,日志里没有明显报错。随后需求又来了一条,再来一条,然后还有一条。经过几轮修改,代码开始变得异常熟悉:业务逻辑散落在各层,模块边界越来越模糊,相同检查重复出现,状态变化藏在分支里,异常处理各自为政,配置逻辑和执行逻辑纠缠在一起。
换句话说,功能完成了,系统却越来越难碰。
这并不只是“AI 会写烂代码”的问题。人类工程师同样会写出这样的代码。区别在于,AI 可以把这个过程加速很多倍。它能放大好的设计,也能放大缺失的边界、含糊的要求和一次次权宜之计。
2025 年 DORA 关于 AI 辅助软件开发的报告,把 AI 的主要作用概括为“放大器”:它会同时放大一个组织原有的优势和弱点,而不是替代工作背后的整个工程系统。[1] 这份研究讨论的是组织能力,但映射到代码库,我看到的是同样的现象:工程纪律清晰时,AI 会让它跑得更快;设计已经漂移时,AI 只会给漂移增加吞吐量。
真正的问题是,大多数时候,我们只给 AI 功能需求。我们告诉它系统要做什么,却没有明确告诉它:出错时应该怎样表现,未来应该怎样维护,运行状态怎样被看见,新的需求怎样扩展,又该怎样防止人犯下代价高昂的错误。
这就是为什么我认为,在 AI Coding 时代,DFX 只会变得更重要。
02只有功能需求,远远不够
在软件设计中,我们通常会谈到两类需求。
功能需求描述系统“要做什么”:用户登录、创建订单、调度任务、生成报表、处理支付、发送通知或执行交易。这些需求很容易从外部观察。按钮有还是没有,API 能不能调用,流程是完成还是失败,一眼就能看见。
但真实系统的评价标准,从来不只是某个功能能否在理想条件下成功运行一次。系统还需要可靠、可维护、可观测、可测试、安全、可扩展、可运营。我们常把它们统称为“非功能需求”,这个名字听起来像是次要要求,实际上它们对架构的影响,往往比可见功能更深。
Fred Brooks 在《没有银弹》中区分了软件工作的“偶然困难”和“本质困难”:编程语言、工具和表达方式带来的摩擦可以被不断降低,但软件真正困难的部分,仍然是对复杂概念结构的定义、设计与验证。[2] 这篇论文比 AI Coding 早了几十年,把它用在今天是一种推论,但很贴切:AI 能显著降低“把想法写成代码”的成本,却不能替我们决定系统究竟意味着什么、边界在哪里,以及失败之后什么承诺仍然必须成立。
以一个简单的任务执行系统为例。如果只关心功能,实现非常直接:
- 从数据库读取任务;
- 执行任务;
- 更新任务状态;
- 返回执行结果。
AI 很快就能写完。但只要把可靠性放进来,设计立刻变得有意思。
如果进程执行到一半崩溃怎么办?同一个任务被两个 Worker 同时领取怎么办?外部 API 已经部分成功,却在返回响应前超时怎么办?业务操作成功后,数据库状态更新失败怎么办?任务该不该重试?操作是否幂等?用户能否安全地再点一次按钮?哪些状态必须持久化,哪些状态可以重新计算?
这些不是无关紧要的实现细节。在生产系统里,真正的事故往往就发生在这些地方。
一个简单的判断标准: 功能验收证明理想路径能跑通;工程验收则要定义,当这条路径被打断、重复、延迟、修改或误操作时,系统还必须守住什么。
第二部分 · DFX 改变的不是名词,而是设计顺序
03DFX 在实践中究竟意味着什么
DFX 是 Design for X,也就是“为了某个目标而设计”。这个 X 可以代表许多不同的质量目标:
下面这张分类图来自更广义的产品设计语境。它把 DFX 分为产品交付、产品演进和产品运行三组,继续向下覆盖采购、供应链、部署、可靠性、可服务性、安全、兼容、复用等目标。[3] 软件团队未必使用完全相同的词汇,但核心思想是一致的:产品必须为功能完成之后的漫长生命周期而设计。

图 1 · DFX 贯穿交付、演进与运行。 功能完成只是产品生命周期中的一个瞬间。这张图的意义,在于让质量目标在实现之前就进入设计讨论。
这些话题听起来不如发布一个新功能兴奋,但它们决定了功能上线之后,系统还能不能活下去。一个功能可以在一个下午里写完,一套糟糕的架构却可能惩罚团队两年。
使用 AI 时,这个问题尤其明显。代码生成变便宜了,偶然复杂度也随之变得廉价。我们可以不断要求它:“就加一个判断”“再支持一个场景”“只修这一个 Bug”“先复用现有逻辑”。每一个指令单独看都很合理,整体设计却在持续恶化。
最后,没有人知道真正的业务边界在哪里,没有人知道哪个状态才是权威状态,也没有人知道一次重试是否安全、一次删除能否恢复、一个失败究竟是预期行为、被忽略的问题,还是即将爆炸的风险。
到了这一刻,代码就不再是资产,而开始变成负债。
04AI 为什么容易写出“意大利面代码”
我不认为 AI 写出意大利面代码,是因为它不懂编程。很多时候,它对语法、框架、常见模式,甚至一些架构概念都掌握得不错。问题在于,它默认优化的目标通常太窄。
如果你只说“实现这个功能”,它自然会优化“把当前功能做完”。它会选择一条最直接的路径,让眼前的需求先跑起来。对于一个小脚本或用完即弃的原型,这可能完全合理;但对于需要持续演进的产品,通往今天功能的最短路径,未必是通往可维护系统的最短路径。
代码的恶化通常并不戏剧化:
- 第一次修改
- ,为了方便,业务逻辑直接写进 Controller。
- 第二次修改
- ,为了省事,几个新条件继续堆进同一个 Service。
- 第三次修改
- ,因为改模型看起来太贵,一个新状态被塞进旧字段。
- 第四次修改
- ,因为要求只是“先让它跑起来”,异常被捕获后悄悄忽略。
每一个决定单独看都不算灾难,合在一起却形成了一个很难推理的系统。

图 2 · 偶然复杂度,往往就是在“只再改一点”中累积起来的。 绿色指示灯依然亮着,功能也依然能跑。代价只是被转移给了下一个需求、下一次事故,以及那个必须解释哪根线才算权威状态的人。
Martin Fowler 的“设计耐力假说”描述了同一条曲线:忽略设计,早期也许能更快交付功能;但代码库会逐渐恶化,让每一次后续修改都更慢。好的设计让项目能够“更长时间地保持速度”。Fowler 很谨慎地把它称为假说,而不是已经得到客观证明的定律;设计从何时开始产生回报,也取决于具体场景。[4] AI 并没有让这条曲线失效。它只是让更多修改在更短时间内发生,因此我们会更早抵达曲线真正产生后果的部分。
这并不意味着,应该让 AI 在写第一行代码前先造一座宏大的架构。AI 同样会过度设计:层次太多、Helper 太多、配置太多,或者引入一个看起来优雅、产品却根本用不到的抽象。无论来自补丁还是模式,复杂度都不是免费的。
所以,正确的问题不再是“AI 能不能写代码”。它当然能。更好的问题是:在 AI 开始写之前,我们能不能先给它正确的工程约束?
第三部分 · 为失败设计,也为人设计
05可靠性:不要只设计 Happy Path
可靠性是最适合带入 AI Coding 的 DFX 视角之一。可靠的系统不是永远不会失败的系统,那不现实。可靠的系统会预期失败,限制故障影响范围,让失败能够被看见,并给团队留下恢复路径。
最重要的原则很简单:假设失败一定会发生。进程会崩溃,网络会抖动,磁盘会写满,第三方 API 会超时,用户会点错按钮,开发人员也会发布错误配置。一个只有在一切顺利时才能工作的系统,并不可靠,只是幸运。
所以,在让 AI 写代码之前,我更愿意先问下面这些问题:
实现之前的 DFX 问题
- 这个流程可能在哪里失败?
- 每一种失败发生后,系统会处于什么状态?
- 哪些操作必须幂等?
- 哪些失败可以重试,重试应该由哪一层负责?
- 哪些失败应该告警,哪些必须人工介入?
- 为了事后理解事故,需要记录哪些日志和指标?
- 为了崩溃后恢复,必须持久化哪些状态?
- 用什么证据证明恢复已经完成?
当 AI 先回答完这些问题,后面的实现通常会明显不同。状态变化会更加清晰,重试责任会更加谨慎,重要失败不会被悄悄隐藏,恢复也会从事后补救变成设计的一部分。
前面任务执行器里的超时问题,在 AWS 有一个几乎对应的例子。Malcolm Featonby 描述过一次 EC2 创建请求:服务可能已经创建了资源,但响应在返回途中丢失。如果调用方盲目重试,就可能再创建一台实例。AWS 的做法,是让调用方通过唯一请求标识明确表达意图,使重复请求能够被识别并按幂等语义处理。[5] 这里真正值得借鉴的不是“所有接口都要加一个幂等键”,而是:重试行为应该是 API 契约的一部分,而不是事故之后随手塞进 Catch 里的补丁。
可靠性也不等于平均保护所有路径。Google SRE 把可靠性视为风险管理:服务的可靠性目标应该与业务愿意承担的风险对齐,而不是不计成本追求最高可用率。[6] 这也提醒我们,DFX 不能变成机械清单。营销报表晚十分钟、订单重复扣款和审计记录丢失,显然不应该获得相同的机制和预算。
另一个重要原则是保持简单。一个解决真实问题的简单设计,通常好过一个聪明却制造出五个新问题的设计。但“简单”也不能掩盖单点故障:如果关键流程依赖唯一的服务、唯一的 Job、唯一的配置、唯一的外部系统或唯一的人工步骤,这个风险必须被明确写出来。除非我们要求 AI 从可靠性角度审查设计,否则它未必会主动指出这些问题。
06人为失误,也是系统设计的一部分
很多生产事故,并不是机器自己坏了,而是人在使用系统时,走进了设计没有防护的路径。
有人删错数据,有人发布到错误环境,有人在不了解影响时修改了配置,有人太快地点下危险按钮,也有人因为看不到进度而把同一个操作执行了两次。
责怪用户很容易,但好的系统设计应该主动降低这些错误发生的概率和代价。Don Norman 在《Human Error? No, Bad Design》中说得很直接:如果我们只盯着事故链条最后那个人的动作,就会忽略真正让错误容易发生的设备或流程设计。[7]
映射到软件系统,这个观点会带来非常具体的设计要求:
- 危险操作不能只弹出一句笼统的“你确定吗?”,还应展示真实影响,并根据风险提供二次确认、Dry Run、审批或回滚路径。
- 复杂配置不能照单全收。系统应该在生效前检查冲突、缺失依赖、非法范围和高风险组合。
- 删除不必总是立即永久删除。软删除、回收站、恢复窗口或延迟执行,通常更安全。
- 长时间运行的操作不能让用户猜测。进度、当前状态、日志、重试行为和取消语义,都是功能的一部分。
这些不是功能之外的装饰,而是可靠性和可运营性本身。但很多 AI Coding 提示词只描述用户怎样完成正确操作,很少要求 AI 思考:用户可能怎样做错、怎样失去上下文、怎样重复执行,以及出错后怎样撤销。
第四部分 · 与 AI 建立一份更完整的工程契约
07一种更好的 AI Coding 使用方式
对于任何不只是孤立小任务的功能,我现在都不认为第一步应该是让 AI 立刻写代码。更好的第一步,是先要求它从 DFX 角度分析需求。
例如:
在写代码之前,请从 DFX 角度分析这个需求。 |
这听起来慢了一步,实际往往更省时间。当 AI 理解了质量目标之后,它就不再只是一个代码生成器,而更像一个工程助手。生成的代码通常更有结构,设计取舍也更容易被评审。
这段提示词不是魔法。你仍然需要质疑 AI 的假设、审查设计、理解自己的系统,并判断哪些风险值得付出成本。真正的变化在于,质量目标不再只存在于评审者脑中,而是正式成为任务的一部分。
为了让实现计划真正可执行,我会要求它至少在六个方面给出证据:
| 视角 | 计划必须回答的问题 | 发布前证据 |
|---|---|---|
| 可靠性 | 哪里会失败、重复或部分成功? | 失败测试、幂等语义、恢复步骤 |
| 可维护性 | 哪个边界拥有这条规则,哪里最可能变化? | 模块图、状态模型、明确契约 |
| 可观测性 | 怎样知道用户结果和系统当前状态? | 结构化日志、指标、追踪、可行动告警 |
| 可测试性 | 关键状态与依赖能否被控制? | 成功、失败和重试的确定性测试 |
| 安全与运营 | 谁可以操作,如何限制影响,怎样撤销? | 权限检查、校验、Dry Run、回滚、审计 |
| 扩展性与成本 | 设计基于什么负载和预算假设? | 限流、容量测试、降级行为、成本信号 |
AI Coding 的目标不应该只是更快地产生更多代码,而应该是在更清晰的约束下,产生更好的代码。
08当代码变便宜,架构反而更值钱
有些人认为,随着代码越来越容易生成,架构会变得不再重要。我的判断恰恰相反。
当写代码变得更便宜,决定什么代码值得写就变得更有价值;当实现速度越来越快,错误设计也更容易被放大;当几乎任何人都能生成一个可运行功能,真正拉开差距的,是增加许多功能之后,这个系统是否仍然能够被理解、修改、运营和信任。
AI 可以写代码,但它需要一个清晰的目标。
AI 可以重构代码,但它需要知道重构服务于哪个质量目标。
AI 可以修复 Bug,但它需要理解什么行为才是正确行为。
AI 可以生成抽象,但它并不总能判断这个抽象是否值得它带来的成本。
所以,DFX 并不是一个过时的架构话题。它可能恰恰是我们用好 AI Coding 最实用的方法之一。
未来我们问 AI 的问题,不应该停在:
这个功能应该怎样实现?
还应该继续追问:
这个功能应该在什么质量约束下被实现?
如果跳过第二个问题,AI 的确可以让我们在短期内跑得更快,同时也可能让系统越来越难改、越来越难运维、越来越难信任。代码依然能跑,绿色指示灯也依然亮着,但工程债务可能早已开始复利增长。
参考资料与延伸阅读
- DORA. “State of AI-assisted Software Development 2025.” Google Cloud,2025。
- Brooks, Frederick P., Jr. “No Silver Bullet: Essence and Accidents of Software Engineering.” University of North Carolina at Chapel Hill,1986。
- “DFX 分类图原图.” 随 6 月 18 日原文提供的图片。
- Fowler, Martin. “Design Stamina Hypothesis.” 2007。
- Featonby, Malcolm. “Making Retries Safe with Idempotent APIs.” Amazon Builders’ Library。
- Alvidrez, Marc. “Embracing Risk.” Site Reliability Engineering,Google,2016。
- Norman, Don. “Human Error? No, Bad Design.” 2014。