Skip to content

工程经验如何传递,而不是让每个人重新踩坑? ​

在软件开发中,我们经常会遇到相似的问题。可能是 Excel 导入导出、文件上传,也可能是服务器配置、服务部署,或者某个业务系统的功能实现。

这些问题有时已经被其他开发人员解决过,但后来的人未必知道。即使是自己曾经处理过的事情,过了一两年,也可能因为忘记了当时的操作步骤或者设计原因,不得不重新查找资料。

我逐渐觉得,工程经验的价值不应该只停留在解决当时的问题。

已经积累的经验,如果能够被后来的人找到、理解,并且有办法验证,就可能减少下一次重复摸索的成本。

这里的后来者,可以是其他开发人员,也可以是几年后的自己。

一、一次 Excel 导入导出的经历 ​

1.1 已经实现的功能,其他人未必知道 ​

之前有一次,我看到一位同事需要开发 Excel 导入、导出功能。

我知道自己维护的一个教育业务系统(以下简称教育系统)中已经有相应实现,于是告诉他,可以直接去那个项目里复制代码。

当时我们没有把这部分能力封装成公共 JAR,但已有实现能够满足他的需要,因此不必重新编写基础功能。

后来,我发现他只复制了实现代码,没有复制对应的单元测试。

教育系统中的 Excel 功能原本就有单元测试(UT)。我向他演示了这些测试的作用,并让他把测试代码也复制到自己的项目中运行。

这件事让我想到,代码复用和工程经验传递并不完全相同。

如果只是复制实现代码,后来的人虽然得到了一个可以使用的功能,却未必知道原作者怎样验证它。

测试用例除了检查执行结果,还能够表达原实现所关注的输入、预期行为和异常情况。后续需要修改时,这些测试可以帮助开发人员了解原来的行为约束。

复制到新项目之后,仍然需要结合实际依赖、环境和业务要求进行验证。原项目有 UT,并不能保证新项目中的实现永远正确。

相比于只有一份实现代码,带有测试的代码能够提供更多可供理解和验证的信息。

1.2 这次复用为什么能够发生 ​

这次复用之所以发生,是因为我知道教育系统中有现成实现,而且恰好了解到同事正在开发类似功能。

如果没有这次交流,他可能会自行寻找其他方案。

在我们团队中,目前没有统一记录各系统已有基础能力的地方。开发人员需要某项功能,通常依靠相互询问了解是否存在类似实现。

也有人习惯先自己研究。

独立解决问题本身没有什么不妥。但如果团队已经积累了成熟的实现,开发人员却根本不知道它存在,那么重新研究就未必是必要的投入。

团队拥有某项实现,与团队成员知道它存在,是两件不同的事。

除了有人愿意分享,还需要考虑怎样让已有成果能够被其他人主动发现。

二、团队中的知识,怎样才能被找到 ​

团队内部的知识并不只有代码。

已有的基础功能、基础设施操作经验,以及业务系统的功能资料,都可能被后来的人重复使用。

它们适合采用不同的传递方式:代码需要明确位置与验证入口,基础设施需要操作说明,业务系统则需要帮助阅读者建立整体认识。

2.1 基础代码:先让别人知道在哪里 ​

不同业务系统之间,可能存在许多类似的基础需求,例如文件处理、接口封装和一些通用的工具方法。

遇到这些需求时,不一定要先建设公共组件。

公共 JAR 可以统一实现,但也会引入版本管理、依赖兼容和后续维护成本。如果只是少量系统需要某项能力,复制经过验证的实现,或者参考已有方案重新适配,也可能更合适。

因此,可以先解决一个基础问题:开发人员能否发现团队已经有哪些成果可以参考?

哪怕只有一份简单的索引,说明实现位于哪个项目、对应哪些代码、有哪些依赖和测试,也能够帮助后来的人判断是否值得复用。

至于是否进一步提取公共组件,可以根据实际复用频率和维护需求再作决定。

这里的目标不是要求所有项目使用同一份代码,而是让已经完成的工作能够成为下一次开发的参考。

2.2 基础设施:让常规操作有据可查 ​

除了代码,团队还会积累许多基础设施方面的经验。

例如宝塔面板的使用、OSS 接入、域名和 Nginx 配置,以及如何通过已有流水线部署一个新服务。

这些操作对于熟悉环境的人来说,可能只是日常工作。但对第一次接触的人而言,需要先了解服务器环境、配置位置、操作顺序以及验证方法。

如果没有可以查阅的资料,就可能需要其他同事重新讲解,或者自己从头摸索。

这类知识适合记录成相对简洁的操作文档,包含环境要求、配置入口、关键步骤、注意事项和验证方法。

涉及权限的操作,可以记录申请入口或负责人。账号密码、访问密钥等敏感信息则应通过受控的凭据管理方式提供,而不是直接写进普通操作文档。

这样,具备相应权限的开发人员就能先通过文档了解基本操作,需要帮助时再针对具体问题交流。

2.3 业务文档:让接手者能够先预习 ​

