把代码换到可读性时踩过的坑

项目里有几个接口,每个都配了一堆描述,但用户还是天天来问:这个字段什么意思、那个参数是必填的吗、调用失败怎么办。

" —— 某个被文档折磨过的工程师

三年前开始做API开发的时候,我也经历过那段"写文档像写说明书"的时期。

从代码注释开始

先看个真实的反面教材。这是我刚入职时写的一段代码注释:

def process_data(data):
    """
    处理数据函数

    Args:
        data: 数据

    Returns:
        返回处理后的数据
    """
    # 处理逻辑
    result = data.strip().lower()
    return result

这个注释除了告诉我"这是个函数",什么信息都没给。真正有用的注释应该是解释"为什么这样做",而不是重复"做了什么":

def process_data(data):
    """
    去除首尾空白并转为小写,用于统一比较前的数据清洗。

    注意:如果需要保留原始大小写或内部空白,使用 parse_data() 代替。

    Args:
        data: 待处理的字符串

    Returns:
        str: 清洗后的字符串
    """
    result = data.strip().lower()
    return result

第二个版本多了几个关键点:说明目的、给出注意事项、告诉读者"如果不行就试试别的"。

这种注释不是给机器看的,是给三个月后的自己看的。那时候你早忘了为什么要先 strip 再 lower,但一句注释就能省掉半小时的重新推理。

API文档的坑

API文档最容易被吐槽的就是"说得不清楚"。比如一个用户创建接口:

POST /api/users
创建一个新用户

这个描述太笼统。用户真正想知道的是:

POST /api/users
创建一个新用户,并返回用户ID和初始token。注意:用户名重复会返回 409 错误。

参数描述也很关键。比如这个:

username: 用户名

这种等于没说。可以改成:

username: 用户名,3-20个字符,只能包含字母、数字和下划线。大小写敏感。

我踩过最大的坑是在某个项目里,文档里写"max_length: 最大长度",但实际实现是按字节算的,而不是字符。结果一堆中文用户上传的内容被截断,浪费了半天排查。

所以现在写API文档,我会特别注意两点:

第一,参数限制写具体。“必填/可选"是基础,“长度限制、取值范围、特殊规则"才是关键:

# 推荐写法
parameters:
  - name: status
    type: string
    required: true
    description: |
      订单状态,可选值:
      - pending: 待支付
      - paid: 已支付
      - shipped: 已发货
      - completed: 已完成
      注意:状态只能单向流转,不能从 completed 回退到 paid。

第二,错误信息说清楚原因。不要只写"400 Bad Request”,要说明"用户名长度小于3个字符"或"缺少必填字段 email”。

示例代码的真实性

示例代码最容易"忽悠人"。我见过最离谱的是文档里的示例可以直接运行,但参数是假的:

# 文档里的示例
client.create_user(username="test_user", email="[email protected]")

# 实际调用时发现还需要一堆必填参数
client.create_user(
    username="test_user",
    email="[email protected]",
    password="must_be_8_chars",
    region="us-west-1",
    accept_tos=True  # 这项文档里根本没提
)

现在写示例代码,我会坚持几个原则:

  1. 能跑就别只是看。给个真实的请求和返回:
# 真实请求
response = client.create_user(
    username="alice",
    email="[email protected]",
    password="SecurePass123!"
)

# 真实返回
# {
#   "user_id": "user_abc123",
#   "created_at": "2026-07-17T10:30:00Z",
#   "status": "active"
# }
  1. 从简单到复杂。先给最基础的用法,再补上错误处理和高级配置:
# 基础用法
client.create_user(username="alice", email="[email protected]")

# 带错误处理
try:
    user = client.create_user(username="alice", email="[email protected]")
except UserExistsError:
    print("用户已存在")

# 完整配置
user = client.create_user(
    username="alice",
    email="[email protected]",
    profile={"age": 28, "city": "Beijing"},
    settings={"notifications": True}
)
  1. 注明前置条件。比如调用之前需要先获取token、配置region、或者某些API需要企业版权限。

文档与代码的同步问题

最大的坑还是文档和代码不同步。改了接口忘了改文档,文档里的参数名早就被重构掉了,这种情况我至少遇到过十次。

现在我们的做法是:

第一,把文档放在代码旁边。比如在同一个仓库里,API的定义和文档用同一套schema:

from pydantic import BaseModel, Field

class UserCreateRequest(BaseModel):
    username: str = Field(..., min_length=3, max_length=20, description="用户名,3-20个字符")
    email: str = Field(..., description="邮箱地址")

    class Config:
        json_schema_extra = {
            "examples": [
                {
                    "username": "alice",
                    "email": "[email protected]"
                }
            ]
        }

这样修改字段时,文档会自动更新,不容易忘记。

第二,把文档检查纳入code review。提交PR的时候, reviewers 要检查代码改动是否需要更新文档,有没有相关的注释或示例需要调整。

第三,定期过一遍文档和代码。我们有个"文档维护日",每个月抽半天时间,随机抽查几个接口,对照文档和实际实现,记录不一致的地方然后修复。

用AI辅助文档的一些经验

最近用ChatGPT帮忙生成API文档,发现有几个技巧:

第一,别让它"生成完整文档",而是让它"补全以下信息的限制条件和错误情况"。这样你给框架,它补细节,质量比让它从头写要高。

第二,让它举反例。比如问"这个函数在什么情况下会抛出异常",比问"这个函数怎么用"更有用。

第三,让它检查一致性。把API定义贴给它,问"有没有明显的限制条件没有说明",比自己逐项检查快。

但AI也不是万能。它生成的示例代码经常用一些不存在的参数,或者默认一些假设。所以最后还是要人工审查一遍。

一些不算总结的总结

文档工作确实烦人,每次改代码都得想文档要不要跟着改。但想清楚一件事:代码是写一遍读多次的,文档也是。省一次更新文档的时间,可能要花十次在回答重复问题上。

有些经验我也还在摸索:比如什么样的文档算"过度"、怎么平衡详细度和简洁、不同团队怎么保持文档风格一致。不过先把基本的注释、参数说明、示例代码写好,已经能解决80%的问题了。

如果你也在写API文档,不妨从今天开始:下次改接口的时候,顺手把文档更新了。三个月后的你会感谢现在自己做的这件事。

版权声明: 本文首发于 指尖魔法屋-把代码换到可读性时踩过的坑https://blog.thinkmoon.cn/post/204-ai-doc-best-practice/) 转载或引用必须申明原指尖魔法屋来源及源地址!