我在创业公司当程序员的那些事
外包干了四年,见过的需求比你吃过的盐还多:要给后台加个“一键变美”按钮的、要求用 Excel 做实时协作系统的、甚至还有让我把 Python 写成 C++ 性能的(对,就上周)。本以为自己已经练就了一身“需求免疫”,结果两个月前跳槽进这家 A 轮创业公司,还是被现实狠狠教育了一顿。
刚入职那天,CTO 拍着我肩膀说:“我们这里节奏快,但技术自由度高。” 我当时还暗自窃喜——终于不用再写那些祖传 jQuery 项目了。没想到,“节奏快”是真的快到飞起,“技术自由”是自由地选择用哪个框架重写上周刚上线的功能。
需求?不,那是每日刷新的任务副本
上个月,产品经理在周五下午四点半甩过来一个需求:“我们要做一个动态表单引擎,支持拖拽、条件联动、多级嵌套,下周一上线。”
我盯着 Slack 消息看了足足十秒,心想:这怕不是把我当成 GPT-5 来用了?但转念一想,创业公司嘛,不就是“不可能任务”的代名词?而且我最近正研究开源的低代码平台源码(比如 Formily、React JSON Schema Form),正好拿这个当实战。
于是我咬咬牙接了。毕竟,谁让我是个喜欢钻源码、关注架构设计的老外包呢?虽然现在身份变了,但骨子里那股“代码洁癖”还在。
JavaScript 的“优雅”陷阱
一开始,我想用纯函数式思路搞一套干净的状态管理:每个字段一个 reducer,联动逻辑用 RxJS 处理。结果写到一半发现——产品经理根本没考虑过“循环依赖”的场景。比如:A 字段变化触发 B,B 又反过来影响 A,直接死循环。
本地还好,一上测试环境,页面卡成 PPT。Chrome DevTools 里 Performance 面板拉出来一看,call stack 长得能绕地球一圈:
Uncaught RangeError: Maximum call stack size exceeded
at Field.update (field.js:42)
at Field.update (field.js:42)
// ... 重复几百行
那一刻,我真的想砸电脑。但冷静下来一想:创业公司资源有限,不能指望 PM 把所有边界情况都想清楚。作为开发者,得自己兜底。
于是我把状态管理改成了基于事务队列 + 异步调度的模式,类似 Vue 3 的 nextTick 机制。核心思想是:任何字段变更先入队,批量处理,避免同步递归。代码大概长这样:
class FormEngine {
updateQueue = [];
scheduleUpdate(field, value) {
this.updateQueue.push({ field, value });
if (this.pending) return;
this.pending = true;
Promise.resolve().then(() => {
this.processQueue();
this.pending = false;
});
}
processQueue() {
const updates = [...this.updateQueue];
this.updateQueue = [];
// 执行更新 + 联动计算,但限制最大迭代次数防死循环
let count = 0;
while (updates.length && count < 10) {
// ...执行逻辑
count++;
}
}
}
虽然糙了点,但至少不会崩。上线后跑得稳稳的,连测试都夸我“这次没出幺蛾子”。
技术分享?先活下来再说
说到技术分享,其实我一直挺想组织团队做内部 workshop 的。之前在外包公司时,我就经常拉着同事讲 V8 引擎原理、Webpack 插件机制,甚至手撕过 React Fiber 的简易版。
但在这儿,现实很骨感。大家每天都在赶 deadline,晨会三句话离不开“进度”“阻塞”“能不能砍功能”。有一次我提议搞个“JS 性能优化小课堂”,结果被反问:“能帮我们提前一天上线吗?”
行吧,理解万岁。但我还是偷偷在团队 Wiki 里建了个《避坑指南》栏目,把踩过的雷都记下来。比如:
不要用
JSON.stringify做深比较
看似简单,但遇到 circular reference 直接崩。改用lodash.isEqual或自定义 diff 算法。
别信“一行代码搞定”
某些开源库号称“轻量级”,结果 bundle 一打进去,体积涨了 300KB。一定要看源码!
慢慢地,居然有新人开始主动来问问题了。上周五晚上加班时,一个实习生跑来问我:“哥,这个闭包内存泄漏怎么排查?” ——那一刻,我觉得值了。
架构 vs 效率:创业公司的永恒悖论
作为有点架构洁癖的人,我特别受不了“屎山代码”。但在这里,MVP(最小可行产品)才是王道。领导说得直白:“先跑起来,再优化。”
于是我们达成了一个微妙的平衡:核心模块写得尽量干净,边缘功能允许“战术性脏代码”。
举个例子,我们有个数据看板,初期直接用 ECharts + 手写配置,性能差得一批。但因为只是内部用,没人投诉。直到用户量上来,老板亲自吐槽“加载像蜗牛”,我才被批准重构。
这次我用了 Web Worker + 虚拟滚动 + 数据分片,首屏加载从 8s 降到 1.2s。关键是我提前写了 benchmark 对比表,用数据说话:
| 方案 | 首屏时间 | Bundle Size | 内存占用 |
|---|---|---|---|
| 原始方案 | 8.2s | 1.8MB | 320MB |
| 重构后 | 1.2s | 1.5MB | 98MB |
有了这张表,老板眼睛都亮了,当场拍板:“以后性能优化都按这个标准来!”
写在最后:外包老兵的自我救赎
说实话,在创业公司这两个月,比我过去两年学得都多。不是技术多高深,而是学会了在混乱中建立秩序。
我不再执着于“完美架构”,但也不会放任烂代码蔓延。我会为了 deadline 写点 hack,但一定会在注释里标上 // TODO: refactor after launch。我依然研究开源项目源码,但目的不再是“炫技”,而是找能真正解决问题的轮子。
如果你也刚从大厂或外包跳槽到创业公司,我的建议就一句:别怕脏手,但别丢掉思考。
技术分享不是站在台上讲 PPT,而是在 PR 里写好注释,在 Slack 里耐心解答新人问题,在深夜修复线上 bug 后顺手更新文档。
毕竟,我们写的不是代码,是未来的自己。
P.S. 上周那个动态表单,现在已经被 PM 用来生成“员工满意度调查”了。讽刺的是,他自己填的时候卡了三次……我默默在后台加了条日志:console.warn('PM is struggling again')。

评论 0