1-2-1-代码是沟通而不是写给机器的

1.2.1 代码是沟通,而不是写给机器的

一个反直觉的真相

大多数人学编程时被告知:"编程就是告诉计算机做什么。"

这话没错,但不完整。更准确的说法是:

编程是告诉其他人,你想让计算机做什么。

计算机不在乎你的代码是否优雅、是否清晰、变量名是否有意义。只要语法正确,它都能执行。

但人在乎。

代码的两个读者

每一段代码都有两个读者:

1. 编译器/解释器(机器)

机器需要的:

  • 语法正确
  • 类型匹配(在静态类型语言中)
  • 逻辑可执行

机器不在乎的:

  • 变量名是 user 还是 u 还是 asdfgh
  • 缩进是 2 空格还是 4 空格
  • 有没有注释
  • 函数是叫 calculate_total 还是 func1

2. 人(包括未来的你)

人需要的:

  • 理解代码在做什么
  • 理解为什么这么做
  • 理解如何修改
  • 理解边界情况如何处理

人在乎的:

  • 变量名是否表达了含义
  • 结构是否清晰
  • 逻辑是否易于跟踪
  • 有没有解释复杂决策的注释

对比:写给机器的代码 vs 写给人的代码

示例1:计算购物车总价

写给机器的代码

def f(c):
    t = 0
    for i in c:
        t += i['p'] * i['q']
        if i['p'] * i['q'] > 100:
            t -= (i['p'] * i['q']) * 0.1
    return t

机器的理解:完全没问题,可以执行。

人的理解

  • f 是什么函数?
  • c 是什么?
  • i['p']i['q'] 是什么意思?
  • 为什么大于 100 要减去 10%?
  • 这个 10% 是折扣吗?

需要花费 2-3 分钟理解。

写给人的代码

def calculate_cart_total(cart_items):
    """
    计算购物车总价,单个商品满100元打9折

    Args:
        cart_items: 购物车商品列表,每个商品包含 price 和 quantity

    Returns:
        总价(已应用折扣)
    """
    total = 0

    for item in cart_items:
        item_subtotal = item['price'] * item['quantity']

        # 单个商品满100元,享受9折优惠
        if item_subtotal > 100:
            discount = item_subtotal * 0.1
            item_subtotal -= discount

        total += item_subtotal

    return total

人的理解:30秒内完全明白。

代价:多了几行代码,多了几个字符。

收益

  • 6个月后的你能立即理解
  • 新同事能快速上手
  • 需求变更时知道改哪里
  • Code Review 时能快速发现问题

示例2:验证邮箱格式

写给机器的代码

const v = (e) => /^[^\s@]+@[^\s@]+\.[^\s@]+$/.test(e);

写给人的代码

function isValidEmail(email) {
    // 简单的邮箱格式验证
    // 格式:任意字符 + @ + 任意字符 + . + 任意字符
    // 注意:这不是完整的 RFC 5322 验证,只是基本检查
    const emailRegex = /^[^\s@]+@[^\s@]+\.[^\s@]+$/;
    return emailRegex.test(email);
}

额外信息

  • 函数名清楚表达了意图
  • 注释说明了验证的程度(不是完整的RFC标准)
  • 给正则表达式起了个有意义的变量名

沟通的多个维度

代码作为沟通工具,传递多个维度的信息:

1. What(做什么)

通过代码本身传达

# 清楚:代码自解释
active_users = [user for user in users if user.is_active]

# 不清楚:需要猜测
result = [x for x in data if x.status == 1]  # status=1 代表什么?

2. Why(为什么)

通过注释传达

# 清楚:解释了业务原因
# 根据财务部门要求,订单金额需要保留2位小数
# 避免出现 0.1 + 0.2 = 0.30000000000000004 的精度问题
order_total = Decimal(str(subtotal)).quantize(Decimal('0.01'))

# 不清楚:没有解释为什么
order_total = Decimal(str(subtotal)).quantize(Decimal('0.01'))

3. How(如何做)

通过清晰的结构传达

# 清楚:分步骤,每步都明确
def process_order(order):
    validate_order(order)
    apply_discount(order)
    calculate_tax(order)
    charge_payment(order)
    send_confirmation(order)

# 不清楚:所有逻辑混在一起
def process_order(order):
    if order.items and order.user:
        t = 0
        for i in order.items:
            t += i.price
        if order.coupon:
            t = t * 0.9
        t = t * 1.1
        payment.charge(order.user.card, t)
        email.send(order.user.email, "ok")

4. When(什么情况下)

通过条件判断的命名传达

# 清楚:条件有明确含义
if is_premium_user(user) and has_valid_subscription(user):
    grant_access()

# 不清楚:魔法数字和不清楚的条件
if user.level > 3 and user.status == 1:
    grant_access()

真实案例:代码即文档

案例:Stripe 的 API 设计

Stripe 的 API 被认为是业界最清晰的 API 之一。看看他们的代码风格:

# Stripe 的设计
stripe.Charge.create(
    amount=2000,  # 金额:20.00美元
    currency="usd",
    source="tok_visa",
    description="Charge for test@example.com"
)

# 如果是"写给机器的"风格
stripe.c(2000, "usd", "tok_visa", "Charge for test@example.com")

