代码文档
概览
使用特定语言的标准创建清晰、全面的代码文档,如JSDoc、Python docstrings、JavaDoc和内联注释。
何时使用
- 函数和类文档
- JavaScript/TypeScript的JSDoc
- Python的docstrings
- Java的JavaDoc
- 内联代码注释
- 从代码生成API文档
- 类型定义
- 代码中的使用示例
JavaScript/TypeScript (JSDoc)
函数文档
/**
* 计算包括税和折扣在内的总价。
*
* @param {number} basePrice - 税前和折扣前的基础价格
* @param {number} taxRate - 以小数形式表示的税率(例如,0.08表示8%)
* @param {number} [discount=0] - 可选的折扣金额
* @returns {number} 税和折扣后的最终价格
* @throws {Error} 如果basePrice或taxRate为负数
*
* @example
* const price = calculateTotalPrice(100, 0.08, 10);
* console.log(price); // 98
*
* @example
* // 没有折扣
* const price = calculateTotalPrice(100, 0.08);
* console.log(price); // 108
*/
function calculateTotalPrice(basePrice, taxRate, discount = 0) {
if (basePrice < 0 || taxRate < 0) {
throw new Error('价格和税率必须非负');
}
return basePrice * (1 + taxRate) - discount;
}
/**
* 从API获取用户数据,并包含重试逻辑。
*
* @async
* @param {string} userId - 用户的唯一标识符
* @param {Object} [options={}] - 额外选项
* @param {number} [options.maxRetries=3] - 最大重试次数
* @param {number} [options.timeout=5000] - 请求超时时间,以毫秒为单位
* @returns {Promise<User>} 解析为用户对象的Promise
* @throws {Error} 如果重试后用户仍未找到
*
* @typedef {Object} User
* @property {string} id - 用户ID
* @property {string} name - 用户的全名
* @property {string} email - 用户的电子邮件地址
* @property {string[]} roles - 用户角色数组
*
* @example
* try {
* const user = await fetchUser('user123', { maxRetries: 5 });
* console.log(user.name);
* } catch (error) {
* console.error('获取用户失败:', error);
* }
*/
async function fetchUser(userId, options = {}) {
const { maxRetries = 3, timeout = 5000 } = options;
// 实现...
}
类文档
/**
* 表示电子商务应用中的购物车。
* 管理商品、计算总计和处理结账操作。
*
* @class
* @example
* const cart = new ShoppingCart('user123');
* cart.addItem({ id: 'prod1', name: 'Laptop', price: 999.99 }, 1);
* console.log(cart.getTotal()); // 999.99
*/
class ShoppingCart {
/**
* 创建一个新的购物车实例。
*
* @constructor
* @param {string} userId - 拥有此购物车的用户ID
* @param {Object} [options={}] - 配置选项
* @param {string} [options.currency='USD'] - 货币代码
* @param {number} [options.taxRate=0] - 以小数形式表示的税率
*/
constructor(userId, options = {}) {
this.userId = userId;
this.items = [];
this.currency = options.currency || 'USD';
this.taxRate = options.taxRate || 0;
}
/**
* 向购物车添加商品或增加已有商品的数量。
*
* @param {Product} product - 要添加的商品
* @param {number} quantity - 要添加的数量(必须是正整数)
* @returns {CartItem} 添加或更新后的购物车商品
* @throws {Error} 如果数量不是正整数
*
* @typedef {Object} Product
* @property {string} id - 商品ID
* @property {string} name - 商品名称
* @property {number} price - 商品价格
*
* @typedef {Object} CartItem
* @property {Product} product - 商品详情
* @property {number} quantity - 商品数量
* @property {number} subtotal - 商品小计(价格 * 数量)
*/
addItem(product, quantity) {
if (!Number.isInteger(quantity) || quantity <= 0) {
throw new Error('数量必须是正整数');
}
const existingItem = this.items.find(
item => item.product.id === product.id
);
if (existingItem) {
existingItem.quantity += quantity;
existingItem.subtotal = existingItem.product.price * existingItem.quantity;
return existingItem;
}
const newItem = {
product,
quantity,
subtotal: product.price * quantity
};
this.items.push(newItem);
return newItem;
}
/**
* 计算包括税在内的总价。
*
* @returns {number} 含税的总价
*/
getTotal() {
const subtotal = this.items.reduce(
(sum, item) => sum + item.subtotal,
0
);
return subtotal * (1 + this.taxRate);
}
/**
* 清空购物车中的所有商品。
*
* @returns {void}
*/
clear() {
this.items = [];
}
}
类型定义
/**
* 所有端点的API响应包装器
*
* @template T - 响应中的数据类型
* @typedef {Object} ApiResponse
* @property {boolean} success - 请求是否成功
* @property {T} [data] - 响应数据(成功时存在)
* @property {string} [error] - 错误消息(失败时存在)
* @property {Object} [metadata] - 额外的响应元数据
* @property {number} metadata.timestamp - 响应时间戳
* @property {string} metadata.requestId - 唯一的请求ID
*/
/**
* 用户认证凭证
*
* @typedef {Object} Credentials
* @property {string} email - 用户电子邮件地址
* @property {string} password - 用户密码(最少8个字符)
*/
/**
* 列表端点的分页参数
*
* @typedef {Object} PaginationParams
* @property {number} [page=1] - 页码(1索引)
* @property {number} [limit=20] - 每页项目数(最多100)
* @property {string} [sortBy='createdAt'] - 排序字段
* @property {'asc'|'desc'} [order='desc'] - 排序顺序
*/
Python (Docstrings)
函数文档
def calculate_statistics(data: list[float], include_median: bool = True) -> dict:
"""
计算数据集的统计量。
计算数值列表的平均值、标准差、最小值、最大值,以及可选的中位数。
参数:
data: 要分析的数值列表。必须至少包含一个值。
include_median: 是否计算中位数(默认:True)。
对于大型数据集,设置为False以获得更好的性能。
返回:
包含以下键的字典:
- 'mean' (float): 数据的算术平均值
- 'std' (float): 标准差
- 'min' (float): 最小值
- 'max' (float): 最大值
- 'median' (float): 中位数(如果include_median为True)
- 'count' (int): 数据点数量
引发:
ValueError: 如果数据为空或包含非数值。
TypeError: 如果数据不是列表。
示例:
>>> data = [1, 2, 3, 4, 5]
>>> stats = calculate_statistics(data)
>>> print(stats['mean'])
3.0
>>> # 不计算中位数以提高性能
>>> large_data = list(range(1000000))
>>> stats = calculate_statistics(large_data, include_median=False)
注意:
对于非常大的数据集,考虑将include_median设置为False
因为中位数计算需要排序,这是O(n log n)的操作。
参见:
numpy.mean, numpy.std, statistics.median
"""
if not isinstance(data, list):
raise TypeError("数据必须是列表")
if not data:
raise ValueError("数据不能为空")
mean = sum(data) / len(data)
variance = sum((x - mean) ** 2 for x in data) / len(data)
std = variance ** 0.5
result = {
'mean': mean,
'std': std,
'min': min(data),
'max': max(data),
'count': len(data)
}
if include_median:
sorted_data = sorted(data)
n = len(sorted_data)
if n % 2 == 0:
result['median'] = (sorted_data[n//2 - 1] + sorted_data[n//2]) / 2
else:
result['median'] = sorted_data[n//2]
return result
类文档
class DatabaseConnection:
"""
管理数据库连接,自动重试和连接池。
这个类提供了数据库操作的上下文管理器接口,
处理连接建立、查询执行和清理。
属性:
host (str): 数据库主机地址
port (int): 数据库端口号
database (str): 数据库名称
max_retries (int): 最大连接重试次数
timeout (int): 连接超时时间,以秒为单位
pool_size (int): 连接池中的最大连接数
示例:
上下文管理器的基本使用:
>>> with DatabaseConnection('localhost', 5432, 'mydb') as db:
... results = db.execute('SELECT * FROM users')
... for row in results:
... print(row)
自定义配置:
>>> config = {
... 'max_retries': 5,
... 'timeout': 30,
... 'pool_size': 10
... }
>>> db = DatabaseConnection('localhost', 5432, 'mydb', **config)
注意:
总是使用这个类作为上下文管理器,以确保正确的
连接清理。不推荐手动连接管理。
警告:
连接不是线程安全的。对于并发操作,请创建单独的实例。
"""
def __init__(
self,
host: str,
port: int,
database: str,
username: str = None,
password: str = None,
max_retries: int = 3,
timeout: int = 10,
pool_size: int = 5
):
"""
初始化一个新的数据库连接管理器。
参数:
host: 数据库服务器主机名或IP地址
port: 数据库服务器端口(通常PostgreSQL为5432)
database: 要连接的数据库名称
username: 数据库用户名(默认:来自环境)
password: 数据库密码(默认:来自环境)
max_retries: 连接失败时的最大重试次数
timeout: 连接超时时间,以秒为单位
pool_size: 连接池中的最大连接数
引发:
ValueError: 如果host、port或database无效
ConnectionError: 如果无法建立初始连接
"""
self.host = host
self.port = port
self.database = database
self.max_retries = max_retries
self.timeout = timeout
self.pool_size = pool_size
self._connection = None
self._pool = []
def execute(self, query: str, params: tuple = None) -> list:
"""
执行SQL查询并返回结果。
参数:
query: SQL查询字符串,可选参数占位符
params: 参数化查询的参数值元组
返回:
以列名作为键的字典形式的行列表
引发:
QueryError: 如果查询执行失败
ConnectionError: 如果数据库连接丢失
示例:
>>> db = DatabaseConnection('localhost', 5432, 'mydb')
>>> results = db.execute(
... 'SELECT * FROM users WHERE age > %s',
... (18,)
... )
"""
pass
def __enter__(self):
"""进入上下文管理器,建立数据库连接。"""
self.connect()
return self
def __exit__(self, exc_type, exc_val, exc_tb):
"""退出上下文管理器,关闭数据库连接。"""
self.close()
模块文档
"""
用户认证和授权模块。
这个模块提供用户认证、密码散列、令牌生成和权限检查的功能。它支持包括JWT令牌、API密钥和OAuth2在内的多种认证方法。
特性:
- 使用bcrypt进行安全的密码散列
- JWT令牌生成和验证
- 基于角色的访问控制(RBAC)
- OAuth2集成(Google、GitHub)
- 双因素认证(2FA)
示例:
基本认证:
>>> from auth import authenticate, generate_token
>>> user = authenticate('user@example.com', 'password123')
>>> token = generate_token(user)
密码散列:
>>> from auth import hash_password, verify_password
>>> hashed = hash_password('password123')
>>> is_valid = verify_password('password123', hashed)
属性:
TOKEN_EXPIRY (int): 默认令牌有效期,以秒为单位
HASH_ROUNDS (int): bcrypt散列轮数
MAX_LOGIN_ATTEMPTS (int): 最大失败登录尝试次数,超过将锁定
待办:
* 添加对SAML认证的支持
* 实现刷新令牌轮换
* 添加登录尝试的速率限制
注意:
这个模块需要安装bcrypt和PyJWT包。
"""
TOKEN_EXPIRY = 3600 # 1小时
HASH_ROUNDS = 12
MAX_LOGIN_ATTEMPTS = 5
Java (JavaDoc)
/**
* 管理系统中的用户账户和认证。
* <p>
* 这个类提供创建、更新和删除用户账户的方法,以及认证用户和管理会话。
* </p>
*
* <h2>使用示例:</h2>
* <pre>{@code
* UserManager manager = new UserManager();
* User user = manager.createUser("john@example.com", "password123");
* boolean authenticated = manager.authenticate(user.getId(), "password123");
* }</pre>
*
* @author John Doe
* @version 2.0
* @since 1.0
* @see User
* @see Session
*/
public class UserManager {
/**
* 使用指定的凭证创建新用户账户。
*
* @param email 用户电子邮件地址(必须有效且唯一)
* @param password 用户密码(最少8个字符)
* @return 新创建的User对象
* @throws IllegalArgumentException 如果电子邮件无效或已存在
* @throws PasswordTooWeakException 如果密码不符合要求
* @see #updateUser(String, User)
* @see #deleteUser(String)
*/
public User createUser(String email, String password)
throws IllegalArgumentException, PasswordTooWeakException {
// 实现
}
/**
* 使用他们的凭证认证用户。
*
* @param userId 唯一用户标识符
* @param password 用户密码
* @return 如果认证成功返回{@code true},否则返回{@code false}
* @throws UserNotFoundException 如果用户不存在
* @deprecated 使用{@link #authenticateWithToken(String, String)}代替
*/
@Deprecated
public boolean authenticate(String userId, String password)
throws UserNotFoundException {
// 实现
}
}
内联注释最佳实践
// ❌ 不好:明显的注释
// Increment counter by 1
counter++;
// ✅ 好:解释为什么,而不是做什么
// Account for 1-based indexing in the API response
counter++;
// ❌ 不好:过时的注释
// TODO: Fix this bug (written 2 years ago)
function processData() {}
// ✅ 好:带有上下文的可操作注释
// TODO(john, 2025-01-15): Refactor to use async/await
// See GitHub issue #1234 for performance benchmarks
function processData() {}
// ❌ 不好:注释掉的代码
// const oldCalculation = (a, b) => a + b;
// const anotherOldThing = 42;
// ✅ 好:移除死代码,使用版本控制代替
// ❌ 不好:多余的注释
/**
* Gets the user name
*/
function getUserName() {
return this.name;
}
// ✅ 好:添加有价值的上下文
/**
* Returns display name formatted according to user's locale preferences.
* Falls back to username if display name is not set.
*/
function getUserName() {
return this.displayName || this.username;
}
最佳实践
✅ 做
- 全面记录公共API
- 包括使用示例
- 记录参数和返回值
- 指定抛出的异常/错误
- 使用特定语言的标准(JSDoc、docstrings等)
- 保持注释更新
- 注释“为什么”而不是“做什么”
- 包括边缘情况和陷阱
- 添加相关函数的链接
- 记录类型定义
- 使用一致的格式
❌ 不做
- 在注释中陈述显而易见的内容
- 留下注释掉的代码
- 编写误导性的注释
- 对于复杂函数省略示例
- 使用模糊的参数描述
- 忘记在代码更改时更新文档
- 过度注释简单代码