惯性聚合 高效追踪和阅读你感兴趣的博客、新闻、科技资讯
阅读原文 在惯性聚合中打开

推荐订阅源

小众软件
小众软件
V
Visual Studio Blog
博客园 - 三生石上(FineUI控件)
Last Week in AI
Last Week in AI
Blog — PlanetScale
Blog — PlanetScale
爱范儿
爱范儿
J
Java Code Geeks
A
About on SuperTechFans
F
Fortinet All Blogs
B
Blog
aimingoo的专栏
aimingoo的专栏
H
Hackread – Cybersecurity News, Data Breaches, AI and More
Engineering at Meta
Engineering at Meta
Y
Y Combinator Blog
有赞技术团队
有赞技术团队
G
Google Developers Blog
Apple Machine Learning Research
Apple Machine Learning Research
V
V2EX
博客园_首页
博客园 - 叶小钗
罗磊的独立博客
OSCHINA 社区最新新闻
OSCHINA 社区最新新闻
D
Docker
云风的 BLOG
云风的 BLOG

博客园 - buguge

交易成功还要记 3 笔账?我们直接砍到 1 笔—— 网络红包记账的一次自顶向下业务层重构 分享一次针对hardcode的小重构:不要把 package 名写死在代码里 聚合系统设计:如何为银行代付通道抽象出公共的代付接口能力 如何自定义 MyBatis枚举处理器(EnumTypeHandler):分享从 “同包同名 shadow 覆盖” 到 “官方扩展点” 的重构经历 这儿也改状态,那儿也改状态,连AI都理不清楚了… 不妨试试这个状态机good-practice 业务解耦的经典实践:从订单表解耦开票业务说起(以滴滴网约车开票为例) 从 `int` 到 `Duration`:一个缓存 API 的三次演进教会我的事 最差实践(bad-practice):开发者在方法里直接实例化线程池对象,然后...(应用gg了) 【HttpClient最差实践(bad-practice)】开发者在 http 工具方法中直接实例化 HttpClient,然后…… Crypto、Cipher与Password:Java加密开发的三个核心概念 知识VS技能:如何优雅判空? 20260604SR超时问题排查 推敲见文章:从 `try..catch` 看异常日志打印的正确姿势 #解决问题要彻底# 慢SQL治理完成后,如何防止同类问题“死灰复燃”? 从合同甲方是荒谬的“JD”谈起:软件开发不应遗忘的“常识” 常见的OOM错误 ( OutOfMemoryError全类型详解) 开发者暴露了一个无需授权访问的裸接口,我问:如果有人暴力请求怎么办? 【SQL性能优化篇】有了!治理慢SQL“WHERE create_time ORDER BY id”的良药---规避“Using filesort”性能杀手 高效查询商户日终余额:一个SQL的优化实践 Hutool 的 `TimedCache` 到期会自动清理吗? ——————hutool cache的"惰性清理"和"定期清理" Fastjson枚举反序列化:当字符串不是枚举常量名时,会发生什么? fastjson-EnumDeserializer类及源码分析 随笔20260309:我们都是围城里的人 `UnexpectedRollbackException: Transaction rolled back because it has been marked as rollback-only` 异常解析 认识2个单词:goal/target —————— 为什么Maven是 "goal" 而不是 "target"? 聚合系统设计:策略模式(Strategy Pattern)在银行通道对接场景中的应用 这样构建对象,太帅了!—— 阶梯式Builder模式与代码整洁之道 注意!字段数据类型不匹配,这个sql会很慢 还在用ArrayList?用HashSet吧!--性能对比 分页查询还在用create_time去做降序?
别留小尾巴/尽快剪掉小尾巴:从一次“ABA”字段重命名,谈谈“解...
buguge · 2026-04-26 · via 博客园 - buguge

一、背景:一次计划周密的“ABA”迁移

最近,团队需要对“API商户密钥配置表” enterprise_api_key 中的 enterprise_id 字段进行重命名,新字段名为 partner_id。为确保迁移过程平稳、不影响线上业务,我们采用了经典的“ABA”策略:

  1. 阶段A:保留原字段,增加新字段
  2. 阶段B:同步数据,双写双读
  3. 阶段A:清理原字段,完成迁移

技术方案清晰明了:

-- 第一步:增加新字段
ALTER TABLE enterprise_api_key
ADD COLUMN partner_id bigint COMMENT '合作伙伴ID';

-- 第二步:同步历史数据
UPDATE enterprise_api_key
SET partner_id = enterprise_id
WHERE partner_id IS NULL;

-- 第三步:代码层面对双字段支持
-- (业务代码适配,此处略)

-- 第四步:删除旧字段(计划中)
ALTER TABLE enterprise_api_key
DROP COLUMN enterprise_id;

二、现实:那个迟迟未剪的“小尾巴”

按照计划,新代码上线并稳定运行后,应立即执行最后一步——删除冗余的 enterprise_id 字段。然而实际情况是:

两天过去了,字段还在

一周过去了,字段依然在

直到10天后的今天,已经过去两个上线日了,这个字段还安静地留在表中

