把代码换到可读性时踩过的坑
项目里有几个接口,每个都配了一堆描述,但用户还是天天来问:这个字段什么意思、那个参数是必填的吗、调用失败怎么办。
" —— 某个被文档折磨过的工程师
三年前开始做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 # 这项文档里根本没提
)
现在写示例代码,我会坚持几个原则:
- 能跑就别只是看。给个真实的请求和返回:
# 真实请求
response = client.create_user(
username="alice",
email="[email protected]",
password="SecurePass123!"
)
# 真实返回
# {
# "user_id": "user_abc123",
# "created_at": "2026-07-17T10:30:00Z",
# "status": "active"
# }
- 从简单到复杂。先给最基础的用法,再补上错误处理和高级配置:
# 基础用法
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}
)
- 注明前置条件。比如调用之前需要先获取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/) 转载或引用必须申明原指尖魔法屋来源及源地址!
评论
使用 GitHub 账号登录后即可留言,支持 Markdown。