拓冰建站拓冰建站
首页 / 资讯中心 / 正文

第2章 解剖一个 AI 烂项目:它到底是怎么一步步失控的

真正危险的项目不是满屏报错的项目。而是每个功能看起来都能用却没有人知道下一次修改会炸在哪里的项目。2.1 那个“很简单”的新需求周一上午九点十三分。林远打开 QuickCRM。周五离开办公室的时候他对这个项目还相当满意。客户列表可以用了。联系人可以用了。销售活动可以记录。标签、搜索、CSV 导入也已经完成。周末的时候他甚至又抽空让 代码x 加了登录功能。现在QuickCRM 已经不太像一个 Demo 了。它越来越像一个真正的 CRM。至少看起来如此。销售部门也很兴奋。他们试用了两天很快提出了第一个真正具有“企业软件味道”的需求“现在所有销售都能看到全部客户。能不能改一下每个销售只能看到自己的客户销售主管可以看到整个团队的”林远看到这句话时第一反应是很简单。无非就是增加一个角色再给客户加一个负责人。他把需求交给 代码x“给 QuickCRM 增加销售权限。普通销售只能查看自己负责的客户销售主管可以查看所有客户。”代码x 很快开始工作。它修改了用户模型修改了客户查询修改了客户列表又增加了几个权限判断。几分钟以后任务完成。林远登录普通销售账号。客户列表里果然只剩下自己负责的客户。再登录主管账号。所有客户都能看到。漂亮他甚至没有仔细看这次到底修改了多少文件。直到测试 CSV Import。导入完成以后新客户没有负责人。普通销售看不到刚刚导入的客户。主管能看到。林远把问题告诉 代码x。代码x 修改 CSV Import。再测。正常了。然后他打开客户详情页。输入一个别人的 客户 ID。页面打开了。普通销售虽然在列表里看不到别人的客户却可以通过 URL 直接访问。“修复这个权限问题。”代码x 继续修改。这次详情页也挡住了。林远顺手测试编辑接口。又发现普通销售可以直接调用更新接口修改别人的客户。继续修。然后是删除。继续修。然后是搜索。搜索结果里又出现了其他销售的客户。继续修。两个小时以后那个最开始看起来只有一句话的需求已经让 代码x 连续修改了很多次。但这还不是最麻烦的。真正让林远觉得不对劲的是他开始无法回答一个非常简单的问题。QuickCRM 的“客户访问权限”到底写在哪里是在客户列表里客户详情页API搜索接口CSV Import数据库查询还是每个地方都有一点他第一次没有马上继续说“帮我修。”而是打开项目目录一个文件一个文件往下看。十分钟以后他有了一种很熟悉、也很不舒服的感觉。这个项目没有坏。它甚至还能正常运行。但它已经开始变得危险。2.2 最可怕的不是缺陷而是你不知道缺陷会从哪里出来传统意义上的“坏项目”很容易想象。运行就报错。页面打不开。接口 500。数据库连接失败。这种项目当然有问题。但这种问题其实没有那么可怕。因为它会明确告诉你我坏了。真正麻烦的是 QuickCRM 现在这种状态。首页正常。登录正常。客户列表正常。新增客户正常。搜索大部分时候正常。CSV Import 也能跑。从业务人员角度看这个系统甚至已经“差不多能用了”。可是林远已经开始不敢随便改它。这是一种完全不同的失败。软件表面仍然工作内部却正在失去可预测性。我们可以把它理解成一个非常简单的变化。项目最开始的时候林远提出“增加搜索。”代码x 修改一个地方。完成。后来提出“增加客户标签。”修改两三个地方。完成。再后来“增加 CSV Import。”修改几个文件。完成。但到了“普通销售只能看自己的客户。”这个业务规则突然开始穿过整个系统。列表需要知道。详情需要知道。编辑需要知道。删除需要知道。搜索需要知道。CSV Import 需要知道。API 需要知道。甚至以后新增的任何客户相关功能也都必须知道。于是一个规则开始拥有越来越多的“副本”。这就是很多 Vibe Coding 项目真正失控的起点系统不是因为某一次代码写错而失控而是因为同一个意思开始以不同形式散落在越来越多的地方。每个地方单独看都可能是对的。组合起来却越来越难保证它们永远一致。2.3 QuickCRM 的第一次尸检林远决定做一件过去很少做的事情。暂时不让 AI 修改任何代码。他只让 代码x 分析。他把整个 QuickCRM Repository 交给它然后要求“不要修改代码。告诉我这个项目现在有哪些工程风险。”结果比他预想得严重。代码x 首先发现客户列表页面里直接存在数据访问逻辑。另一个页面也在自己查询客户。CSV Import 又实现了一套客户创建逻辑。普通表单创建客户时做了一次校验CSV Import 却没有完全使用相同的校验。客户权限在几个入口分别判断。有些入口检查了有些没有。有些地方发生错误会返回明确提示。有些地方直接抛异常。还有一些地方捕获异常以后什么都没有做。数据库 Schema 也留下了几次快速修改的痕迹。一些字段的含义已经和最开始不同但代码里仍然保留着旧假设。更麻烦的是很多修改没有对应的 回归问题 测试。也就是说今天修好的问题没有东西保证它明天不会再次回来。如果把这些问题单独列出来它们看起来都不是什么灾难。一个重复函数。一个写死的配置。一个没有统一的错误处理。一个漏掉的权限判断。一个越来越大的模块。一个没有测试保护的 缺陷 Fix。每一个都可以说“以后再整理。”问题恰恰就在这里。所有技术债最开始看起来都不像债。2.4 什么叫技术债这是本书第一次正式使用这个词。技术债技术债我们把它定义为为了当前速度采取的捷径未来需要用更高修改成本偿还。注意这个定义里有两个非常重要的词当前速度以及未来成本。不是所有“不完美代码”都是技术债。为了快速做一个一次性 Demo少写一些抽象层不一定是技术债。一个只有几十行的小工具把几个逻辑写在同一个文件里也不一定是技术债。甚至有时候刻意不做复杂设计反而是正确决策。只有当今天的捷径开始让未来的修改变得更贵它才真正变成债。QuickCRM 最开始把客户查询直接写在页面里。当时很快。客户列表半小时就出来了。如果这个页面永远不再变化这个决定甚至可能没有任何问题。但后来出现了搜索、权限、标签、CSV Import、主管视图。这时候“客户应该怎样被查询”已经不再只是某个页面的问题。过去节省的那一点时间开始以另一种方式回来。每增加一个规则都要重新寻找所有相关位置。每修改一次都担心漏掉某个入口。每修一个 缺陷都可能在另外一个地方留下不同版本的逻辑。这就是“还债”。而技术债最麻烦的地方是它有利息。2.5 技术债为什么会滚成雪球想象 QuickCRM 最开始只有三个功能客户 ListCreate 客户客户 Detail此时增加一个规则普通销售只能访问自己的 客户假设需要修改三个地方。问题还不大。后来系统加入SearchCSV ImportEditDeleteActivityDashboardExport如果访问规则没有形成统一边界那么同一个规则可能开始散落到十个地方。下一次规则改变“主管只能看到自己团队的客户总经理才能看到全部客户。”你需要重新确认十个地方。如果其中漏掉一个缺陷 出现。你修复。但修复时又复制了一段逻辑。现在不是十个地方可能变成十一个。再增加“离职销售的客户自动转给主管。”修改面继续扩大。于是项目出现一种非常典型的增长第一次捷径↓少量重复↓需求变化↓复制更多逻辑↓规则开始不一致↓缺陷↓局部修复↓产生更多特殊处理↓下一次修改更困难图2-1QuickCRM 技术债雪球这里有一个非常值得记住的规律技术债不是代码“难看”的问题而是变化成本不断上升的问题。代码写得不够优雅不一定影响项目。但如果一个小需求开始需要修改越来越多不相关的地方工程债已经在积累。如果一个 缺陷 每次修复都容易引入另一个 缺陷工程债已经在积累。如果你必须依赖“某个人记得这个地方很特殊”工程债已经在积累。如果 AI 每次修改之前都需要重新猜整个项目为什么这样设计工程债同样已经在积累。2.6 AI 为什么特别容易把技术债滚大这里必须说清楚一件事。这不是因为 AI “喜欢写烂代码”。真正原因更简单AI 天然擅长解决当前任务。你说“让搜索支持权限。”它会去解决搜索。你说“CSV 导入也要自动设置负责人。”它会去解决 CSV Import。你说“详情页也要限制。”它会继续解决详情页。从每一次任务来看AI 都在认真完成你的要求。问题是谁在负责发现这些任务其实属于同一个规则如果没有人做这件事那么 AI 很容易不断进行“局部正确”的修改。而局部正确并不保证全局正确。这正是 QuickCRM 最典型的状态。客户列表是对的。详情页修完也是对的。API 修完也是对的。CSV Import 修完也是对的。但是每个地方都拥有自己版本的“正确”。于是整个系统反而越来越脆弱。图2-2局部正确 → 全局失控局部任务 A → 正确局部任务 B → 正确局部任务 C → 正确局部任务 D → 正确↓规则重复边界模糊实现分叉修改面扩大↓全局越来越不可预测这也是为什么很多人会产生一个非常困惑的感觉“AI 每一次明明都修对了为什么我的项目还是越来越烂”答案就在这里。因为软件质量不是所有局部正确的简单相加。一个系统还需要保证这些局部之间不冲突、不重复、不泄漏、不产生不同版本的业务事实。2.7 “500 行代码写在一个文件里”只是最容易看到的问题很多人判断 AI 项目质量第一反应是看代码。看到一个巨型文件“烂。”看到函数很长“烂。”看到重复代码“烂。”这些当然值得警惕。QuickCRM 里也出现了越来越大的模块。一个文件同时处理客户查询、客户创建、权限判断、CSV 解析、数据校验、错误处理甚至还有部分 界面 状态。看起来非常像典型的“意大利面条代码”。但如果只把注意力放在文件长度上会错过更严重的问题。因为真正危险的工程债有很多根本看不出来。比如 Schema 漂移数据库里的字段经过多次快速修改代码不同位置对同一个字段已经产生不同理解。比如 权限判断 漏洞页面隐藏了按钮但某个服务入口并没有真正阻止操作。比如 重复逻辑同一业务规则有三个实现其中两个目前碰巧一致。比如错误处理不一致同一种失败有的地方返回业务错误有的地方抛异常有的地方静默失败。比如环境配置不规范本地能跑是因为某个值刚好存在于开发机器上。再比如没有 回归问题 测试某个 缺陷 今天已经修好但这个“修好”只存在于聊天记录和人的记忆里。所以一个项目是否失控不能只靠“代码看起来整不整齐”来判断。我们需要一种更系统的方法。2.8 不要急着重构先做 项目 CT看到这里很多工程师会产生一个冲动重构。看到重复代码抽函数。看到巨型模块拆文件。看到命名不好重命名。看到目录乱重新整理目录。先别做。这是 AI Coding 项目里另一个非常危险的习惯还没弄清楚项目为什么乱就让 AI 大规模“整理代码”。结果经常是代码看起来更漂亮了缺陷 也跟着被重新分布了一遍。在真正修改一个失控项目之前我们需要先知道它到底坏在哪里。本书把这个动作称为项目 CT项目 CT。定义是在不修改代码的前提下对项目结构、数据、依赖、接口、风险和技术债进行系统扫描。为什么叫 CT因为真正做 CT 的时候医生不会先把你切开。第一步是看清内部。软件也一样。在我们不知道问题分布之前大规模修改代码只是在黑暗里动刀。项目 CT 的第一条规则因此非常简单只扫描不修改。2.9 项目 CT 看什么为了避免把 项目 CT 变成一场漫无目的的“代码审查”我们把它压缩成六层。图2-3项目 CT 六层模型1. Structure项目结构2. Data数据3. Logic业务逻辑4. 边界权限 / 输入 / 接口边界5. Reliability错误 / 测试 / 配置6. Change 风险修改风险这里我们只学会看问题。怎么重新设计这些东西是后面章节的任务。第一层Structure问有没有越来越大的文件一个模块是不是承担了太多职责页面是不是直接承担了本应由其他层负责的工作同类功能是不是散落在不同目录不是为了评价目录漂不漂亮而是判断一次修改会不会被迫穿过很多不相关代码。第二层Data问同一个业务概念是否出现多种字段表达是否存在明显的重复数据数据关系有没有依赖代码“默认知道”Schema 的变化是否留下不一致痕迹这一层暂时不教你怎么画 ER 图。那是后面的内容。现在只需要识别数据是不是已经开始说不同语言。第三层Logic问同一个业务规则出现了几次有没有复制粘贴后稍微修改的逻辑不同入口是不是在做同一件事却有不同实现有没有大量特殊情况不断叠加QuickCRM 的客户访问规则就是典型问题。第四层边界问页面禁止的操作接口是否真的禁止输入是否在所有入口得到一致处理用户能不能绕过 界面 直接完成不该完成的操作模块之间有没有直接穿透彼此内部实现注意这里我们只识别边界缺失。身份认证、权限判断 具体怎么设计第6章再正式解决。第五层Reliability问错误处理是否一致配置是不是写死关键修改有没有测试保护一个已经修复的 缺陷 有没有可能再次出现这里也不展开测试方法。测试的正式主场是第7章。现在只问这个项目有没有证据证明“昨天修好的东西今天还不会坏”第六层Change 风险最后一层最重要。问如果明天修改一个核心规则你知道会影响哪里吗如果答案是“应该就两三个文件”这不算答案。如果答案是“让 AI 搜一下看看”也不算。真正要观察的是一个业务变化会穿过多少层、多少文件、多少入口。这就是项目是否已经开始失控的最直观信号之一。2.10 P02-01项目 CT 提示词现在我们终于可以让 AI 参与了。但注意这一次AI 的任务不是写代码而是诊断代码。这个 提示词 解决什么问题当你已经有一个正在开发的 AI Coding 项目却不知道它是否正在积累技术债时用它做第一次系统扫描。请对当前项目执行一次 项目 CT。重要规则现在不要修改任何代码不要重构不要创建新文件。请只分析并输出报告。从以下六个层面检查1. Structure- 巨型文件或巨型模块- 职责混杂- 页面直接承担数据或业务逻辑- 不合理的跨模块依赖2. Data- Schema 不一致- 重复数据- 字段语义漂移- 潜在的数据完整性风险3. Logic- 重复业务规则- 重复逻辑- 同一规则存在多个实现- 特殊情况不断叠加的位置4. 边界- 权限判断 缺口- 输入校验不一致- 界面 与服务端规则不一致- 模块边界被绕过5. Reliability- 错误处理不一致- 写死配置- Secret / 环境 风险- 缺少测试保护的关键逻辑- 已修复 缺陷 缺少 回归问题 测试6. Change 风险- 修改一个核心业务规则时可能影响的文件和模块- 高耦合区域- 最容易发生连锁回归的位置对每个问题输出- 问题位置- 观察到的现象- 为什么它构成风险- 严重程度Critical / High / Medium / Low- 未来最可能在哪类需求变化中爆发最后输出A. Top 10 Engineering 风险sB. Top 5 技术债 HotspotsC. 当前项目最危险的三个 修改面sD. 一句话项目健康结论再次强调不要修复。不要重构。只做诊断。AI 输出仍然需要人验收。它可能误判也可能漏掉业务背景。项目 CT 的价值不是让 AI 替你宣布“代码好不好”而是让它帮你把原本散落在几百个文件里的风险变成一张可以讨论的问题地图。2.11 QuickCRM 的 CT 报告林远让 代码x 按这套方式重新扫描 QuickCRM。这一次他不允许它改任何代码。扫描结束以后问题第一次不再以“一个 缺陷、一个 缺陷”的方式出现而是形成了一张地图。表2-1QuickCRM Q8 尸检摘要层发现风险Structure客户相关逻辑散落在页面、API、Import 等位置HighDataSchema 经多轮修改部分字段语义开始漂移HighLogic客户访问规则存在多个实现Critical边界部分入口存在 权限判断 缺口CriticalReliability错误处理不一致关键 缺陷 缺 回归问题 测试HighChange 风险修改客户权限会触达多个模块和入口Critical林远看着这张表突然明白了一件事。过去几天他一直以为自己面对的是很多不同的问题。CSV Import 有一个问题。搜索有一个问题。权限有一个问题。详情页有一个问题。数据库也有几个问题。但 项目 CT 把它们放在一起以后他第一次看到这些并不是十几个孤立的问题。它们其实来自少数几个更深层的原因。规则没有稳定位置。边界没有稳定位置。数据含义在变化。修改没有安全网。于是每一个新需求进入项目以后都在寻找自己“最方便落脚的地方”。久而久之整个系统到处都是落脚点却没有真正的中心。2.12 一个项目是怎样从“快”变成“慢”的现在回头看 QuickCRM 的发展过程会看到一条非常清晰的曲线。第一天新增一个功能20 分钟。第二天新增一个功能30 分钟。第三天新增一个功能40 分钟。看起来都很快。于是项目不断增加功能。但与此同时另一个数字也在悄悄增长每次修改需要理解的旧代码数量。最开始几乎是零。后来需要看两个文件。再后来五个。再后来十几个。直到某一天一个原本只需要一句话描述的需求需要修改、测试、发现回归、修复、再测、再发现另一个入口、再修。AI Coding 的速度没有变慢。代码x 生成代码甚至比以前更快。真正变慢的是项目吸收变化的能力。这就是技术债真正的利息。它不会让 AI 打字变慢。它会让每一次正确修改所需要的上下文越来越多让每一次修改的风险越来越高让每一次验证越来越困难。最终你可能拥有世界上最快的 Coding Agent却仍然觉得项目开发越来越慢。因为瓶颈已经不在代码生成速度而在系统还能不能安全地接受变化。2.13 一个非常反直觉的结论AI 越快越要早点体检过去人工开发时技术债往往积累得比较慢。一个工程师一天能写多少代码是有限的。一个错误结构即使正在形成也需要时间才能长大。AI 改变了这个速度。过去两周才能堆出来的代码现在可能两天。过去两个月才会出现的复杂度现在可能两个星期。这意味着一个很反直觉的结论AI Coding 不是让 项目 CT 变得不重要而是让它更早变得重要。项目还只有几十个文件时扫描很多问题很好处理。等到几百个文件、几十个模块、几万行代码以后再第一次问“这个项目到底是什么结构”成本已经完全不同。所以成熟的 Vibe 代码r 不应该只在项目“烂掉以后”做 CT。你应该逐渐养成一种新的习惯每当出现以下信号就停一下。一个 缺陷 连续修了三次。一个简单需求修改了大量文件。AI 开始重复创建相似函数。你已经不确定某个规则写在哪里。同一个功能在不同入口表现不同。AI 每次修改都需要重新解释大量背景。或者最简单的一种你开始害怕改代码。这时候不要继续加速。先扫描。2.14 但是CT 不是治疗这里必须划一条非常重要的边界。项目 CT 能告诉你哪里有问题、哪里风险最高、哪些地方可能已经积累技术债。但它不会自动告诉你整本书后面所有问题应该怎样解决。如果扫描发现“需求含义不清”第3章解决。如果发现“业务边界混乱”第4章解决。如果发现“数据和模块结构混乱”第5章解决。如果发现“权限、配置和工程规则没有边界”第6章解决。如果发现“缺陷 修完以后没有安全网”第7章解决。如果发现“本地正常但部署不可控”第8章解决。如果发现“修改以后无法安全回退”第9章解决。所以本章不要急着把 QuickCRM 修好。我们现在做的只有一件事看清它为什么会坏。这也是工程化最容易被忽略的一步。很多人认为工程师最重要的能力是解决问题。但面对一个复杂系统更重要的能力往往是先确认你解决的是哪个问题。2.15 林远第一次没有让 代码x“继续”项目 CT 完成以后代码x 给出了很多建议。拆分模块。集中权限。整理数据访问。统一错误处理。补测试。调整配置。如果是几天前林远大概会直接说“好的全部帮我优化。”但这一次他没有。因为他已经意识到如果连 QuickCRM 的需求边界、业务结构和核心规则都没有重新确认那么所谓的“全面优化”很可能只是另一轮更大规模的 AI 修改。代码可能更漂亮。目录可能更整齐。但系统未必更正确。他关闭了自动修改。然后打开一个空白文档。在最上面写下一句话“QuickCRM 到底要给谁用”接着是第二句“他们到底要完成什么”第三句“哪些规则绝对不能错”这一次他没有让 代码x 立刻写代码。因为他终于意识到QuickCRM 现在的问题不是缺一个更好的 提示词也不是缺一次更彻底的重构。它缺的是一些在第一行代码出现之前本来就应该被问清楚的问题。而这些问题恰恰是很多 Vibe 代码r 最容易跳过的地方。下一章我们就从这里开始。不写代码。先把一句“帮我做一个 CRM”变成一份 AI 真正可以执行、开发者真正可以验收的需求。现在就做给你的项目做第一次 CT如果你手上已经有一个 AI Coding 项目现在不要继续增加功能。花 20 分钟做下面四件事。第一运行 P02-01 项目 CT 提示词。明确告诉 AI只分析不修改。这是最重要的限制。第二只看 Top 10 Engineering 风险s。不要看到几十条建议就开始重构。先问自己哪三条最可能让下一次需求修改失败第三找出一个重复出现的业务规则。可能是权限。可能是金额计算。可能是状态判断。可能是数据校验。只记录它出现在哪里。今天不要修。第四回答一个问题如果明天老板要求修改这个规则我知道需要改哪些地方吗如果答案是否定的那么你已经找到第一个真正值得处理的工程问题。不要沮丧。能够看到技术债比继续假装它不存在重要得多。QuickCRM 的真正改变也不是从第一次重构开始的而是从林远第一次愿意停止写代码、认真看清项目内部开始的。先诊断再治疗。这就是 Engineering Vibe Coding 的第二步。
分享:

看完干货,该让你的企业上线了

免费需求沟通 · 48 小时内出具建站方案 · 河南本地可上门