三年前端瓶颈期破局:从接需求到主导技术专项

3 阅读1分钟

三年前端瓶颈期破局:从接需求到主导技术专项

git log --oneline | wc -l 跑一下,几千条 commit 是有的,但你仔细想想简历上能拿出来讲的技术亮点有几个?两三个撑死了吧。需求做了一堆——虽然我觉得没必要,feature/xxx 分支开了合、合了开,你心里隐隐觉得哪里不对劲,但又说不上来到底卡在哪。

不是错觉。

三年这个节点很微妙,一部分人开始主导技术方向了,在团队里说话有分量了,推着基建往前走了,另一部分人还在老老实实写业务代码,一个 JIRA 卡片接一个 JIRA 卡片地消化。区别在哪?不是谁 TypeScript 类型体操玩得更花哨,是谁先想明白了一件事——你得从"给什么做什么"的走一遍者,变成"我来定义做什么"的那个人。跟天赋没太大关系——先别急着反驳,方法论的事(听起来很合理对吧,但是)。

发现问题的能力比解决问题更稀缺

"我想做点技术建设,但不知道做什么。"

这话我听太多了。答案简单得要命——去找让你烦的东西。等等,其实得要命——去找让你烦的东西。你每次复制粘贴一段代码的时候,每次手动改 nginx.conf 或者 .env.production 的时候,每次在群里问"这个接口的 status 字段 2 到底是什么意思"的时候,每次 npm run build 转圈等两分钟你只能刷手机的时候——全是问题。你只是习惯了而已。

// 你每天都在做的事,但从来没觉得它是个"问题"

// 每个页面都手写一遍 loading + error + empty 状态
const [loading, setLoading] = useState(true)
const [error, setError] = useState(null)
const [data, setData] = useState(null)

useEffect(() => {
  fetchData()
    .then(res => setData(res))
    .catch(err => setError(err))
    .finally(() => setLoading(false))
}, [])

// 这段代码在你项目里出现了多少次?30次?50次?
// 有的忘了 finally,有的漏了 catch,有的 setLoading 放错位置
// 这就是一个值得用 useSWR() 或自定义 hook 干掉的"问题"

发现问题这件事嘛,说白了就是模式识别。跟你扫一眼代码就能看出 O(n²) 嵌套循环是一回事,你需要训练自己扫一眼工作流就能看出哪里在重复、哪里在空转。

不是所有问题都值得你上

发现了就冲?太急了。

问题发现 → 问题分级 → 方案设计 → 成本评估 → 推动决策 → 落地执行
    ↓
  记录下来        ← 大多数人卡在这步,发现了但没记录
    ↓                直接忘了,或者想着"以后再说"
  评估 ROI
    ↓
  高 ROI → 立项推动
  低 ROI → 扔进 backlog,等时机成熟

ROI 怎么算?粗暴一点:解决这个问题能省多少人天,除以做这件事要花多少人天。哦不,准确说是:解决这个问题能省多少人天,除以做这件事要花多少人天。比如一个 CI/CD 流水线优化的场景,你把每次 docker build + deploy 的耗时从 15 分钟压到 3 分钟,团队 10 个人每天部署 3 次,一年下来节省的时间大约是 (15-3) × 10 × 3 × 250 / 60 ≈ 1500 小时。这数字摆出来,leader 没有理由不批。

说到这里我自己都有点绕了。

但你要是想花两周把 ESLintairbnb 换成 standard 的话?算了吧,ROI 约等于零,还容易在群里吵起来。别问我怎么知道的。

从问题到专项:把想法变成能落地的东西

先卖问题,再卖方案

太多人上来第一句就是"我要引入 Monorepo"。停一下。

你 leader 不关心 Monorepo 是什么,他关心的是现在有什么问题,不解决的话会怎样。所以你的 RFC 开头应该是痛点,带数字的那种:

## 背景

当前项目存在以下问题:

1. 公共组件改一次需要手动 `npm publish` 然后去 3 个仓库分别 `npm update`,
   上周因为同步遗漏导致线上事故(P2 级别)
2. 三个仓库的 `eslint.config.js` / `tsconfig.json` / 构建配置各不相同,
   新人上手平均要花 3 天搞清楚差异在哪
3. 依赖版本不统一,A 仓库 `react@18.2`,B 仓库还停在 `react@17.0`,
   共享代码时 `@types/react` 类型冲突不断

每一条,具体场景,具体后果,最好有数字。这不是技术博客的科普风格,你要建立的认知是"不做这件事我们要亏多少"。

方案对比不能走过场

alternatives 里随便列两个方案,每个写一句"不够灵活"或者"生态不成熟"就带过去——这种 RFC 一看就知道是先定了结论再补的理由。真正让人信服的对比长这样:

方案评估矩阵(构建工具迁移)

                 Vite        Turbopack      保持 Webpack
─────────────────────────────────────────────────────────
冷启动速度      ~300ms       ~200ms         ~18s
HMR 速度        <50ms        <30ms          ~2s
生态成熟度                      
迁移成本        2 周         4 周           0
团队熟悉度      中           低             高
SSR 支持        稳定         实验性          稳定
─────────────────────────────────────────────────────────
推荐指数                        继续用也不是不行

表格一摆,选谁不用你多费口舌,数据替你说话(听起来很合理对吧,但是)。很多三年前端不是不会做这件事,是懒得做,觉得"我技术好就够了,搞这些文档是浪费时间"。浪费吗?你写的代码 leader 未必逐行看,但你提交的 RFC 他一定会打开。

