FDE Times 数据在招 FDE 职位 862▼55 近 7 天在招职位数的变化(同口径比较):不计入本周新开始追踪的公司的职位近 7 天新增 70在招公司 180支持远程 24%美国薪资中位数 $200k招聘最多 Palantir 95
ENVI

前线部署工程师(FDE)的专业媒体

书籍与课程

按这本 2004 年的书,FDE 接手的代码大多是遗留代码

Michael Feathers 的《修改代码的艺术》教你给没有测试的客户系统加上 AI 功能,又不弄坏正在运行的东西。

封面: Working Effectively with Legacy Code
Working Effectively with Legacy Code · Michael C. Feathers · 封面图片:Open Library
分享微博

要点速览

  • Feathers 把遗留代码定义为没有测试的代码,与代码写了多久无关。
  • 动手修改之前,先用特征测试记录当前行为。这类测试可以交给 AI 写,有些测试只需要临时存在。
  • 接缝是不必在原处修改就能改变行为的地方,LLM 就从这里接入。
改造前后对比图。改造前,routeTicket() 函数内部直接包含分配优先级的 if 链。改造后,routeTicket() 的路由逻辑保持不变,通过 PriorityClassifier 接缝调用。该接缝可接入三种实现:作为默认实现的旧 if 链、调用 LLM 的版本,以及测试用的 fake。特征测试始终保持通过。
分配优先级的代码被提取到 PriorityClassifier 接口中,并通过构造函数传入,由此形成一个接缝:默认实现原样保留旧的 if 链,调用 LLM 的版本按工单分组逐步启用;测试时,接缝接入的是 fake。旧的路由逻辑一行都不用改。来源:文中示例,基于 Michael Feathers 所著 Working Effectively with Legacy Code。

Michael Feathers 说,他最为人所知的是一个定义:遗留代码就是没有测试的代码。代码也许去年才写好,但只要还没有测试,它就是遗留代码。

按这个标准,前线部署工程师(FDE)在客户现场第一周打开的代码库,大多是遗留代码。而这份工作常常要求你给一个不是自己写的系统加上 AI 功能,比如用 LLM 汇总案卷或给工单分类。这个系统没人敢碰,客户也不允许它出问题。

所以,这本 2004 年出版的书值得每个想做 FDE 的人放在手边。书里只字未提 AI,却讲透了这份工作最难的部分:修改别人的代码,同时不破坏已经在运行的东西。

旧书能解决新问题吗?

Working Effectively with Legacy Code 由 Pearson 于 2004 年 9 月 22 日出版,属于 Robert C. Martin 系列(ISBN-13 978-0-13-117705-5)。出版社对这本书目标的概括是:帮助程序员应对接手的代码,而不必全部重写,因为重写代价极高。

这种思路与部署工作的现实相符。你很少会被邀请提议重写客户系统,更几乎不可能在几周内完成重写。你需要的是一种安全地逐步切入的方法。

有一个障碍最好提前知道。书中的示例用 Java、C++ 和 C# 编写,并默认读者能看懂 UML 表示法。如果你主要写 Python 或 TypeScript,就去读书里的思路,自己把示例换成熟悉的语言,而不是照抄代码。

观点一:缺少测试才是真正的风险

这本书的核心是写测试,确保修改不会意外改变程序行为。Feathers 说得很直白:没有测试,你就麻烦大了;有了测试,你就进入了“黄金地带”。

他最实用的建议是:不要试图用测试覆盖整个系统。在测试薄弱的代码里,只为即将修改的那部分写测试。对时间紧迫的 FDE 来说,这应当成为一条工作准则:测试跟着改动范围走,而不是跟着覆盖率指标走。

观点二:修改之前,先记录代码在做什么

假设客户有一个 Java 函数 routeTicket(),长达几百行,用一串基于关键词的 if 语句给支持工单分配优先级。客户希望用 LLM 替换这段优先级逻辑。第一步并不是调用模型。

第一步是拿一批真实工单跑一遍现有函数,然后写测试,断言它今天产生的确切输出,包括那些看起来像 bug 的结果。Feathers 把这类测试称为特征测试(characterization test),并说明它记录的是代码的当前行为,而不是正确行为。

Feathers 也认为这正是 AI 擅长的工作。他建议接受一点:有些测试是临时的,写出来只为理解代码或支撑某次修改,之后就可以扔掉。这样你就能让编码助手批量生成描述性测试,不用担心要永远维护它们。

观点三:找到接入 LLM 的接缝

书中最有价值的概念是接缝(seam)。Martin Fowler 引用过 Feathers 的定义:接缝是一个不必在该处修改代码,就能改变程序行为的地方。Feathers 把它比作衣服上的接缝,一个天然的断点,可以把一个组件换成另一个。

回到 routeTicket()。把优先级逻辑提取到 PriorityClassifier 接口中,通过构造函数传入。默认实现原样保留旧的 if 链,所有特征测试都保持通过。这就是你的接缝。

接下来,写第二个调用 LLM 的实现,接到同一个接缝上,按工单分组逐步启用。测试时用返回固定结果的 fake 替换它,测试套件就既不依赖模型,也不依赖网络。旧的路由逻辑一行都没改。

适合谁读,按什么顺序读

这本书适合有两到八年经验、曾经战战兢兢改过别人代码的开发者。先读 Martin Fowler bliki 上的 Legacy Seam 页面,理解这个概念;再细读书中关于给遗留代码写测试和关于接缝的章节。其余部分可以略读,遇到对应场景时再回来翻。

在 FDE 的岗位描述里,“与现有系统集成”“在客户代码库中工作”这类表述,说的正是这项能力。写简历时,可以讲一次你给没有测试的模块加新功能的经历:怎样写特征测试,接缝选在哪里,以及怎样做到什么都没坏。

模型每个季度都在变。客户现场那个没有测试、长达几百行的函数却会一直在那里,等着一个知道去哪里找接缝的人。

这篇文章对你有帮助吗?

3 个信源
路线图上的下一篇 · 阶段 2: 全栈工程能力DDIA 第二版:数据从本地磁盘搬到对象存储Kleppmann 与 Riccomini 保留了核心权衡,但讲清它们如今落在哪里,这决定集群扩容快慢和账单来源。