leetcode3310 深夜运维惊魂:那个叫k的方法有毒

深夜运维惊魂:那个叫k的方法有毒

凌晨三点,你正做着美梦——梦见自己成了技术总监,手下管着100个程序员,每个人都在996,只有你在摸鱼。

突然,手机炸响。屏幕上赫然两个字:老板。

你心脏骤停半秒,还没来得及说“喂”,那头已经咆哮如雷:“李码!线上崩了!运维说是方法 k 炸的,这方法是不是你写的?!”

你瞬间清醒,脑子里一万个 console.log("卧槽") 疯狂刷屏。又是k!为什么每次都是k? 上次是变量k,这次是方法k,下次键盘上 K 键坏了是不是也要算你头上?


一:方法的社交圈

你打开IDE,眼前是一片代码屎山。

n个方法,编号从0n-1,像极了你们公司的组织架构——看似井然有序,实则一团乱麻。

调用关系写在一个叫 invocations 的二维数组里,invocations[i] = [x, y] 表示方法 x 调用了方法 y。

这不就是方法的社交网络吗?你迅速建了个有向图,锁定每个方法的狐朋狗友。

graph = [[] for _ in range(n)]  # 我调用了谁

for x, y in invocations:
    graph[x].append(y)

二:标记"k家军"

已知方法 k 有 bug,所有它直接或间接调用的方法全部被视为成为“可疑方法”。

你盯着这行字,一时间有些恍惚——六年前,你也这样被标记过——那天,你只不过和对门邻居在楼道里打了个照面,就因为“时空伴随”喜提居家隔离七天,健康码红得像你写的错误日志,社区工作人员每天上门测核酸比你 CI 流水线跑得还准时。

你苦笑一声,祭出 DFS 大法,从 k 出发,沿着调用链挨个打码。

suspicious = [0] * n   # 标记数组,0是清白,1是可疑

def dfs(x: int):
    suspicious[x] = 1
    for y in g[x]:
        if not suspicious[y]:
            dfs(y)

dfs(k)

DFS跑完,suspicious 数组里标为1的方法,就是传说中的**“k家军”**——一个都跑不掉。


三:移除决策

已经标记了所有"k家军",下一步是不是直接 Ctrl+X 一把梭?太天真了。

安全手册第一条:删代码可以,崩系统不行。

什么意思?只有当这组可疑方法没有被任何外部方法调用时,才能安全移除。如果圈外还有人深情地调着圈内的方法,那你强行删除就会导致 NullPointerException,整个调用链像多米诺骨牌一样连环崩塌,明天的日报上你就能亲手写下“因误删可疑方法导致 P0 事故,影响用户 XXXXX 人,已深刻反省,主动申请取消年终奖。”

你的手指悬在键盘上方,敲下了决定职业生涯能否存续的检查代码:

for x, y in invocations:
    if not suspicious[x] and suspicious[y]:
        # 有外部依赖!原地摆烂
        return list(range(n))   # 全留着,一个不动,祖传屎山永流传

如果这段循环跑完都没触发return,那么,恭喜你——这个可疑方法集合就是一个完美的隔离孤岛。你完全可以一键 rm -rf,直接返回劫后余生的幸存者名单:

return [i for i in range(n) if not suspicious[i]]

彩蛋

事后你复盘此事,悟出一个真理:老板要删方法,先看有没有人保它。外部有调用,屎山也能免死;没外部调用,再干净也得滚蛋。

你以为你刷的是图遍历?不,你刷的是职场生存学。

如果你和你的小团队内部自嗨,从不跟外界交互——那裁员的刀落下来,你们就会被一锅端。

但如果其他部门还死死依赖着你们……嘿嘿,就算你代码写得再烂,老板也得咬牙留你——这叫技术债绑架,或者,也叫组织的“不可或缺性”。

所以,你是想当那个随时可被替换的干净方法,还是那个让老板不敢动的屎山核心?

明天上班,记得把你的方法多暴露几个接口出去。保命。

知识共享许可协议
本作品采用 知识共享署名-非商业性使用-禁止演绎 4.0 国际许可协议 进行许可。