Skip to content

Engineering Guides

51hhh edited this page Sep 16, 2026 · 1 revision

工程思维指南

大多数 bug 和技术债来自「没想到」,不是来自能力不足。

  • 没想到层边界会发生什么 → 跨层 bug
  • 没想到这个模式会重复 → 到处是重复代码
  • 没想到边界情况 → 运行时错误
  • 没想到后来维护的人 → 读不懂的代码

这一页的作用是在写代码之前问对问题。核心信条:30 分钟的思考省下 3 小时的调试。

什么时候该停下来想

跨层思考的触发条件

  • 功能涉及 3 层以上(IPC、领域模块、组件、数据库)
  • 数据格式在层之间发生变化
  • 多个消费者需要同一份数据
  • 你不确定某段逻辑该放哪一层

代码复用思考的触发条件

  • 你正在写和已有代码相似的东西
  • 同一个模式重复出现 3 次以上
  • 你在给多个地方添加同一个字段
  • 你正在修改任何常量或配置
  • 你正在创建新的工具/辅助函数 ← 先搜索!

修改前铁律

改任何值之前,先搜索。

grep -r "value_to_change" .

这一个习惯能防住绝大多数「忘了改 X」的 bug。


代码复用

重复代码是不一致性 bug 的第一来源。 复制粘贴或重写已有逻辑会导致:bug 修复不传播、行为随时间分叉、代码库越来越难理解。

写新代码之前

先搜索,再问四个问题:

问题 如果是
已经有类似函数了吗? 用它或扩展它
这个模式别处用过吗? 跟随已有模式
这能不能是个共享工具? 放到正确的位置去创建
我在从另一个文件抄代码吗? 停 —— 抽取成共享的

什么时候抽象

该抽象:同样代码出现 3 次以上;逻辑复杂到会有 bug;多人都需要。

不该抽象:只用一次;trivial 的一行;抽象本身比重复更复杂。

一个真实陷阱:不对称机制产出同一批文件

问题:当两种不同机制必须产出同一批文件时(例如初始化用递归目录复制,而更新用手工逐条列举),结构性变化——重命名、移动、新增子目录——只会通过自动机制传播,手工那条会静默漂移。

症状:初始化完全正常,但更新把文件建到了错误路径,或干脆漏掉。

预防:

  • 迁移目录结构时,搜索所有引用旧结构的代码路径
  • 如果一条路径是自动推导(glob/copy)而另一条是手工列举,手工那条需要同步更新
  • 加一个回归测试,比较两种机制的输出

批量修改之后

  1. 复查:所有实例都改到了吗?
  2. 搜索:跑一遍 grep 找漏掉的
  3. 考虑:这是不是该抽象了?

跨层思考

大多数 bug 发生在层边界,不在层内部。

典型跨层 bug:接口返回格式 A 而消费方期待格式 B;存储层存 X、服务层转成 Y 但丢了数据;多个层用不同方式实现同一逻辑。

第一步:画出数据流

来源 → 转换 → 存储 → 取出 → 转换 → 显示

对每一个箭头问:数据是什么格式?可能出什么错?谁负责校验?

第二步:识别边界

边界 常见问题
IPC ↔ 领域模块 类型不匹配、字段缺失
领域模块 ↔ 数据库 格式转换、null 处理
后端 ↔ 前端 序列化、时间格式、字节数组 vs 字符串
组件 ↔ 组件 props 形状变化

第三步:定义契约

每个边界都要明确:精确的输入格式、精确的输出格式、可能发生的错误。

三个典型错误

隐式格式假设 —— 不检查就假定格式。应在边界做显式转换。

分散校验 —— 在多个层校验同一件事。应在入口处校验一次。

泄漏的抽象 —— 组件知道数据库 schema。每层只该知道它的邻居。

跨层功能清单

实现之前:

  • 画完了完整数据流
  • 识别了所有层边界
  • 定义了每个边界的格式
  • 决定了校验发生在哪里

实现之后:

  • 用边界情况测过(null、空、非法)
  • 验证了每个边界的错误处理
  • 检查了数据能完整往返
  • 对自写自读的格式,验证了写入方产出的每种产物都被同版本读取方接受
  • 显示/预览表示与 canonical 可编辑源、坐标系是分开的
  • 显式定义了部分成功的语义(例如文件已提交但剪贴板投递失败)

最后三条来自实际踩过的坑,值得单独说:

  • 自写自读格式最容易出的问题是 writer 比 reader 宽松,产出一批自己读不回来的文件
  • 把预览表示当作编辑源,会导致重复编辑逐次退化(例如效果类工具采样已绘制的画布而非原图)
  • 「部分成功」不定义清楚,用户就会看到「保存失败」但文件其实已经写出去了

何时写流程文档

  • 功能跨 3 层以上
  • 数据格式复杂
  • 这个功能以前出过 bug

新增的跨模块约定要写进 docs/architecture.md,否则下一个改这块代码的人会再踩一次。


把新教训写回来

发现了新的「没想到」时刻,就补充到这一页。这些清单的价值全部来自真实事故——保持它增长。

相关页面

Clone this wiki locally