为什么 Stripe 成功?

因为他们理解:API 的调用者是人,不是机器。 清晰的 API 能降低学习成本,减少出错,提高开发者满意度。

案例:Linux 内核的注释文化

Linux 内核以代码质量著称,其中一个重要原因是严格的注释规范:

/*
 * We don't want to keep the lock while loading the file from disk,
 * so we release the lock, load the file, then re-acquire the lock.
 *
 * This is safe because the file content is immutable once written.
 */
unlock(&cache_lock);
data = load_from_disk(filename);
lock(&cache_lock);

注释解释了

  • 为什么要释放锁(避免持锁时间过长)
  • 为什么这样做是安全的(文件内容不可变)

这些信息机器不需要,但对理解代码的人来说至关重要。

对使用 AI 的程序员的特别建议

AI 生成的代码往往是"机器友好"的,但不一定是"人类友好"的。

AI 代码的常见问题

  1. 变量名过于简洁

    # AI 可能生成
    def proc(d, u, t):
        return calc(d, u) * t
    
    # 应该改成
    def process_transaction(data, user, tax_rate):
        base_amount = calculate_base(data, user)
        return base_amount * tax_rate
    
  2. 缺少解释复杂逻辑的注释

    # AI 生成
    result = sorted(items, key=lambda x: (x.priority, -x.created_at))
    
    # 应该改成
    # 排序规则:
    # 1. 优先级高的在前(priority 小的在前,1 > 2 > 3)
    # 2. 相同优先级时,创建时间晚的在前(降序)
    result = sorted(items, key=lambda x: (x.priority, -x.created_at))
    
  3. 函数做了太多事情,但名字不能体现

    # AI 生成
    def get_user(id):
        user = db.get(id)
        log_access(user)
        update_last_seen(user)
        return user
    
    # 应该拆分或改名
    def get_and_track_user(id):
        """获取用户信息,并记录访问日志、更新最后访问时间"""
        user = db.get(id)
        log_access(user)
        update_last_seen(user)
        return user
    

改进AI代码的流程

  1. 生成后必须重命名:把所有过于简洁的变量名改成有意义的
  2. 添加关键注释:解释"为什么",而不是"是什么"
  3. 检查函数职责:一个函数是否做了太多事情
  4. 添加文档字符串:说明参数、返回值、可能的异常

实践原则

1. 变量名即文档

不好 更好
t total cart_total_after_discount
d data user_profile_data
i item cart_item
f flag is_premium_user

例外:在非常小的作用域内(如循环中的 i, j),简短名字是可以接受的。

# 可以接受
for i in range(10):
    print(i)

# 应该改进
for i in users:
    process(i)

# 更好
for user in users:
    process_user(user)

2. 函数名即规格说明

函数名应该回答:

  • 做什么(动词开头)
  • 对什么对象(名词)
  • 返回什么(或修改了什么)
# 不够清楚
def user(id): ...

# 更清楚
def get_user(id): ...

# 最清楚
def get_active_user_by_id(id): ...

3. 注释即设计文档

好的注释解释:

  • 为什么这样做(业务原因、性能考虑)
  • 为什么不那样做(排除了哪些替代方案)
  • 有哪些边界情况或限制

不好的注释重复代码:

# 不好的注释
# 获取用户
user = get_user(id)

# 好的注释
# 这里使用缓存的用户信息,而不是实时查询数据库
# 因为用户信息更新频率低(每天 < 10次),而读取频率高(每秒 > 1000次)
# 缓存过期时间设置为 5 分钟
user = get_cached_user(id)

4. 结构即架构图

代码的组织方式应该反映系统的架构:

# 不清楚的结构
user_repo.py        # 2000行,包含用户、订单、支付所有逻辑

# 清楚的结构
user/
    repository.py   # 用户数据访问
    service.py      # 用户业务逻辑
    validators.py   # 用户数据验证
order/
    repository.py
    service.py
payment/
    repository.py
    service.py

一眼就能看出系统的模块划分。

检查清单:你的代码是否在沟通

写完代码后,问自己:

如果有任何一项答案是"不能"或"不确定",代码需要改进。

代码审查的真正目的

Code Review 不是为了找茬,而是检查代码是否在有效沟通:

不好的 Code Review 评论

"这个变量名不符合规范。"

好的 Code Review 评论

"这个变量名 data 太宽泛了,6 个月后我们可能记不清它代表什么。建议改成 user_profile_data,这样一眼就知道它存的是用户资料。"

总结

代码的本质是沟通工具:

  1. 机器能理解任何合法的代码 —— 但人类需要清晰、有意义的代码
  2. 代码被读的次数远多于被写的次数 —— 为读者优化,而不是为编写速度优化
  3. 好的代码是自解释的 —— 命名、结构、注释共同传达设计意图
  4. AI 生成的代码需要人类润色 —— 让它从"机器友好"变成"人类友好"
  5. 清晰度是第一优先级 —— 性能可以后期优化,但混乱的代码会永久性拖累团队

记住:

你不是在写代码,你是在写一封给未来维护者的信。

这个维护者可能是你的同事,可能是你的继任者,很可能就是6个月后的你自己。

写得清楚一点,未来会感谢你的。

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