
分页接口很容易被当成 limit + offset 的小功能,直到列表翻到后面越来越慢,用户刷新后看到重复数据,或者运营导出时少了几行。分页真正要设计的是一组边界:结果如何排序,下一页从哪里开始,数据变化时是否允许漂移,以及客户端能不能理解“还有没有更多”。

分页接口很容易被当成 limit + offset 的小功能,直到列表翻到后面越来越慢,用户刷新后看到重复数据,或者运营导出时少了几行。分页真正要设计的是一组边界:结果如何排序,下一页从哪里开始,数据变化时是否允许漂移,以及客户端能不能理解“还有没有更多”。

Shell 脚本常常从一两行命令开始,后来慢慢变成构建、发布、备份、迁移和运维入口。它的问题也在这里:看起来只是“把命令串起来”,一旦变量为空、管道中间失败、临时文件没清理,影响就会被放大。写稳 Shell 脚本,不是把 Bash 语法背全,而是给失败路径、输入边界和资源清理留出明确位置。

很多服务的数据库故障,并不是 SQL 变慢才开始的,而是连接池先被打满,请求继续排队,应用线程被占住,最后把局部慢查询放大成整站超时。连接池不是越大越安全,它更像一个阀门:放得太小会限制吞吐,放得太大又会把数据库推到极限。要把它用稳,需要同时设计容量、排队、超时和背压。

开发时最打断节奏的场景,往往不是写新功能,而是新功能写到一半,线上突然要修一个小 bug;或者正在做代码审查,本地又必须回到干净的 main 复现问题。反复 stash、切分支、装依赖,会让工作区越来越混乱。git worktree 的思路很朴素:同一个仓库可以挂出多个工作目录,每个目录检出不同分支,但共享同一份 Git 对象库。这样你可以保留当前现场,同时在另一个目录里处理热修复或评审。

很多系统一开始把耗时逻辑丢进队列,只是为了让接口更快返回。等业务量上来后,真正难处理的往往不是“怎么入队”,而是任务重复执行、卡在半路、持续失败、人工不知道该不该重放。异步任务要跑稳,需要把队列、消费者、数据库状态和告警流程放在一起设计,而不是只换一个更强的消息中间件。

很多技术债不是因为当初的选择一定错了,而是后来的人只看见了“现在这样”,却找不到“当时为什么这样”。ADR(Architecture Decision Record,架构决策记录)要解决的不是写更多文档,而是把关键选择、约束和取舍放进代码仓库,让团队在修改系统前能先理解背景。

缓存不是“给慢接口加一层 Redis”这么简单。它能降低数据库压力、缩短高频读取的响应时间,也会引入过期数据、穿透、击穿、雪崩和回源放大。要把缓存用稳,关键是先承认它只是数据副本,再围绕读写路径、过期策略和故障边界做工程约束。

代码质量问题越晚发现,修复成本越高。等 CI 跑红时,开发者已经切到下一个任务;等评审者指出格式、拼写、导入顺序或误提交密钥时,讨论也会被低价值噪声占满。pre-commit 的价值不是替代 CI,而是把确定、低成本、可自动修复的检查提前到 git commit 之前。

一次发布真正危险的部分,往往不是代码合并,而是新逻辑第一次面对真实流量。Feature Flag 的价值,就是把“部署”和“启用”拆开:代码可以先安全上线,功能再按用户、环境、比例逐步打开;一旦指标异常,也能在不重新发版的情况下关闭入口。

项目刚启动时,依赖更新看起来只是顺手执行一次 npm update、pip install -U 或 go get -u。但项目一旦进入多人协作和持续发布,依赖就会变成一条隐形供应链:版本范围决定会装到什么,锁文件决定实际运行什么,CI 决定能不能把变化放进主干。把这三件事管住,依赖更新才不会从“维护动作”变成“随机事故”。