1-3-2-命名哲学

1.3.2 命名哲学:命名是小型哲学思考

引言

Phil Karlton 有句名言:

"计算机科学中只有两件难事:缓存失效和命名。"

为什么命名这么难?

因为命名是一个哲学问题——你需要理解一个事物的本质,然后用一个词或短语精确地表达它。

好的命名不仅仅是"听起来不错",而是:

  • 准确反映事物的本质
  • 符合读者的心智模型
  • 在系统中保持一致
  • 随时间推移仍然有意义

命名的本质:抽象的具体化

命名是把抽象的概念变成具体的符号。

# 抽象概念:一个保存用户信息的数据结构
# 具体化1
x = {...}

# 具体化2
data = {...}

# 具体化3
user_info = {...}

# 具体化4
user_profile = {...}

每一层具体化都在传达更多信息。

x:没有传达任何信息
data:传达了"这是数据"
user_info:传达了"这是用户的信息"
user_profile:传达了"这是用户的档案资料"

命名的层次

层次1:描述是什么(What)

# 差
a = 25

# 一般
number = 25

# 好
age = 25

# 更好
user_age_in_years = 25

层次2:描述做什么(Do)

# 差
def process(data): ...

# 一般
def handle(data): ...

# 好
def validate_user_input(data): ...

# 更好
def validate_and_sanitize_user_input(data): ...

层次3:揭示意图(Intent)

# 描述"做什么"
def filter_items(items, status):
    return [item for item in items if item.status == status]

# 揭示"为什么"
def get_active_items(items):
    """获取所有活跃的项目(用于展示给用户)"""
    return [item for item in items if item.status == 'active']

常见的命名反模式

反模式1:无意义的前缀/后缀

# 不好:无意义的前缀
myVariable = 10
theUser = get_user()
aList = []

# 不好:匈牙利命名法(在现代语言中)
strName = "Alice"
intAge = 25
boolIsActive = True

# 好:直接用有意义的名字
name = "Alice"
age = 25
is_active = True

例外:在特定上下文中有意义的前缀是可以的

# 好:区分原始值和处理后的值
raw_text = "  Hello World  "
cleaned_text = raw_text.strip()

# 好:区分不同类型的ID
user_id = 123
order_id = 456

反模式2:过于通用的名字

# 不好
def process(data):
    ...

def handle(input):
    ...

def do_something(x, y):
    ...

# 好
def validate_email(email_address):
    ...

def send_welcome_notification(new_user):
    ...

def calculate_shipping_cost(weight, distance):
    ...

反模式3:缩写和简写

# 不好
def calc_tot_prc(itms):
    tot = 0
    for i in itms:
        tot += i.prc * i.qty
    return tot

# 好
def calculate_total_price(items):
    total = 0
    for item in items:
        total += item.price * item.quantity
    return total

例外:广为人知的缩写是可以的

# 可以接受的缩写
html = "<div>...</div>"
json = {"key": "value"}
url = "https://example.com"
id = 123
max_size = 1024
min_value = 0

反模式4:单词拼写错误

# 不好
def send_notifaction(user):  # typo: notifaction
    ...

def get_usr_permisions(user):  # typo: permisions
    ...

# 好
def send_notification(user):
    ...

def get_user_permissions(user):
    ...

注意:拼写错误会传播,6个月后你可能忘了是哪个错误拼写。

反模式5:名字说谎

# 不好:名字和实际行为不符
def get_user(user_id):
    user = db.query(User).get(user_id)
    if not user:
        # 名字说"get",但实际上会"create"
        user = create_default_user(user_id)
    return user

# 好:名字如实反映行为
def get_or_create_user(user_id):
    user = db.query(User).get(user_id)
    if not user:
        user = create_default_user(user_id)
    return user

# 或者分成两个函数
def get_user(user_id):
    return db.query(User).get(user_id)

def ensure_user_exists(user_id):
    user = get_user(user_id)
    if not user:
        user = create_default_user(user_id)
    return user

命名的规则和模式

规则1:布尔值用 is/has/can/should

# 不好
user_active = True
user_permissions = True
user_delete = True

# 好
is_active = True
has_permissions = True
can_delete = True
should_notify = True

规则2:集合用复数

# 不好
user_list = [user1, user2]
active_user = [user1, user2]  # 看起来像单个用户

# 好
users = [user1, user2]
active_users = [user1, user2]

规则3:函数用动词开头

# 不好
user_email(user)
user_validation(data)

# 好
send_user_email(user)
validate_user_data(data)

常见动词

  • get_*: 获取(不修改)
  • set_*: 设置
  • create_*: 创建新对象
  • delete_*: 删除
  • update_*: 更新现有对象
  • find_*: 查找(可能找不到)
  • calculate_*: 计算
  • validate_*: 验证
  • send_*: 发送
  • process_*: 处理

规则4:对称命名

# 不好
def open_connection(): ...
def terminate(): ...

# 好
def open_connection(): ...
def close_connection(): ...

# 不好
def start_server(): ...
def kill(): ...

# 好
def start_server(): ...
def stop_server(): ...

常见对称词

  • open / close
  • start / stop
  • begin / end
  • create / delete
  • add / remove
  • insert / delete
  • lock / unlock
  • acquire / release

