免费获取学习方案
ARTICLE DETAIL

资讯详情

深耕编程基础知识与建站技术分享的一线实战洞察。

代码评审中如何识别和删除没用的功能

代码评审中如何识别和删除没用的功能 在代码评审里我几乎每次都会遇到一个让人头疼的问题某个功能看起来一点用都没有但真正把它删掉的时候总有人跳出来说不行。前阵子我处理一个编号为149的遗留功能提交信息写着“新增打点功能”代码量不大但半年过去没有任何显式调用方。按直觉这就是一个典型的“没用的功能”。不过当我顺着 git 历史、日志和配置文件重新走了一遍才发现它其实是某条旧链路的重要补偿逻辑只是触发条件很少见。那次之后我就不太敢用“没用”两个字给功能下结论了。“没用的功能”更像是一个需要被验证的判断而不是一眼能看出来的事实。功能之所以被误判往往不是因为代码质量差而是因为我们对它的历史、场景和成本了解不够。这篇博客会从一个真实代码评审场景出发讲清楚功能为什么会进入“没用”的状态再给出一套判断方法、删除流程以及什么情况下应该保留甚至重新设计。1. 先搞清楚功能为什么会进入“没用”的状态1.1 历史演进留下的“时间胶囊”几乎每个老项目都是时间堆积出来的。功能在某个阶段可能是整个系统的核心路径但随着业务调整、架构升级、交互改版它逐渐从主流程退到角落里。比如旧版系统需要兼容某些客户端版本新版系统已经不需要了但兼容代码还在。又比如某个接口早期是内部服务之间的主通道后来消息队列替换了它接口变成空壳。这些“时间胶囊”看起来没用但它们是系统演进过程的一部分删除之前必须搞清楚它当初解决过什么。我在处理这类功能时第一个动作不是删代码而是查提交记录。有一次看到一个接口已经半年没有任何业务代码调用但 git history 显示它曾在一次大促压测中支持过一个特殊限流规则。如果把接口直接删掉当天的监控面板和降级脚本就全部失效。所以“历史遗留”不能简单理解为“过期垃圾”它需要拆开看是这段逻辑不再需要还是另一个系统还在默默依赖。1.2 防御式设计埋下的“预备功能”开发时为了应对可能到来的需求我们往往会提前写一些功能模块。比如预留了多语言配置、预留了批量处理、预留了多种判断分支。有些时候这是合理的但更多时候需求没有来模块就永远停在“已经写完但从未使用”的状态。这类功能的问题在于它看起来像是有意设计但又没有真实使用场景维护者通常不敢动它。因为代码里有注释写着“未来可能支持”但没有人知道“未来”具体是哪一天。最稳妥的办法是在预埋时就写清楚“我们为什么预留它预计谁会用触发条件是什么”。如果没有这些说明它就会变成最典型的一种“没用的功能”。实际上很多“预备功能”真正的问题不是无用而是它制造了模糊性。它把决定权留给了未来却没有给未来留下判断依据。于是后面接手的人只能继续猜继续不敢动功能就在灰色地带里一天天腐烂。1.3 过度抽象制造的理解成本还有一种情况很常见为了让代码“更通用”我们设计了一套复杂抽象结果真实项目里只需要一个简单的实现。比如一个功能可能只需要一个函数但为了应对未来的多种“策略”我们引入了策略模式、配置文件、动态加载。这样做的后果是功能表面看起来很多真正被使用的只有一个分支。其他分支就成了没人敢碰的“功能遗迹”。这类问题的本质不是功能没用而是抽象过度。它在没有足够复杂度的前提下制造了额外理解成本让新人很容易把分支看成无用代码。我曾经维护过一个“多通道通知”模块里面配置了短信、邮件、站内信、App 推送四种通道实际上公司只用了邮件和站内信。另外两种通道没有任何配置和调用方但它们占用了大量代码位置还让测试报告看起来必须覆盖四种通道。这种情况下删掉一个分支也许是对的但更本质的问题是当初为什么会有人基于错误的假设做抽象如果只是删代码而不纠正设计约束类似的“无用分支”很快又会回来。1.4 文档和沟通断裂导致“名存实亡”也有不少功能明明在跑但没有文档解释它为什么要跑。系统里埋了一个定时任务每天凌晨清理数据但没有任何注释说明这个任务对应哪条业务规则。后来业务方换人了新同事看不懂这个任务就把它标记成“没用的功能”。这类情况里功能本身可能还在产生价值只是价值没有被捕捉到。我曾经遇到一个清理临时文件的脚本代码里只有一个函数名没有任何注释。后来一查日志发现它每天都在运行并且会删除过期超过三十天的临时文件。如果只看代码会以为它毫无意义但结合存储成本和合规要求它反而是系统里不能缺的兜底逻辑。所以“没用的功能”有时不是真的无用而是我们对它的认知已经断层了。2. 给“没用的功能”做一次系统诊断2.1 判断之前先画出调用链和触发路径“没被调用”是大家说一个功能没用时最常用的理由但它很容易骗人。一个功能可能没有被直接调用却通过配置文件、反射、动态路由、定时任务、消息队列订阅等方式间接运行。也可能它确实不被调用但它是另一个正常功能的数据依赖。所以第一步不是问“它有没有被调用”而是把它周围所有可能的入口列出来。我会先把代码里对应的函数名、类名、配置项和资源路径全部搜一遍再看数据库表、缓存键和消息主题里有没有历史数据记录。一个通用的搜索示例长这样# 在项目里搜索包含功能标识符的引用示意 grep -rn 149_feature --include*.py --include*.js --include*.config .如果代码层面完全没有引用而线上日志和数据库中有执行痕迹那它就有真实触发场景。这个时候就不能简单说它是“没用”的。2.2 看日志、看指标、看数据落表比代码更接近真相的是运行数据。一个功能如果被运行通常会产生日志、修改数据库或调用第三方服务。哪怕半年才触发一次在日志里也会留下痕迹。我会先在大盘里搜功能标识符再翻链路追踪、告警平台和任务调度平台。只要找到一次真实触发记录就能说明这个功能没有被世界完全遗忘。如果没有触发记录也不代表删除一定安全还需要结合设计意图判断。这里有一个容易踩的坑很多人只看应用日志忽略中间件日志。比如一个功能可能没有自己的日志但它会写入 Redis、MySQL 或 Elasticsearch。如果只搜应用日志很容易漏掉真实痕迹。所以我在做诊断时给自己定了一个顺序先搜代码引用再搜应用日志再搜中间件数据最后问业务方。这个顺序能最大程度减少盲区。2.3 问产品、运营和少数知情用户有些功能不是给普通用户用的而是给管理后台、客服、风控、运营人员用的。这些功能可能触发频率极低但一旦触发都是核心操作。比如一个“数据修复工具”、一个“手工对账入口”代码上看起来很久没人用但运营团队每周都会使用。只看代码提交时间会被误导。所以遇到可疑功能我会先拉出功能日志的分位数再去找相关业务方确认。这个确认动作不能省因为很多后台功能没有埋点代码里也没有调用链只能靠人来回答“这个东西你还在用吗”。我一般会问三个问题这个功能你最近一次使用是什么时候如果它消失你的工作流程会不会中断你当初是怎么知道有这个功能的回答往往比代码更能说明问题。2.4 回到设计文档、PRD、issue 和 git 历史每个功能背后都应该有原始设计意图。翻看 git blame、提交说明、关联的 issue 或 PRD可以知道它是什么时候加入的、为了解决什么问题、当时有哪些替代方案。有些功能是线上故障的临时修复有些是合规要求有些是某个大客户的定制需求。一次真实的排查经历是这样的我在代码里看到一个没有入口的“数据核对”方法搜索无果后去看 git log发现它是在一次线上资损风险复盘后新增的目的是每日校验账单金额是否一致。需求方把功能做进去了但上线后没做推广所以一直没人调用。后来我把这个方法接到新的对账流程中反而解决了一个长期存在的重复劳动。这个功能并不是没用只是没有被正确连接起来。2.5 用“功能价值档案”分类而不是简单打标签基于上面这些信息我会把功能划分为四种状态状态判断特征典型示例处理方向真没用无调用链、无运行日志、无设计意图、删除后无影响某个已经被新方案取代的旧工具函数删除并留档过期后遗症曾经服务于某个已结束的业务或版本但没有清理干净只兼容旧版本客户端的接口短期保留标记废弃下个版本移除低频高价值调用频率很低但每次调用都关系到核心业务或应急恢复应急恢复脚本、冷门合规操作保留补充文档和测试完善监控备用触发平时不运行只在特定配置、开关或异常路径下触发数据修复任务、灰度分支、降级逻辑保留明确触发条件增加告警和日志这张表的好处是它把“有没有用”这个粗暴二分问题变成了“功能正在哪个生命周期”的问题。真没用可以删过期后遗症需要计划删除低频高价值应该被好好保护备用触发必须设置可见性。处理方式完全不同。2.6 给每个功能做一个风险评分在确认分类后我还会做一次综合评分。从五个维度打分每个维度1到5分调用频率完全无调用为1高频调用为5。影响范围影响数据一致性为5只影响显示文案为1。维护成本需要单独维护依赖和配置为5无外部依赖为1。业务价值核心合规、资金、安全相关为5锦上添花为1。删除风险有隐式调用、缓存、反射、外部依赖为5自行可控为1。如果业务价值和删除风险都很高那就不能简单删除应该优先补测试、补观测。如果两者都很低才考虑“真没用”的判定。评分不是算法而是一个把所有信息摆到台面上的手段。注意评分低不代表一定可以删还要看有没有人依靠这个功能完成书面流程。很多管理功能虽然调用少但它们是合规流程的一部分删除前必须和流程负责人确认。3. 确认无用后如何安全地删除一个功能3.1 删除前先做“功能留痕”不要只留下一段 commit message即使已经判断它为真没用我还是会先建一个“功能档案”。把功能入口、历史用途、删除理由、关联 issue、负责人、影响面都写清楚。这个档案可以放在仓库里也可以放在项目文档里。不要小看这一步很多删除后返工都源于后来者不知道我们为什么删。删掉一个功能不难难的是让下一代维护者理解“为什么它不该存在”。留痕的意义不只是记录历史更是减少未来重写同款功能的概率。否则半年后另一个新同学会在代码库里惆怅这个逻辑好像很眼熟是不是我们曾经用过3.2 用“冻结-观察-删除”三步而不是直接删代码我的推荐流程是这三步冻结先把功能入口注释掉或者用一个全局开关把它关掉。不删除代码。观察跑一个完整回归并观察预发或线上环境的日志、监控、告警。通常观察一到两个版本周期或者至少一周。删除确认没有异常后再删除代码和相关配置。如果这一步出问题回滚也比较快因为前两步还没有破坏代码结构。这里很容易犯的错是“先斩后奏”直接删完等下个版本发布后才发现某个报表数据不更新了。实际上用开关关掉功能与直接删除在运行时很多时候是等价的但它在代码层面仍然可控。我喜欢把删除看成一次发布而不是一次顺手清理。3.3 最容易误判的三个隐藏依赖删除一个看似无用的功能时最怕遇到“隐藏依赖”。我从实际项目中归纳出三类高频问题反射与字符串调用有些框架会通过反射调用方法代码里搜不到直接引用。比如 Spring 的 bean name、Python 的 getattr、Java 的 Method 反射都可能在运行时才解析字符串。搜索的时候要覆盖配置文件和注解不只是函数名。缓存与消息队列残留功能被删除后队列里可能还有旧消息消费方一旦找不到对应处理逻辑就可能报错。清理代码之前要先看目标消息主题里还有多少延迟消息必要时先清理队列或做消息版本兼容。外部系统约定功能可能不是给自己用的而是给下游系统用的。它虽然内部没有调用方但下游会定期请求。删之前要确认对外接口文档、网关路由、合作伙伴联调文档里有没有残留记录。3.4 如果删完才发现问题怎么办一旦发现线上异常最重要的不是马上还原代码而是先判断是不是这个功能造成的。看报错栈、看功能开关状态、看消息队列积压确认因果关系后再去恢复。如果保留了功能开关恢复就是一瞬间的事如果已经删除代码就得从上一个版本回滚或者把删除前保存的代码恢复出来。所以删除前保留一个分支或一个压缩包是成本很低但收益很高的习惯。不要以为“没被调用”就等于“没有依赖”。很多功能是被“隐藏调用”的尤其是动态语言项目反射、装饰器、事件监听和任务队列都可能让调用关系变得不可见。3.5 删除后还要做一次全链路验证删除不只是一个“删代码”动作还要在发布后检查启动日志里有没有类找不到、方法找不到的报错。页面和接口有没有回归失败。定时任务和消息消费者有没有因为缺失配置而中断。数据任务是否仍然能正常产出报表。把这一步做成发布检查清单能避免很多“以为删干净了结果第二天才炸”的情况。我会在发布单里把要核对的日志关键词、监控面板和数据报表名称全部列出来发布后逐项确认并保留至少一天的观察窗口。4. 不要急着删先想想它能不能被重新设计4.1 很多“没用”是上下文断裂不是功能没有价值刚才说了一大堆判断和删除方法但还有一种更关键的情况这个功能不是真的没用而是我们丢失了它存在的理由。比如一个很小众的导入功能可能是财务月底导入对账单用的一段很少有人走到的前端分支可能是为了兼容某个特定浏览器版本。如果我们因为看不到理由就直接删除可能会把重要业务的兜底逻辑一起删掉。更聪明的做法是先把功能本来要解决的问题定义清楚再决定是保留、删除还是重新设计。我第一次意识到这件事是因为一个“看起来根本没人用”的导出按钮。后来才知道它是客服人员处理投诉时必须用的证据导出功能。对普通用户来说它确实没用但对特定角色来说它就是核心工具。4.2 把可疑功能改造成“被解释的功能”与其留一堆没有说明的代码不如花半天时间做一次“功能体检”。对每个可疑功能写一个简短说明它为什么存在、在什么条件下触发、它依赖什么数据、它输出什么结果、如果删掉会有什么风险。这个说明可以放在文件头、README或者仓库的 archive 目录里。我一般会把说明写成一个小卡片## 功能149 打点逻辑 - 状态保留 - 原因兼容旧客户端的登录回传当前仅在小流量下触发 - 触发条件客户端版本号 2.4 且允许统计上报 - 删除计划待旧客户端整体下线后移除预计 2026 Q1 - 负责人平台组 / 张三只要把一个功能解释清楚“没用”的比例就会下降很多。因为绝大多数维护者并不是真的觉得它没用而是不知道该怎么用它。一份好的功能档案远比一行注释更能避免“误删一个重要功能”。4.3 建立“功能审计”机制而不是等问题爆发与其每次遇到可疑功能都临时考古不如定期做一次审计。建议每季度或每个大版本前用脚本或表格盘点一次功能清单把主仓库里所有对外暴露的功能、接口、任务、配置项都列出来。调用频率拉取日志平台最近一个季度的调用量。维护状态看提交记录里最近一次改动时间。删除计划标记已经进入“废弃观察期”的功能。这样的话那些“没用的功能”会提前暴露在阳光下而不是等到某个同事偶然翻代码时才被发现。功能审计的价值在于它把删除一个功能的判断从“个人感觉”变成了“团队流程”。团队有了共同语言就不会再出现“这个东西是不是没用”的低效讨论。4.4 这个思维也能用到个人知识库和工具库“没用的功能”这个说法不只是项目代码里有个人工具箱、知识库、笔记系统里同样存在。我经常看到有人收藏了一堆“看起来有用”的工具和资料但从来没有真正派上用场。它们和代码里的遗留功能一样占据空间制造认知负担。对个人知识库也可以定期做一次审计这个东西解决过我的什么问题如果从未解决过它应该被清理、归档还是等一个合适的场景这个问题比“它有没有用”更值得问。一个工具在今天没用不代表它永远没用但如果你连它可能解决什么问题都想不起来那它就只是在占用大脑缓存。4.5 最后想讲的不是“删”而是“理解”回看这个过程处理“没用的功能”最消耗精力的一步不是删除而是理解。理解一个功能为什么长成这个样子比直接删掉它更能提高项目质量。它背后往往蕴含着一次业务调整、一次架构升级、一次故障补偿。我们真正在做的不是清理垃圾代码而是把这些“时间胶囊”打开确定它们的内容是否仍然有意义。如果下一次再看到一个没用的功能我建议你先别急着下结论。先问一句我是否已经知道它存在的真正原因如果答案是否定的那现在删除它可能也只是重复之前某个人犯过的错。
返回列表