技术探索与实践踩坑记录:从测试转开发后,我被“运营”逼成了全栈(伪)
大家好,我是小陈。三年前还在拿着 Postman 一遍遍跑接口、在 Jira 里怼产品经理需求不清晰的 QA,如今已经是个坐在 MacBook Pro 前写 TypeScript 的“准开发”了。刚入职新公司两个月,每天都在“我以为我会了”和“这玩意怎么又崩了”之间反复横跳。Windows?早扔角落吃灰了,除非要测 IE11——别笑,我们还真有个老系统要兼容(泪)。
这篇文章不是什么高大上的架构演进,纯粹是我在“被运营需求追着打”的过程中,硬着头皮上手新技术、翻车、爬起来、再翻车的真实记录。如果你也刚转开发、或者正被业务方各种“简单改个功能”折磨得想删库跑路,那咱们算同病相怜了。
起因:运营说“我们要一个数据看板”,我以为只是加个图表
事情发生在上周三下午 4 点,距离季度复盘会还有两天。运营小姐姐带着甜甜的笑容走进我们工位:“小陈啊,能不能帮忙搞个简单的数据看板?就展示下最近一周的用户活跃、订单转化这些,老板要看。”
“简单?”我内心一咯噔。在测试岗待久了,听到“简单”俩字就条件反射冒冷汗——当年产品经理说“加个按钮就行”,结果牵扯出三个微服务改造,差点让我在双11前夜通宵。
但转念一想:现在我是开发了!不就是个看板吗?用现成的 BI 工具拖拖拽拽不就完事了?
结果现实啪啪打脸。
公司现有的 BI 平台(某知名 SaaS)权限锁得死死的,运营只能看预设报表。而她想要的是实时筛选、自定义维度、还能导出原始数据——本质上是要一个轻量级的数据分析平台。更糟的是,后端 API 根本没暴露这些聚合接口,全是原始日志表。
Deadline 是周五下班前。也就是说,我有 不到 48 小时,从零搭建一个前端 + 中间层 + 数据处理链路。
探索:技术选型像相亲,既要心动又要能过日子
我第一反应是上 D3.js —— 毕竟《数据可视化实战》这本书我翻过三遍(虽然大部分时间在看配色方案)。但冷静下来一想:D3 学习曲线陡峭,两天根本搞不定交互逻辑,而且团队没人维护,上线即遗产。
于是我把目光投向了 ECharts + Node.js 中间层 的组合:
- ECharts:文档全、社区大、React 封装成熟(我们前端是 React 技术栈)
- Node.js:轻量、快速写 API、能直接连数仓(公司用的是阿里云 AnalyticDB)
技术选型不是炫技,是权衡。我喜欢折腾 Rust、Go、甚至 WebAssembly,但工作中?稳字当头。毕竟线上崩了,运维不会管你用了多酷的语言,只会甩锅:“开发写的啥玩意?”
我火速建了个新 repo,yarn create react-app ops-dashboard,然后 nest new api-gateway(对,后端用 NestJS,TypeScript 全栈走起)。
踩坑实录:你以为的“连接数据库”,其实是地狱副本
坑 1:数据库连接池炸了
NestJS 连 AnalyticDB 很顺利,本地跑通查询。但一部署到测试环境,请求一并发,直接报错:
Error: connect ECONNREFUSED 10.x.x.x:3306
查了一圈,发现是 连接池配置太小。默认只开了 5 个连接,而运营一次筛选可能触发 10+ 个并行查询(每个指标一个)。我赶紧调大:
// typeorm.config.ts
{
type: 'mysql',
host: process.env.DB_HOST,
port: 3306,
username: process.env.DB_USER,
password: process.env.DB_PASS,
database: 'analytics',
synchronize: false,
logging: false,
poolSize: 50, // 从 5 改到 50
extra: {
connectionLimit: 50,
}
}
但问题没完——DBA 找上门:“你这服务占了 50 个连接,其他服务快连不上了!” 最后妥协方案:前端做请求合并,把多个指标查询打包成一个 API 调用,后端用 SQL UNION ALL 一次性返回。性能提升 3 倍,连接数降到 10 以内。
坑 2:日期时区搞乱所有数据
运营说:“为什么周三的数据跑到周四去了?”
我:“???”
查日志发现:前端传的是 2024-05-01,后端用 new Date('2024-05-01') 解析,结果变成 2024-04-30T16:00:00.000Z(因为服务器在 UTC 时区)。
解决方案?统一用 ISO 8601 字符串 + 明确时区:
// 前端传
const startDate = dayjs().startOf('week').format('YYYY-MM-DDTHH:mm:ssZ'); // "2024-04-29T00:00:00+08:00"
// 后端解析
const date = new Date(startDate); // 正确保留东八区时间
顺便安利一本救我命的书:《Working with Time in JavaScript》,薄薄一本,专治各种时区 PTSD。
坑 3:ECharts 在 Safari 上白屏
本地 Chrome 完美,Mac Safari 打开一片空白。控制台报:
TypeError: undefined is not an object (evaluating 't.getContext')
查了 ECharts GitHub issue,发现是 Canvas 渲染器在某些 Safari 版本有兼容问题。解决方案:强制用 SVG 渲染:
<ReactECharts
option={option}
style={{ height: '400px' }}
opts={{ renderer: 'svg' }} // 👈 关键!
/>
那一刻我真想给 ECharts 团队寄锦旗——文档里居然没写这茬,全靠社区 issue 挖出来的。
教程?不存在的,全靠“野路子”拼凑
说实话,整个过程我没看任何完整教程。网上那些 “Build a Dashboard in 10 Minutes” 的视频,要么用 Firebase 这种我们不能用的云服务,要么数据都是 mock 的。
我的学习路径大概是:
- 官方文档速读:ECharts 配置项、NestJS TypeORM 用法
- Stack Overflow 拼命搜报错信息
- GitHub 搜关键词:比如
nestjs mysql connection pool - 问同事:特别是后端老哥,一句“你试试加个事务隔离级别”救我狗命
最离谱的是,为了搞懂 AnalyticDB 的 SQL 优化,我硬啃了阿里云文档里的 执行计划(EXPLAIN)章节,还画了个对比表格:
| 优化前 | 优化后 | 查询耗时 |
|---|---|---|
SELECT * FROM logs WHERE date = '2024-05-01' |
SELECT user_id, event FROM logs WHERE dt = '20240501' |
8.2s → 0.4s |
| 无索引 | 按 dt 分区 + user_id 二级索引 |
↓ |
注:AnalyticDB 要求分区字段命名规范,
date不行,得用dt这种格式。
成果 & 反思:上线了,但代价是头发
周五晚上 7 点,看板终于跑起来了。运营小姐姐发来微信:“太棒了!比原来那个 BI 快多了!” 我瘫在椅子上,盯着终端里 npm run build 的成功提示,长舒一口气。
但冷静下来想想,这次“救火”暴露了很多问题:
- 缺乏前期沟通:如果一开始就拉上 DBA 和运维,能避免一半的坑
- 技术债堆积:中间层代码写得像意大利面条,后续维护成本高
- 监控缺失:上线后才发现没加日志埋点,排查问题全靠猜
所以周末我干了两件事:
- 写了一份 内部简易教程,放在 Confluence 上,标题就叫《如何快速搭一个临时看板(以及千万别踩的坑)》
- 给团队提了个 RFC:建立数据分析中间件规范,包括连接池配置、时区处理、错误重试等
最后:转开发三年,最大的感悟是“务实”
从测试转开发,我一度沉迷于“炫技”:用最新框架、写最优雅的函数式代码、追求 100% 单元测试覆盖率。但现实是——业务需求永远比技术理想更急迫。
运营要的不是一个完美的系统,而是一个 明天早上能用的东西。作为开发者,我们的价值不是写了多少行酷炫代码,而是 用最稳妥的方式,把问题解决掉。
所以现在的我,依然会翻《JavaScript 高级程序设计》第 4 版,也会在个人项目里玩 SvelteKit + WASM。但工作中?能用 Express 就不用 Koa,能用 MySQL 就不碰 MongoDB,能 copy-paste 就绝不重复造轮子。
毕竟,稳定交付,才是程序员最大的浪漫。
P.S. 如果你也刚转开发,别怕踩坑。每个 bug 都是你简历上的一颗星 ✨。
P.P.S. 本文所有代码已脱敏,但情绪真实——上周五加班到 10 点,回家路上真的想砸电脑。

评论 0