推动落地:最难的部分不是代码

渐进式迁移还是一把梭

方案通过了,开干。这时候有个致命的岔路口。

一把梭的做法就是找个周末全量切换,听起来痛快。但出了问题你连 git bisect 都没法用——所有改动挤在一个巨型 commit 里——这个等下再说,你根本定位不到是哪行代码引入的回归。我亲眼见过一个团队周六做了次"大重构",周一上班整个项目起不来,花了三天才修好。血淋淋的。

渐进式迁移才是正路,核心思路是绞杀者模式(Strangler Fig Pattern):

// 新代码走新方案,老代码逐步替换,两套并行

// Step 1:建适配层,兼容新旧
function request(url: string, options?: RequestOptions) {
  if (options?.useNewClient) {
    return newHttpClient.request(url, options) // 新方案
  }
  return legacyAxios.get(url) // 旧方案暂时留着
}

// Step 2:新需求一律用新方案
// Step 3:每个迭代顺手迁移 2-3 个旧接口
// Step 4:legacyAxios 调用量归零 → rm -rf legacy/

// 关键:用埋点或日志统计 legacyAxios 的调用频次
// 降到 0 了再删,不要凭感觉

这个模式的精髓就俩字:可停。做到一半业务优先了的话?没关系,暂停就是,系统照跑不误,下个迭代接着来。

人比代码难搞

你推了个新的 code review 规范也好,推了个新的内部组件库 @company/ui 也好,总有人觉得"现在挺好的啊,为什么要改"。这种时候不要在技术层面硬刚。换个思路,找到对方的痛点。

"你上次那个 CSS 样式被别的页面覆盖的 bug,排查了多久来着?

比跟他解释 CSS Modulesscoping 原理管用一百倍(这里有坑)。人只在乎跟自己切身相关的事情,技术正确性在说服人这件事上排不到第一位。等等,其实跟自己切身相关的事情,技术正确性在说服人这件事上排不到第一位。扯远了,拉回来。

量化成果,不然白干

做完了怎么证明有价值?拿数据。

interface TechProjectImpact {
  before: {
    buildTime: '180s'
    bugRate: '每周 3-5 个样式相关 bug(Sentry 统计)'
    onboardingTime: '新人平均 3 天才能本地跑起来'
  }
  after: {
    buildTime: '30s(↓83%)'
    bugRate: '上线两个月 0 个样式 bug'
    onboardingTime: 'git clone 之后 npm i && npm start 直接跑'
  }
  effort: '2 人 × 3 周'
  roi: '预计年节省 400+ 人时'
}

beforeafter 必须是同一维度的对比,别前面说"构建慢"后面说"代码质量高了",这叫偷换概念。

心态和节奏

"三年了还在写 CRUD"这种焦虑,大半是社交媒体制造出来的。继续。你打开掘金、知乎,满屏都是"两年经验 40w""自学转全栈年薪翻倍"(我也是后来才想明白的)。这些帖子的幸存者偏差比 JavaScript0.1 + 0.2 !== 0.3 还离谱。能跑就行,别被带节奏。

找到你的技术锚点

什么都学?

选一个方向,扎下去:

// 别这样:
const skills: Record<string, number> = {
  react: 0.6,
  vue: 0.5,
  node: 0.4,
  rust: 0.1,
  web3: 0.05,
  // 什么都沾一点,简历很好看,面试一问就露馅
}

// 要这样:
const skills: Record<string, number> = {
  react: 0.9,           // 主力框架,源码级熟悉
  performanceOpt: 0.8,  // 性能优化是你的招牌
  buildTools: 0.7,      // Vite / esbuild / Rollup 插件写过
  // 其他的够用就行
}

T 型人才结构,横向够用纵向突出,选什么方向?看团队最缺什么和你个人最感兴趣的东西交集在哪。性能优化、工程化、Design System、监控体系、微前端——哪个都够你深耕好几年的。选了就别轻易换,虽然很多时候是被业务推着走身不由己,但至少你可以在业务间隙有意识地往一个方向积累厚度。

不知道第一步做什么的话

就做这一件事。

打开你们项目,跑一下 npx depcheck 看看有多少 package.json 里躺着但代码里根本没 import 的僵尸依赖,再跑一下 npx webpack-bundle-analyzer 看看产物体积分布。把结果截图丢到团队群里,配一句话:"我们首屏加载的 bundle2.3MB(gzipped 之后还有 680KB),行业标准建议 < 200KB,我初步分析了下原因写了个优化思路,感兴趣的可以看看这个文档。"

反正大概是这么个意思。

就这一步。你搞定了"发现问题、量化问题、输出方案、主动沟通"的完整闭环。后面的事情会自然发生——有人会问你打算怎么优化,有人会给建议甚至要跟你一起搞,你的 leader 会注意到你在主动推动事情而不是等着被分配。

写到这里突然觉得之前说的不太对。

整个过程跟 EventEmitter 的模式一模一样:你得先 emitter.emit('proposal', { topic: 'bundle优化' }) 把信号发出去,别人才能 emitter.on('proposal', review) 接住你。一直等着被 on 的话?等了个寂寞。

说到这里我自己都有点绕了。

这套路跑通一次之后后面会越来越顺,因为"这个人靠谱"的信任已经建立了,推动成本会断崖式下降(虽然官方文档不是这么说的)。做到这一步你的瓶颈期基本就过了——不是你突然技术变强了多少,是你做事的方式变了,从等活干变成了找活干,从闷头写代码变成了带着别人一起解决问题。