我也有提醒开发人员,得到的回复是:“好的,过两天就处理”或“下个版本一起清理”。结果,当我给新同学讲解 API接口加密算法升级 的优化工作时,我才注意到,这个字段依然存在。这个 enterprise_api_key 表中既有enterprise_id,又有partner_id,也给新同学带来了困惑。

三、反思:为什么“小尾巴”总能存活?

我们必须正视一个现实:人的本性是倾向于即时满足和回避繁琐的。一旦主体功能上线且运行正常,大脑便默认“核心问题已解决”,自动将清理、收尾这类不直接影响功能的工作归为“低优先级”。这种心理机制,正是“小尾巴”能够顽强存活的土壤。

更关键的是,没有明确的“剪尾巴”工具和时机。如果清理工作缺乏具体的操作指引、明确的执行节点和便捷的工具支持,那么“尽快处理”就只能停留在良好的愿望层面,无法转化为实际行动。

认识到这一点至关重要——我们不能仅仅依赖个人的自觉性或“好记性”。在持续交付、多任务并行的开发节奏中,任何没有明确边界、具体工具和强制约束的“收尾工作”,被遗忘是常态,被记住才是例外。

四、方案:解决问题要彻底————用明确的规则和准备对抗惯性

要让“解决问题要彻底”从口号变为实践,核心在于两项可立即落地的行动:准备好清晰的清理脚本,设定出严格的执行纪律

首先:提前准备好清理脚本

这是降低执行门槛、消除操作恐惧的关键一步。在方案评审阶段,就应准备好最终清理的SQL脚本,并确保其安全可靠。

-- 文件:drop_enterprise_id_column.sql
-- 描述:清理 ABA 迁移后的冗余字段 enterprise_id
-- 执行前提:新字段 partner_id 已稳定运行超过24小时,无异常

-- 1. 记录操作日志(可选,用于审计)
INSERT INTO schema_change_log (change_type, table_name, column_name, executed_by, executed_at)
VALUES ('DROP_COLUMN', 'enterprise_api_key', 'enterprise_id', CURRENT_USER, NOW());

-- 2. 执行清理(核心操作)
ALTER TABLE enterprise_api_key DROP COLUMN enterprise_id;

-- 3. 验证(可选,检查字段是否已删除)
-- SELECT COLUMN_NAME FROM INFORMATION_SCHEMA.COLUMNS WHERE TABLE_NAME = 'enterprise_api_key';
-- 也可直接查看 enterprise_api_key 表,或检查应用程序中的 entity 结构 
-- 预期结果中不应再出现 enterprise_id

然后:设定清理SLA(服务等级协议)

有了趁手的“剪刀”(脚本),还必须规定明确的“理发时间”。清理工作必须像发布上线一样,有明确、不可妥协的时间节点,形成强制纪律。

**字段清理SLA(服务等级协议)**
- 上线当天:生产验证通过后2小时内执行清理
- 最晚期限:上线次日凌晨的维护窗口
- 绝对红线:自上线起不超过72小时

为什么必须规定得如此严格?

  1. 在认知负担最低时动手:上线24小时内,技术上下文、数据关系、变更细节在开发者脑中最为鲜活。此时执行脚本,风险最小,效率最高。时间每过一天,理解和操作的成本都会显著上升。

  2. 切断拖延的退路:明确的最后期限,本质上是与“明天再处理”的拖延心理正面对抗。如果没有“72小时红线”,“稍后”在心理上就等于“完成”,清理任务几乎必然被后续的新需求冲走。

  3. 培养工程纪律:将“执行清理脚本”作为上线流程的强制性环节,通过重复执行形成肌肉记忆,最终内化为“定义完成”的一部分。

可落地的执行框架

  • 方案即承诺:在技术评审时,清理脚本和SLA就必须作为交付物的一部分,写入方案文档。
  • 流程即关卡:将“执行清理脚本”纳入上线Checklist。上线成功后的报告,必须包含“冗余字段已清理”的验证结果。
  • 监督即保障:建立简单的同步机制(如群机器人提醒),在SLA节点检查并播报结果,将依赖“人治”的问题转化为可见的“流程”问题。

五、结语:彻底是一种可培养的工程素养

在软件开发中,每一个被遗忘的“小尾巴”,都是未来某个时刻的“技术债”。它们可能默默占用资源,可能引发数据歧义,也可能在某个深夜让接手同事困惑不已。

“解决问题要彻底”——这不仅是态度,更是一种可通过清晰边界、趁手工具和严格流程培养的工程素养。它意味着我们不仅关注功能的“从无到有”,也同等重视工程现场的“整洁有序”。

从这次字段迁移的小故事开始,让我们在团队中建立这样的共识:每个变更都应有清晰的开始与干净的结束。而“尽快剪掉小尾巴”,是我们对自己作品的基本尊重,也是对并肩作战的伙伴们最可靠的承诺。

记住:最好的清理时机,一个是“上线时”,一个是“现在”。如果当时没剪,那么现在就是最好的第二个时机。

本文包含由AI生成的部分废话。