业务系统的功能文档,类似学生上课前的预习材料。

一个开发人员刚接触已有系统时,如果连系统主要负责什么、与哪些服务关联、有哪些核心业务流程都不了解,那么后续讨论代码实现就会比较困难。

如果接手者能够先通过文档了解业务概况,再与原维护人员交流,就不必从最基础的内容开始讲解。

这类文档可以保持轻量化。

例如,说明系统的主要业务、核心流程、相关服务,以及进一步查看技术资料的入口。没有必要把所有 Controller、Service 和数据库字段都罗列出来。

文档首先帮助读者建立整体认识。

至于复杂业务规则、历史决策和特殊情况,可以在读者提出问题后,再由了解系统的人补充。

这样,文档承担基础信息的传递,人与人之间的交流则用于解释难以理解的部分。

无论是已有代码的位置、基础设施的操作步骤,还是业务系统的功能概览,它们解决的都是同一个问题:让需要信息的人,能够先找到正确的入口。

三、个人知识库:把经验留给未来的自己 ​

3.1 过去解决过,不代表以后还记得 ​

工程经验的传递并不一定涉及其他人。

我平时会在个人知识库中记录一些软件安装、环境配置和操作方法,例如 Docker 的安装与使用。

这类记录通常不需要完整的文章结构。

可能只需要保存操作系统和软件版本、安装命令、配置文件位置、遇到的问题,以及最后确认可用的方法。

这些看起来普通的记录,对未来的自己仍然可能有价值。

几年之后再次安装同样的软件时,我未必还能记得当时具体使用了哪些命令、为什么修改某项配置。

如果没有记录,就可能重新查阅文档,甚至重复之前的试错过程。

个人知识库的作用,是为未来的自己提供一个已经实践过的起点。

3.2 记录的形式,应该由用途决定 ​

个人知识库主要是为了方便自己查阅,因此不需要每份笔记都写得非常完整。

一次简单操作,保存几条命令可能就够了。

一次复杂问题排查,则可能需要记录错误现象、环境信息、尝试过的方案和最终结果。

如果涉及容易遗忘的设计原因,还可以补充当时为什么选择这种处理方式。

记录不应成为额外的形式负担。

如果只是为了记住一条命令,却需要先写背景、分析过程和总结,反而可能让人失去记录的意愿。

对自己有用、以后能够找回,已经可以是个人笔记存在的理由。

部分个人记录在积累之后,还可能具备面向其他人的分享价值。

四、从个人记录到公开的工程经验 ​

4.1 从自己看得懂,到别人也能理解 ​

知识分享并不局限于公司内部。个人积累的经验,也可能对其他开发人员有参考价值。

我在小刘实验室 Docs 中公开过一些技术文章,其中一部分最初只是个人知识库中的记录。

例如:

《PageHelper 两种分页写法对比:一次泛型失真的排查与源码分析》源于实际遇到的分页问题。它值得整理的地方,不只是最终采用哪种写法,还包括问题如何复现、源码中的原因以及结论的适用条件。

《从 JPA + MyBatis 到 MyBatis-Plus:一次旧项目数据访问层的维护性收敛》则来自旧项目维护中的技术调整。仅知道最终选型,无法判断是否适用于自己的项目,还需要理解原有数据访问层的问题,以及为什么以维护性收敛作为主要目标。

这些内容最初记录在个人知识库中,后来经过整理,才逐渐变成公开文章。

对我而言,这相当于让经验传递的范围从自己扩大到其他开发人员,甚至是完全不了解原项目的陌生读者。

公开分享与个人记录之间,有一个明显区别。

个人笔记中,很多背景可以省略,因为我自己知道当时发生了什么。

公开文章则需要让读者理解:问题发生在什么条件下,为什么采用这个方案,有哪些证据支持结论,以及哪些场景不能直接套用。

只有这些信息相对完整,读者才有机会理解原作者的判断,并在自己的环境中验证经验是否适用。

4.2 代码能展示实现,却不一定能解释动机 ​

在整理工程文章时,我越来越重视一个问题:当初为什么这样设计?

因为代码能够展示程序最终做了什么,却未必能够回答原作者为什么作出某种选择。

例如,之前整理 Redis 缓存治理文章时,我们曾讨论过一个问题:

既然已经实现了类型化读取,为什么还要保留旧的 Object get 方法?

单看代码,很难确定真正原因。它可能是尚未完成迁移,也可能与历史兼容有关。

而我当时保留旧方法的实际原因,是需要兼容存量调用。

如果不知道这个兼容要求,就可能把旧方法的保留误认为重构没有完成。

这并不意味着所有历史设计都合理,而是评价一个设计之前,需要了解它在当时受到哪些约束。

代码能展示最终实现,却不一定能解释当时的设计动机。

工程经验中真正值得留下的,不只是最终实现,还包括影响方案选择的重要约束和判断依据。

4.3 AI 可以帮助整理,但不能替代事实来源 ​

现在,我也会使用 AI 辅助整理技术文章。