规则5:保持作用域一致的详细程度

# 局部变量:可以简短
def calculate_total(items):
    total = 0  # 作用域小,可以简短
    for item in items:  # 循环变量可以简短
        total += item.price
    return total

# 全局变量/常量:必须详细
DATABASE_CONNECTION_POOL_SIZE = 10  # 全局作用域,必须清楚

# 类属性:中等详细
class Order:
    status = 'pending'  # 在类的上下文中,status 就够了
    created_at = datetime.now()

命名的文化差异

Python 风格

# Snake case for variables and functions
user_name = "Alice"
def get_user_profile(): ...

# Pascal case for classes
class UserProfile: ...

# UPPER_CASE for constants
MAX_UPLOAD_SIZE = 1024

JavaScript 风格

// Camel case for variables and functions
const userName = "Alice";
function getUserProfile() { ... }

// Pascal case for classes
class UserProfile { ... }

// UPPER_CASE for constants
const MAX_UPLOAD_SIZE = 1024;

Go 风格

// Public (exported): starts with uppercase
func GetUserProfile() { ... }
var UserName string

// Private: starts with lowercase
func validateEmail() { ... }
var internalState int

在团队中保持统一比个人偏好更重要。

领域驱动的命名

使用业务领域的术语

# 不好:技术术语
def process_transaction(data):
    record = DatabaseRecord(**data)
    record.save()

# 好:业务术语
def place_order(order_details):
    order = Order(**order_details)
    order.save()

避免技术泄漏

# 不好:暴露实现细节
def get_user_from_redis_cache(user_id): ...
def save_to_postgres_database(data): ...

# 好:隐藏实现细节
def get_cached_user(user_id): ...
def save_user(user): ...

如果未来从 Redis 切换到 Memcached,第一种命名就需要改,第二种不需要。

重命名的勇气

何时应该重命名

  • 名字不能准确反映功能(需求变更导致)
  • 发现更好的术语
  • 团队达成新的命名共识
# 旧代码
def send_email(user):
    # 后来需求变了,不仅发邮件,还发短信
    email_service.send(user.email)
    sms_service.send(user.phone)

# 应该重命名
def send_notification(user):
    email_service.send(user.email)
    sms_service.send(user.phone)

如何安全重命名

  1. 使用 IDE 的重构功能(不是手动查找替换)
  2. 先写测试确保重命名不破坏功能
  3. 批量重命名,不要留下新旧名字混用的状态
  4. 更新文档和注释

对使用 AI 的程序员的建议

AI 生成的命名往往是"安全的"但不一定是"最好的"。

AI 命名的常见问题

# AI 可能生成
def process_data(data):
    result = do_something(data)
    return result

# 应该改成
def validate_user_registration(registration_form):
    validation_result = check_all_required_fields(registration_form)
    return validation_result

如何改进 AI 生成的命名

  1. 检查所有 dataresultitem 等通用名字
  2. 用业务术语替换技术术语
  3. 确保动词准确描述行为
❌ 不好的提示:
"写一个函数处理用户数据"

✅ 好的提示:
"写一个函数 validate_user_registration_form,它接收注册表单数据,
验证所有必填字段,返回验证结果(包含 is_valid 和 errors 列表)"

命名检查清单

完成代码后,检查每个名字:

变量名

函数名

类名

真实案例

案例1:Ruby on Rails 的命名约定

Rails 有严格的命名约定,让代码高度一致:

# 模型(单数)
class User < ApplicationRecord
end

# 表名(复数)
# users

# 控制器(复数)
class UsersController < ApplicationController
  def index    # GET /users
  def show     # GET /users/:id
  def create   # POST /users
  def update   # PUT /users/:id
  def destroy  # DELETE /users/:id
end

这种一致性让新人能快速理解代码结构。

案例2:Stripe API 的命名

Stripe 的 API 命名清晰且一致:

# 创建
stripe.Customer.create(email="user@example.com")
stripe.Charge.create(amount=1000, currency="usd")

# 获取
stripe.Customer.retrieve("cus_123")
stripe.Charge.retrieve("ch_123")

# 更新
stripe.Customer.modify("cus_123", email="new@example.com")

# 删除
stripe.Customer.delete("cus_123")

每个资源都使用相同的动词,降低了学习成本。

总结

命名的哲学:

  1. 命名是理解的体现——好的命名来自对事物本质的深刻理解
  2. 准确比简短更重要——user_age_in_yearsage 好(如果精度重要)
  3. 一致性是关键——在整个项目中保持命名风格统一
  4. 使用领域术语——让业务人员也能读懂代码
  5. 不要害怕重命名——发现更好的名字时,立即改
  6. AI 生成的命名需要人工审查——改成更精确的业务术语

记住:

你今天多花 30 秒想一个好名字,能为未来的维护者(包括你自己)节省 30 分钟的理解时间。

命名不是小事,而是每天都在进行的小型哲学思考。

好的命名让代码自解释,差的命名让代码需要注释,糟糕的命名让代码无法理解。

posted @ 2025-11-29 21:54  Jack_Q  阅读(0)  评论(0)    收藏  举报