首页 日记 项目 关于

— 开发者日记 —

用代码雕刻每一天

记录开发路上的点滴思考、踩过的坑、学到的东西。
每一个 Bug 都是成长的印记,每一次重构都是思维的进化。

|

编码足迹

📅
0
累计编码天数
🚀
0
完成项目
🐛
0
修复 Bug
0
咖啡杯数

开发日记

2026.06.03 · 周二

重构老旧 API 层的那些事

😤

今天终于下定决心重构那个两年没人敢动的 API 层了。3000 多行代码,函数名全是 doStuff()processData() 这种命名,看得我血压飙升。

核心思路是把所有数据访问逻辑抽到独立的 Repository 层,Controller 只负责参数校验和返回格式化。过程中发现了三个隐藏的内存泄漏——原来某个老函数在循环里创建数据库连接但从不释放。

typescript · 重构后 class OrderRepository { constructor(private db: Database) {} async findByUserId(userId: string): Promise<Order[]> { return this.db.query( 'SELECT * FROM orders WHERE user_id = $1', [userId] ); } }
💡 经验教训

永远不要假设旧代码"能跑就别动"。隐藏的 bug 不会自己消失,只会等到最糟糕的时候爆发。重构时先写集成测试,保底不亏。

2026.05.28 · 周四

CSS Grid 竟然可以这样玩

🤯

之前做响应式布局一直用 Flexbox 各种嵌套,今天研究了一下 CSS Grid 的 subgrid 特性,豁然开朗。以前要实现卡片网格内标题对齐,要么固定高度,要么用 JS 算——现在一行 CSS 搞定。

css .card-grid { display: grid; grid-template-columns: repeat(auto-fill, minmax(280px, 1fr)); gap: 1.5rem; } .card { display: grid; grid-template-rows: subgrid; grid-row: span 3; /* 标题、内容、按钮自动对齐 */ }

配合 container queries,组件级别的响应式简直丝滑。已经开始把项目里那些复杂的媒体查询全部替换了。

💡 经验教训

CSS 的进化速度远超想象。每隔一段时间回头看看新特性,往往能发现让你少写一半代码的方案。subgrid + container queries 是 2026 年必须掌握的技能。

2026.05.20 · 周三

一次诡异的数据库死锁排查

😫

生产环境凌晨 3 点报警:订单创建接口超时率飙升到 40%。登录服务器一看,PostgreSQL 里锁了一堆 UPDATE 语句。问题是——这个接口跑了半年都没事,最近也没上线新代码。

排查了四个小时,最后发现是运维团队调整了数据库连接池大小,从 20 改到了 10。在高并发下,事务等待时间变长,导致了之前从未触发过的死锁条件。一个看似无害的配置变更就能引发雪崩。

sql · 排查死锁的查询 SELECT blocked.query AS blocked_query, blocking.query AS blocking_query FROM pg_stat_activity AS blocked JOIN pg_stat_activity AS blocking ON blocked.wait_event_type = 'Lock' AND blocking.pid != blocked.pid;
💡 经验教训

任何基础设施的变更都要走灰度发布流程,哪怕只是"改个配置"。同时,连接池大小应该根据实际负载测试确定,写入文档并加监控告警。

2026.05.12 · 周二

用 Rust 重写 CLI 工具的初体验

🦀

花了两周时间把那个 Node.js 写的批量文件处理 CLI 工具用 Rust 重写了。性能差距简直离谱——处理 5000 个文件从 47 秒降到了 1.8 秒。

最让我震撼的是 Rust 的错误处理哲学。以前写 Node 经常忘了处理边缘情况,Rust 的 Result 类型逼着你显式处理每一个可能的失败路径。借用检查器刚开始让人抓狂,但一旦理解了所有权的概念,反而觉得之前写 C++ 的时候一直在裸奔。

rust use std::fs; use rayon::prelude::*; fn process_files(paths: &[PathBuf]) -> Result<Vec<String>> { paths.par_iter() // rayon 并行迭代器,零成本抽象 .map(|p| fs::read_to_string(p)) .collect() }
💡 经验教训

选择合适的工具语言真的能事半功倍。对于 I/O 密集型的 CLI 工具,Rust + rayon 的组合拳太香了。而且编译器的严格检查帮我提前发现了 6 个潜在的 bug,这在动态语言里根本意识不到。

2026.05.05 · 周一

搭建了一套完美的 CI/CD 流水线

😌

终于把项目的 CI/CD 从"能跑就行"升级到了"看着就舒服"的水平。用 GitHub Actions 实现了:PR 提交自动跑 lint + type-check + 单元测试,merge 到 main 后自动构建 Docker 镜像并部署到 staging,手动审批后推生产。

最花时间的是把构建时间从 12 分钟优化到了 3 分钟。关键改动:缓存 node_modules 和 TypeScript 增量编译、平行化测试、使用 BuildKit 的 layer caching。

yaml · GitHub Actions jobs: test: runs-on: ubuntu-latest steps: - uses: actions/cache@v4 with: key: npm-${{ hashFiles('package-lock.json') }} - run: npm ci - run: npm run check & npm run test:coverage
💡 经验教训

CI 速度直接影响开发体验。没有人愿意等 15 分钟看自己的 PR 能不能合。把 CI 当成产品来优化——每个环节都要问"能不能更快?"缓存策略是关键中的关键。

2026.04.22 · 周二

从单体应用到微前端的迁移之路

🧐

团队从去年底开始讨论微前端方案,今天终于完成了第一个模块的迁移。选型上最终放弃了 Webpack Module Federation,选了 Single-SPA——更轻量,渐进式迁移更友好。

把用户管理模块从巨石应用中拆出来后,独立部署、独立技术栈(甚至可以用不同版本的 Vue),团队并行开发的效率明显提升。但代价也不小:应用间通信需要专门设计事件总线、CSS 隔离要用 Shadow DOM、首屏加载多了不少 JS bundle。

我觉得微前端不是银弹。如果你只有一个小团队维护一个不算大的应用,单体架构完全够用。但当团队规模超过 20 人、应用模块之间足够独立时,微前端的收益才会超过成本。

💡 经验教训

架构选型永远要以团队实际痛点为出发点,而不是追逐热点。微前端解决的是"组织的规模化协作问题",不是"技术问题"。先问自己:是不是真的需要?有没有更简单的方案?

项目作品

🗂️

TaskFlow

一个极简的任务管理工具,支持看板视图、时间追踪和团队协作。前后端分离架构,实时同步使用 WebSocket。

Vue 3Node.jsPostgreSQLWebSocket
📊

CodeStats

Git 仓库可视化分析工具,自动生成代码贡献热力图、代码质量趋势和团队效率报告。

ReactPythonD3.jsGit API
🔔

AlertPilot

智能告警聚合与分发系统,支持多数据源、自定义规则引擎、钉钉/飞书/邮件多渠道通知。

GoRedisgRPCReact

关于我

👨‍💻

Citrus

全栈开发者 · 开源爱好者 · 终身学习者

一个热爱编程的全栈开发者,主要在 Web 领域深耕。信奉"代码是写给人看的,顺便能在机器上运行"。喜欢探索新技术,用博客记录开发过程中的思考和成长。

技术栈横跨前后端,日常使用 TypeScript、Vue、React、Node.js、Go 和 Rust。对系统设计和代码美学有执念——整洁的架构比炫技的代码更重要。

这个网站是我个人的开发者日记,记录每天的编码日常、踩坑记录和技术思考。不追求华丽的辞藻,只求真实的记录。

TypeScript Vue.js React Node.js Go Rust PostgreSQL Docker AWS GraphQL