网站构建秘籍:19年全栈工程师的框架选型与设计铁律
|
跟产品吵完接口背锅那会儿,灰度开关没推完,后端服务切了七成流量,前端还卡在 v3.2.1 的 bundle hash 里——PM 站我工位边啃冷包子,说“用户点击率涨了零点三”,我盯他三秒,把刚改的 OpenAPI spec 扔进回收站,连删带清缓存,整个下午再没碰 swagger。 优胜劣汰?这词现在听都起鸡皮疙瘩。去年一月那个项目,上线前夜我原以为用 Rust 写核心鉴权模块能扛住峰值,结果 DBA 老张凌晨两点打电话说:“你那个 `SELECT FOR UPDATE` 在 pg_stat_activity 里排第九,前三都是你。” 我查日志发现他没关 connection pool reuse,但我也没吭声——因为我自己漏写了 retry-on-deadlock。这个我敢打包票,当时 oncall 手机震了一下,是测试发的 Slack 提醒:“支付页 HOC 里用了 memo,但 props 每次 new Date()”。 框架选型?早就不信“选型”这词了。Node.js 用 Express 做网关层,三年没升大版本,不是因为它稳,是没人敢动中间件顺序;Vue 3 Composition API 看似清爽,但 frontend 小李写了个 useAsyncData,里面 `onUnmounted(() => controller.abort())` 忘加空判,导致三个页面共享一个 abortController,路由跳转时触发未捕获 reject,报错堆栈里混着十八毫秒的 fetchTimeout 和三百七十二次调用的 mockAdapter —— 这个我说不准,后来是 QA 在生产环境抓包发现的,不是监控告的警。 反常识结论来了:你写的第一个 commit,就是淘汰规则的起点。不是靠 benchmark,是靠谁先删它。上周我看见实习生在 SvelteKit 的 hooks.server.ts 里加了个 `import { env } from '$env/dynamic/private'`,然后顺手 `console.log(env)`,没删。两天后运维把 config 注入方式全换了,他那个 log 没被测出来,因为 log 本身不打监控指标,只往 stdout 喷一行字——可就这一行字,让整个 CI pipeline 多跑了十七秒,因为日志采集 agent 死锁了一次。咖啡杯上印的公司 logo,正好盖住“2020技术峰会”的年份,我看不清,也没去擦。 跟 DBA 吵最狠那次,不是为索引,是为 nullability。他说“email 字段必须 NOT NULL,不然分库分表没法做 join”,我甩出线上一百二十七条 email 为空的订单记录,他回手把那批数据 update 成 “_unfilled_@tmp.local” —— 不是修业务逻辑,是填 schema 兼容性。我原以为他会同步改应用层校验,结果他只改了数据库约束,第二天前端传了个空字符串,ORM 自动转成 null,insert 报错,又回到我这儿背锅。监控大屏上一个无关曲线抖了一下,是 Redis cluster 的 client-side caching miss ratio,从 23% 到 23.04%,没人管,但我就盯着看了四分钟。 设计铁律?第一条是:别信文档里写的“高可用”,信你 last deploy 回滚花了多久。我们组去年 Q3 KPI 是“接口 P99 < 800ms”,结果压测环境所有链路加了 mock delay,真实用户跑的是降级策略里的 fallback 函数,返回静态 JSON,P99 是 67 毫秒——PM 说这叫“有效优化”。我没拆穿,但把 fallback 返回的 JSON 里 `"status":"ok"` 改成了 `"status":"ok-rolled-back"`,上线后没人问,只有测试小王截图问我:“这个字段是新加的?”,我说:“嗯,内部埋点。” 她点了头,去倒了杯水,水杯放回饮水机时碰倒了旁边的绿萝。
文章配图,仅供参考 第二条铁律:每个 config key 必须有唯一 owner,且该 owner 必须是最后一个改过它的活人。不是 Git blame,是物理意义的“最后碰过”。比如我们有个 `feature.flag.auth.enforce_mfa`,配置中心显示值为 true,可 prod 环境就是不生效——排查三天,发现前端没读 config,自己硬编码了 `const mfaRequired = false`,放在 utils/auth.js 第四行,上面注释写着:“临时关闭,等 PM 确认 UX”。没人知道是谁写的,Git history 被 rebase 过三次。后来是我手动 ssh 进容器,在 node_modules/@company/ui-kit/dist/xxx.min.js 里搜到 `mfaRequired=!1`,反编译后定位到 source map,发现是前端组长半年前随手加的。但他不承认,说“记不清了”。我说:“那你重装一次 node_modules?” 他沉默十秒,关了电脑走了。我不屑讲“微服务拆分”,因为拆得越细,越容易在 trace 上看见三个 span 都标 success,第四个却卡在 grpc handshake timeout。也不提“可观测性建设”,我们告警系统去年十一月起就默认关掉所有 duration >5s 的 slow sql 告警——因为告不过来。所以现在的慢查询报警只看“执行次数突增”,而不是耗时。这个逻辑是我跟运维老王喝第三杯散装白酒时定的,他手机壳裂了,一直没换,露出底下一层黄漆。 站长个人见解,下个项目,我不再参与任何框架选型会议。我要去 infra 组盯一周 deployment pipeline,看清楚他们怎么处理 rollback 后的 schema 版本漂移——上次升级 Postgres 14,我们回退到 13,但 migration history 表里还留着一条 `ALTER TABLE user DROP COLUMN phone` 的记录,直到某个 batch job 报 `column "phone" does not exist` 才被发现。那时候已经丢了两百单。 我现在在改 webpack.config.js 里一个 alias,要把 `@assets/images` 指向 `src/assets/static`,而不是之前的 `public/`——因为前端说他们要用 new URL 的动态 import 加载 SVG Sprite。我知道这会让 vite 用户抱怨,也知道 dev server 可能因此卡顿两秒……但算了,先提交再说。咖啡凉了,logo 那块也模糊了,随它吧。 (编辑:站长网) 【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容! |

