同一个坑踩第二遍的时候,你以为自己在进步,其实只是在重复。
这一页把 23 个真坑 按「死法」分类存成账本 —— 每一条都带现象、根因、对策、预防四段。
这一页的每一条都不是「网上看到的技术要点」,是 2026-10-02 用 AI 扫本地 100+ 个子目录的全部代码之后,对着grep 结果和文件实测逐条核对出来的。包括那些让我一度误判自己技术栈的坑 —— 比如我以为有 11 个项目在 tRPC、以为主栈是 MySQL+Drizzle,实测一跑:tRPC 只有 2 个真项目,全盘零 MySQL。
坑库的存在意义:把「我记得有个坑」变成「我知道第 47 号坑长这样」。延伸:基础 19 · 读懂 AI 代码 讲怎么验收 AI 给你的东西,这一页是它的一次完整实战。
经验总结是事后美化的:怎么做成的、有啥心得。踩坑记录是事前置的:下次遇到长这样,直接照着做。
| 对比 | 经验总结(我以前的做法) | 踩坑记录(现在) |
|---|---|---|
| 触发时机 | 项目做完了才写,一半靠回忆 | 当场记,四段齐全 |
| 内容粒度 | 「要注意并发问题」 | 「SQLite WAL 下两条写SQL 交叉执行会 BUSY,对策是改事务边界」 |
| 能不能复用 | 换个项目就得重新悟 | 复制粘贴,改两行 |
| 客户能不能看懂 | 看得出你想得多,看不出你能交付 | 看得出你真干过 |
| 面试官买不买账 | 半买半信 | 能追问细节,一问就露馅 vs 一问就答得出 |
按「死法」分类,比按技术栈分类有用 —— 同一个坑区里,现象长得几乎一样,根因却差很远。
| 坑区 | 典型死法 | 根因模式 | 是否已解决 |
|---|---|---|---|
| 认知偏差 | 以为自己技术栈是什么,实测不是 | 凭印象写文档,没对过代码 | ✅ 已用代码盘点纠正 |
| 认知偏差 | 接受了一个错的「行业惯例」 | 网上通用答案 ≠ 你的场景 | ⏸ 持续补充中 |
| 部署与进程 | 服务起不来、端口被占、重启雪崩 | 孤儿进程脱离监管 | ✅ 有标准处置流程 |
| 部署与进程 | 中文乱码、证书过期打不开 | 编码没统一 / 证书没续期 | ✅ 有巡检 |
| 数据 | 整库读不出来、97% 字段是空的 | JSON blob 塞行内 + 采集没做 | ⚠️ 部分(债还在) |
| 生产变更 | 改生产系统改出事故 | 没备份、没预览、没只读诊断 | ✅ 制度化了(红线) |
| AI 协作 | AI 生成的图结构错、代码没测试 | 没验收标准就采信 | ✅ 四步验收法 |
| AI 协作 | 派出去的 agent 把文件写错目录 | 没给绝对路径 + 没声明目标目录 | ✅ 已有强制约束 |
这一类最阴,因为它不报错,只是让你在错误的前提上继续决策。
| 编号 | 现象 | 我当时的判断 | 实测真相 | 对策 / 预防 |
|---|---|---|---|---|
| 01 | 「我做了 11 个项目用 tRPC」 | 以为 tRPC 是主力 | 真实只有 2 个(delimao-system、shower-order-p3),其余是 grep 字符串误命中 | 计数必须限定文件类型(ts/tsx)并人工看一眼 package.json |
| 02 | 「主栈是 MySQL + Drizzle」 | 写进了个人简介 | 全盘零 MySQL / 零 PostgreSQL,只有 SQLite 家族 + Drizzle | 文档栈和实测栈必须分开记,每年代码盘点对冲一次 |
| 03 | 「Express 用了 36 个项目」 | 觉得自己很全栈 | 命中 85 个文件,真项目 13 个 | 命中数 ≠ 项目数,要按仓库去重 |
| 04 | 「我做过 PostgreSQL 迁移」 | 简历里当亮点 | 只有 schema.ts 末尾的迁移预案注释,一行代码没迁 | 预案和现状要写清楚,承认是预案比含糊过去值钱 |
| 05 | 「我有 7 个系统在跑」 | 口头盘点 | 文件实测后只有少数几个有完整链路,其余是脚本集合 | 系统清单从目录结构读,不从记忆读 |
| 编号 | 现象(线上长什么样) | 根因 | 对策 | 预防 |
|---|---|---|---|---|
| 06 | PM2 里几十个 God Daemon,内存吃光,应用全部 PPID=1(孤儿) | 早期反复 pm2 start 且没 --save,重启后进程树错乱 | 先 kill 掉重复 daemon,再 pm2 resurrect 从 dump 恢复 | 启动时必带 --save;改配置前先看 pm2 list |
| 07 | 端口 address already in use,服务无限崩溃重启 | 孤儿进程仍占着端口,新进程抢不到 | 先按 PID 查是哪个进程占端口,杀掉再起(不要再 try 重启) | 部署脚本启动前先做端口占用探测 |
| 08 | 站能打开但 https 000 / 301 → 死链 | 宝塔签发的 Let's Encrypt 证书过期,nginx SSL 握手失败 | 宝塔面板续签,或 certbot renew 后 nginx -t 再 reload | 证书到期前 7 天巡检一次 |
| 09 | 中文文件名/中文内容乱码 | Windows 下 shell 传中文路径编码不一致 | 文件名一律 ASCII;需要中文内容时走文件写入工具不走 shell 传参 | 部署文件命名规则:全 ASCII |
| 10 | 子站 SPA 全站打不开、爬虫不收录 | 证书过期连锁 + 纯 JS 渲染,服务端无正文 | 证书修复 + 预渲染静态正文块 | 见坑 15 |
| 11 | 传了 14 个文件上服务器,线上还是旧版 | 只传了 html 没传 css,浏览器缓存旧样式 | 传完立刻 curl 量字节数对比;css 版本化或加 query | 部署后必跑 curl 校验,见坑 20 |
| 编号 | 现象 | 根因 | 对策 | 预防 |
|---|---|---|---|---|
| 12 | 整库读不出来,所有查询报空 | collections 表是单行 JSON blob,一个字段写坏整行 JSON 解析失败,库没坏但数据全丢可读性 | 拆行 + 关键字段独立成列;导入前先做 JSON 合法性校验 | 热点数据不许塞 JSON blob,这是设计红线 |
| 13 | 统计出来「型号匹配 96.6%、客户匹配 0%」 | 分母不一致:型号有值,客户 ID 压根没关联上 | 三个口径分开统计:有单 / 有字段 / 有价格 | 覆盖率永远报「分子/分母」,不报裸百分比 |
| 14 | 400 单里 97% 的 spec 是 null 或「否」 | 门店下单时尺寸靠口头传,没进系统 | 先做采集(让录入必填关键字段),再谈算法 | 见坑 13 的配套:数据不够就报「算不了」 |
| 15 | 官网 84 个 URL 给爬虫只返回 3120 字节空壳 | React SPA 纯客户端渲染,服务端 HTML 里没正文 | 预渲染静态块(#root 外持久 h1 + meta + OG + JSON-LD) | robots.txt 早就配对了,根因不在 SEO 配置——差点白白改错地方 |
| 16 | 玻璃图纸导出中文渲染成方块 | 服务器无中文字体,或渲染引擎字体路径没指定 | 服务端装字体 + 渲染时显式指定 font-family | 导出功能上线前用中文字符串跑一遍 |
| 17 | 报价算出一个「看起来很精确」的错价 | 空字段被默认值填平了:没客户 ID 就按「平均客户」算 | 校验函数三态:算得出 / 算不出要补数据 / 数据本身错 | 「算不了」是合法输出,不许猜 |
| 编号 | 现象 | 根因 | 对策 | 预防(已制度化) |
|---|---|---|---|---|
| 18 | 「我先改一下看看」→ 生产库被改坏,回滚都难 | 没有备份、没有预览、直接上手 | 备份 → 精确替换 → 预览 → 确认 → 生效 | 生产变更先只读是红线第三条 |
| 19 | 部署技能里「只传变动文件」跳过 css,导致样式没更新 | 缓存判定靠文件时间戳,跨机器不同步 | 变动文件 + 依赖文件一起传;传输后核对字节数 | 部署 skill 里固化「传完必校验」 |
| 20 | 传完 14 个文件,不确定线上是不是新版 | scp 返回成功 ≠ 内容一致 | curl -o /dev/null -w "%{http_code}:%{size_download}" 逐个量 | 每次部署后必跑,见 模块 01 · 服务器托管 |
| 编号 | 现象 | 根因 | 对策 | 预防 |
|---|---|---|---|---|
| 21 | 派 4 个 agent 写文档,全部写进了错误的工作区 | prompt 里没给绝对路径,agent 用默认工作目录 | prompt 必写目标目录绝对路径 + 显式声明「写入 X」 | 派发清单里,「写到哪个目录」和「写什么」同等权重 |
| 22 | 新页面出现两个 class="on",导航高亮错乱 | agent 复制基准页时把兄弟页的选中态一起抄了 | 交付前 grep class="on" 计数,必须恰好 1 | 写进验收脚本,见 基础 19 |
| 23 | 顺手就能改的 skill / lock 工具调用失败,卡住整个流程 | 工具在当前环境不可用,没降级方案 | 降级:把方法写进工作记忆,用文件持久化代替 | 任何依赖外部工具的动作,先想好「工具废了怎么办」 |
坑 21 让我掉了一次大坑:4 篇文档写到了别的目录,最后靠 cp 合并才救回来。这次之后,我给 agent 的每条 prompt 里,「目标绝对路径」是强制项,不是建议项。
一条坑只有写全这四段,下次才救得了你。缺一段,就退化成「我记得有件事」。
| 字段 | 要写什么 | 反面例子 |
|---|---|---|
| 现象 | 线上当时长什么样,越具体越好(报什么错、字节多少、几个进程) | 「并发有问题」 |
| 根因 | 落到机制层:为什么会发生,不是「因为没注意」 | 「因为我不小心」 |
| 对策 | 当时怎么救的,可执行步骤 | 「重新部署一下」 |
| 预防 | 下次产出前自动带上的动作(写进 skill / 红线 / 校验脚本) | 「下次注意点」 |
完整可复制版本在 交付物模板库 · 坑库条目模板。
一个坑库只写「已解决」是广告,写「还没解决」才是账本。
| 坑 | 状态 | 为什么还没修 | 什么时候会修 |
|---|---|---|---|
| JSON blob 崩库(坑 12) | ⚠️ 设计债 | 拆表要重跑历史数据 + 改写入路径,得腾一个完整窗口 | 等下一个改库窗口,或接手新项目时顺带重构 |
| MySQL / PostgreSQL(坑 02) | ⏸ 只写了预案 | SQLite 单机扛得住当前数据量,换库是纯成本 | 出现「多台机器要读写同一库」时才换 |
| 测试几乎为零(坑 26 后续) | ⏸ 已知短板 | 一个人的项目优先级永远是交付,测试排不进节奏 | 按「先补出过事的地方」推进,见 技术短板 · 测试从 0 到 1 |
| 图表库为零(坑 28 后续) | ⏸ 已知短板 | 现阶段用服务端出静态图够用,引前端图表库反而是负担 | 要做「客户能自己筛选」的看板时再补 |