它可以阅读代码、检查文章结构、发现逻辑缺口,并根据已有信息提出需要进一步核实的问题。

沿用上面的 Redis 例子,AI 可以发现新旧接口并存这一现象,却无法仅凭代码确认旧方法为什么仍然保留。这时,就需要由了解实际情况的人补充原因。

我们逐渐形成了一种合作方式:先让 AI 从现有材料中发现疑问,再由了解情况的人补充真实背景,最后检查文章中的解释是否有足够依据。

对于能够通过源码、测试、日志或官方资料确认的技术事实,AI 可以协助核实。

但涉及历史决策、业务要求和当时的实际动机时,如果缺少可靠证据,就应该向了解情况的人询问,而不是自行补全。

这里需要区分三件事:已经确认的事实、基于事实形成的判断,以及目前还不知道的原因。

这不仅适用于 AI 写作,也适用于开发人员接手遗留系统时的分析工作。

代码只是工程历史的一部分,不能代替全部背景。

4.4 小众问题也值得留下记录 ​

有些技术问题只发生在特定框架版本、技术环境或旧系统的升级过程中,受众可能并不广泛。

但如果有人恰好遇到了类似问题,能够通过文章了解如何复现、怎样分析原因,以及最终方案为什么成立,这份经验就可能具有参考价值。

公开分享不一定需要追求很大的阅读量。

对我而言,能够把一次真实问题的解决过程记录清楚,本身也是知识积累。它既可以供其他人参考,也方便未来的自己重新审视当时的判断。

不过,公开分享仍然需要遵守必要的边界。

公司内部代码、业务数据、账号凭据和不适合公开的实现细节,不能直接从个人笔记搬到公开网站。

可以分享的是经过必要脱敏、具有独立参考价值的工程问题、分析过程与技术取舍。

五、知识分享也需要考虑成本 ​

5.1 不是所有问题都需要留下完整记录 ​

前面讲的是已有经验如何传递,这里还需要考虑哪些经验值得记录。

开发人员每天会处理很多问题。如果每解决一个问题,都要求整理一篇文档,那么记录工作也可能成为新的负担。

判断是否值得记录,可以考虑几个因素:

这个问题以后是否可能再次遇到?如果没有记录,重新调查需要多少时间?其中是否存在容易遗忘的关键条件?别人是否可能遇到类似问题?

一个简单、偶发、重新查阅也很容易解决的问题,可以不专门记录。

相反,有些问题虽然发生频率不高,但排查过程复杂、涉及多个系统,或者需要了解特定历史背景。这种经验即使只是留给未来的自己,也可能值得记录。

记录形式也不需要统一。

有些只需要几条操作说明;有些适合整理成团队文档;还有一些可以经过进一步核实,形成公开技术文章。

5.2 留下来的经验,还需要判断是否有效 ​

记录并不是一次性完成的工作。

例如,基础设施配置可能因为环境迁移而发生变化,技术文章可能因为框架升级而需要补充说明,已有代码也可能逐渐不再符合新的业务要求。

如果记录缺少版本、适用条件或者验证方法,后来的人可能无法判断它是否仍然可靠。

因此,文档应该尽可能保留必要的背景信息,而不是只给出一句“按照这个方法处理”。

但也不必要求每一份个人笔记都建立复杂的维护机制。

对于使用频繁、影响较大的团队文档,可以投入更多精力保持准确;对于个人的历史排障记录,则可以明确当时的环境和时间,让后来的人知道这是一次特定条件下的实践。

记录与维护的投入,应该与内容可能带来的复用价值相匹配。

5.3 让经验能够被使用,而不是只增加文档数量 ​

最初的 Excel 案例,只靠一次日常交流,就让已有实现和测试方法得到了复用。

这种日常分享本身就有价值。

但如果希望减少对偶然交流的依赖,团队可以尝试为已有成果提供简单的查找入口。

基础代码可以记录实现位置和测试入口;基础设施可以提供操作说明;业务系统可以保留功能概览及关联资料。

这些内容不必全部集中到一个庞大的平台中。

重要的是,当后来的人准备处理一个问题时,是否知道从哪里寻找已有经验,找到之后能否理解,并判断它是否适用于当前情况。

知识分享不是为了证明团队拥有多少文档,而是为了让已有成果在需要的时候能够发挥作用。

六、结语:让后来的人不必每次从零开始 ​

从最初的 Excel 导入导出经历,到日常的个人知识记录,再到后来整理发布的技术文章,我逐渐发现,工程经验可以通过不同方式传递。

分享代码,可以减少重复实现;分享测试,可以传递验证方法;分享文档,可以减少基础信息的重复讲解;分享工程判断,则能帮助别人理解方案背后的原因与限制。

这些方式没有固定的先后顺序,也不需要每个问题都全部采用。

值得记录的经验,应当根据实际用途选择适合的形式,并考虑整理与维护的成本。

经验不应该只是被保存。它还应该让后来的人有机会在已有成果上继续工作。