在阅读《重构:改善既有代码的设计》时,第一条坏味道就是 Mysterious Name(神秘命名)。
很多代码的问题,其实不是逻辑复杂,而是名字太差。
好的命名应该清晰表达变量的用途和业务含义。
在所有重构手法中,改名(Rename)是最常用、也最值得投入时间的操作。
如果你发现自己想不出一个好名字,往往说明:
代码背后可能存在设计问题。
一、为什么命名这么重要
代码阅读的成本,大部分来自 理解变量含义。
例如:
let data = {}
let obj = {}
let temp = []
这些名字几乎没有提供任何信息。
而如果写成:
let customer = {}
let orderList = []
let totalPrice = 0
读者几乎不用思考就能理解代码。
所以命名的本质是:
降低理解成本。
二、如何命名(实践经验)
结合书中的建议和自己的实践,我总结了几个常用原则。
1. 表达业务含义,而不是技术细节
不要写:
data
obj
tmp
而是:
customer
orderList
totalPrice
命名应该反映业务语义。
2. 避免无意义缩写
例如:
usr
cfg
msgLst
可读性很差。
更好的写法:
user
config
messageList
除非是非常通用的缩写:
- id
- url
- api
- db
否则尽量避免。
3. 命名体现数据结构
名字最好能反映数据结构。
例如:
customer // 单个对象
customers // 数组
customerList // 列表
对于 Map / Dictionary:
customerById
userById
productIndex
这种命名在大型代码库中非常常见。
4. 在 JS/TS 中补充类型信息
《重构》里提到一句话:
在 JavaScript 这样的动态类型语言中,我喜欢把类型信息也放进名字里。
例如:
aCustomer
我觉得这个实践在 JS / TS 中仍然有价值。
常见命名模式:
单个对象
customer
aCustomer
集合
customers
customerList
Map / 字典
customerMap
customerById
productIndex
布尔值
isActive
hasPermission
canEdit
即使在 TypeScript 时代,命名依然重要。
因为很多代码库虽然用了 TS,但实际写法仍然接近 JS。
而好的命名可以显著降低阅读成本。
事实上,很多源码(如 Vue / React)也大量采用这种实践。
5. 根据作用域控制命名长度
命名不是越长越好,而是与作用域匹配。
局部表达式
例如:
array.map(x => x.id)
一个字母完全没问题。
短函数参数
function sum(a, b) {
return a + b
}
简短即可。
跨函数或复杂业务变量
如果变量在多个函数中使用,就需要更明确的命名:
currentLoginUser
selectedCustomerList
pendingPaymentOrders
三、封装变量(Encapsulate Variable)
书中的另一个建议是:
如果变量被广泛使用,可以考虑 封装变量。
核心思想是:
不要让变量被随意修改。
例如:
let price = 100
改为:
function getPrice() {
return price
}
function setPrice(value) {
price = value
}
这样可以:
- 控制修改入口
- 降低耦合
- 更容易维护
本质上就是:
将数据访问收敛到函数中。
四、注意“已发布变量”
书中还有一个非常重要的概念:
Published Variable(已发布变量)
如果变量已经被外部代码使用,就不能随便重构。
例如:
- npm 包 API
- SDK 导出变量
- 服务接口字段
- window/global 全局配置
示例:
window.APP_CONFIG
如果你直接重命名,很可能会导致外部系统崩溃。
正确做法应该是 兼容迁移:
旧变量 -> 标记废弃 -> 用户迁移 -> 大版本删除
例如:
// deprecated
window.APP_CONFIG = config
window.appConfig = config
等用户迁移完成后,在下一次 major version 删除旧变量。
五、引申:代码所有权边界
这背后其实是一个更大的设计理念:
代码所有权边界(Ownership Boundary)
一个真实系统往往包含:
- library
- SDK
- API
- 服务
- 数据库
如果没有明确的边界,就无法判断:
哪些代码可以安全重构,哪些不可以。
所以:
重构的前提是清楚代码的边界。
六、安全重命名的一种技巧
如果变量是 不可变的,可以采用一种更安全的方式重命名。
例如:
const oldVar = "PUBLIC_KEY_STRING"
步骤:
1️⃣ 新建变量
const newVar = "PUBLIC_KEY_STRING"
const oldVar = newVar
2️⃣ 逐步替换使用代码
3️⃣ 每次修改后运行测试
4️⃣ 最终删除旧变量
这样做的原因是:
JavaScript 可能存在动态访问:
obj['oldVar']
如果直接替换,很容易漏掉。
因此:
重命名之后一定要跑测试。
七、IDE 的重命名重构
很多人会用 全局搜索替换。
但这其实不是重构功能,很容易改错。
现代 IDE 都支持 语义级 Rename。
常见快捷键:
IntelliJ IDEA
Shift + F6
VSCode
F2
VSCode 依赖:
Language Server Protocol (LSP)
才能正确识别符号引用。
总结
好的命名,本质是让代码 更容易理解。
核心原则:
1️⃣ 表达业务语义,而不是技术细节
2️⃣ 避免无意义缩写
3️⃣ 命名体现数据结构
4️⃣ 在 JS/TS 中适当补充类型信息
5️⃣ 根据作用域控制命名长度
另外要注意:
- 已发布变量不要随便重构
- 理解代码所有权边界
- 使用 IDE 的 Rename 功能