关于 aif-best-practices
aif-best-practices 是适用于不同语言和框架的代码质量指南,面向编写、测试和审查代码的开发者。它涵盖命名、结构、错误处理、测试及代码审查,并可结合项目架构和专属规则。
主要功能
- 01提供命名约定
- 02说明函数与模块组织
- 03指导错误处理
- 04覆盖测试实践与代码审查
适用场景
- 01为新代码选择一致的命名和结构
- 02检查错误处理与测试覆盖重点
- 03在代码审查中使用质量检查清单
安装
复制下面的命令,在终端中运行。
$
npx skills add https:/ / github.com/ lee-to/ ai-factory --skill aif-best-practices安装后在 Claude Code 中输入/aif-best-practices确认已加载。
详细介绍
最佳实践指南
适用于任何语言或框架的通用代码质量指南。
上下文: 如果存在 .ai-factory/ARCHITECTURE.md,请在遵循这些指南的同时,遵守其中的文件夹结构、依赖规则和模块边界。
阅读 .ai-factory/skill-context/aif-best-practices/SKILL.md——如果该文件存在,则必须阅读。
此文件包含 /aif-evolve 根据补丁、代码库约定和技术栈分析积累的项目专属规则。这些规则针对当前项目进行了定制。
如何应用 skill-context 规则:
- 将这些规则视为此技能通用说明的项目级覆盖规则
- 当 skill-context 规则与此 SKILL.md 中的一般规则冲突时,以 skill-context 规则为准(更具体的上下文优先级更高——这与嵌套 CLAUDE.md 文件遵循相同原则)
- 如果没有冲突,则同时应用两者:SKILL.md 中的一般规则和 skill-context 中的项目规则
- 即使 skill-context 规则看似与此技能的默认规则矛盾,也不要忽略它们——这些规则源于项目经验,证明默认规则并不足够
- 重要: skill-context 规则适用于此技能的所有输出,包括你提供的建议、示例和检查清单。如果 skill-context 规则指出“最佳实践必须优先考虑 X”或“示例必须遵循约定 Y”,你就必须遵守。提供与 skill-context 规则矛盾的指导属于错误。
执行要求: 生成任何输出内容后,都要根据所有 skill-context 规则进行核查。如果违反任何规则,必须在呈现给用户之前修正。
快速参考
/aif-best-practices— 完整概览/aif-best-practices naming— 命名约定/aif-best-practices structure— 代码组织/aif-best-practices errors— 错误处理/aif-best-practices testing— 测试实践/aif-best-practices review— 代码审查清单
命名约定
变量和函数
✅ Good ❌ Bad
─────────────────────────────────────────────
getUserById(id) getUser(i)
isValidEmail checkEmail
maxRetryCount max
calculateTotalPrice calc
handleSubmit submit
规则:
- 使用能清楚表达意图的描述性名称
- 避免使用缩写(普遍认可的缩写除外:
id、url、api) - 布尔变量:使用
is、has、can、should前缀 - 函数:动词 + 名词(
fetchUser、validateInput) - 常量:SCREAMING_SNAKE_CASE
- 类/类型:PascalCase
- 变量/函数:camelCase(JS/TS/PHP)或 snake_case(Python/Rust)
文件和目录
✅ Good ❌ Bad
─────────────────────────────────────────────
user-service.ts userService.ts (inconsistent)
UserRepository.ts user_repository.ts (mixed)
/components/Button/ /Components/button/
/services/auth/ /Services/Auth/
规则:
- 每个项目统一采用一种约定(文件名使用 kebab-case 或 PascalCase)
- 目录:使用小写字母和连字符
- 测试文件:
*.test.ts或*.spec.ts(保持一致) - 索引文件:仅用于重新导出,不包含逻辑
代码结构
函数设计
// ✅ Good: Single responsibility, clear inputs/outputs
function calculateDiscount(price: number, discountPercent: number): number {
if (discountPercent < 0 || discountPercent > 100) {
throw new Error('Discount must be between 0 and 100');
}
return price * (1 - discountPercent / 100);
}
// ❌ Bad: Multiple responsibilities, side effects
function processOrder(order) {
validateOrder(order); // validation
order.discount = getDiscount(); // mutation
saveToDatabase(order); // persistence
sendEmail(order.user); // notification
return order;
}
// ✅ Good: PHP with type declarations
function calculateDiscount(float $price, float $discountPercent): float
{
if ($discountPercent < 0 || $discountPercent > 100) {
throw new InvalidArgumentException('Discount must be between 0 and 100');
}
return $price * (1 - $discountPercent / 100);
}
规则:
- 单一职责:一个函数只做一件事
- 每个函数最多 20–30 行
- 最多 3–4 个参数(更多时使用对象)
- 纯函数不产生副作用
- 对守卫条件尽早返回
模块组织
feature/
├── index.ts # Public exports only
├── types.ts # Types and interfaces
├── constants.ts # Constants
├── utils.ts # Pure utility functions
├── hooks.ts # React hooks (if applicable)
├── service.ts # Business logic
└── repository.ts # Data access
规则:
- 按功能分组,而不是按类型分组
- 通过 index.ts 提供清晰的公共 API
- 内部模块使用
_前缀或放在internal/中 - 避免循环依赖
错误处理
应做与不应做
// ✅ Good: Specific errors, meaningful messages
class UserNotFoundError extends Error {
constructor(userId: string) {
super(`User not found: ${userId}`);
this.name = 'UserNotFoundError';
}
}
async function getUser(id: string): Promise<User> {
const user = await db.users.find(id);
if (!user) {
throw new UserNotFoundError(id);
}
return user;
}
// ❌ Bad: Generic errors, swallowed exceptions
async function getUser(id) {
try {
return await db.users.find(id);
} catch (e) {
console.log(e); // Swallowed!
return null; // Hides the problem
}
}
规则:
- 为领域错误创建专用错误类
- 绝不在不记录日志的情况下吞掉异常
- 记录错误时包含上下文(用户 ID、请求 ID 等)
- 在系统边界使用错误边界
- 对预期的失败使用 Result 类型(可选)
错误消息
✅ Good: "Failed to create user: email '[email protected]' already exists"
❌ Bad: "Error occurred"
❌ Bad: "Something went wrong"
测试实践
测试结构(AAA 模式)
describe('calculateDiscount', () => {
it('should apply percentage discount to price', () => {
// Arrange
const price = 100;
const discount = 20;
// Act
const result = calculateDiscount(price, discount);
// Assert
expect(result).toBe(80);
});
it('should throw for invalid discount percentage', () => {
expect(() => calculateDiscount(100, -10)).toThrow();
expect(() => calculateDiscount(100, 150)).toThrow();
});
});
规则:
- 每个测试只验证一个断言概念
- 使用描述性测试名称:“当 [条件] 时应 [预期行为]”
- 测试行为,而不是实现
- 使用工厂/固定数据作为测试数据
- 避免直接测试私有方法
测试覆盖优先级
1. Critical business logic ████████████ Must have
2. Edge cases and boundaries ████████░░░░ Important
3. Integration points ██████░░░░░░ Important
4. Happy paths ████░░░░░░░░ Basic
5. UI components ██░░░░░░░░░░ Optional
代码审查清单
请求审查前
- 自行审查差异
- 本地测试通过
- 没有调试代码(console.log、debugger)
- 没有注释掉的代码
- 必要时更新了文档
- 提交消息清晰
审查者检查清单
- 正确性:它是否实现了所声称的功能?
- 边缘情况:可能会出现什么问题?
- 安全性:是否存在漏洞?(参见
/aif-security-checklist) - 性能:是否存在明显的瓶颈?
- 可读性:我能否在 5 分钟内理解?
- 测试:是否覆盖了关键路径?
- 一致性:是否遵循项目约定?
审查意见
✅ Good feedback:
"This could throw if `user` is null. Consider adding a null check
or using optional chaining: `user?.profile?.name`"
❌ Bad feedback:
"This is wrong"
"I don't like this"
"Why did you do it this way?"
快速规则摘要
| 方面 | 规则 |
|---|---|
| 命名 | 描述清晰、保持一致、体现意图 |
| 函数 | 小巧、单一用途、无副作用 |
| 错误 | 使用具体类型、绝不吞掉错误、记录上下文 |
| 测试 | 采用 AAA 模式、测试行为、使用描述性名称 |
| 审查 | 具体明确、提出解决方案、友善待人 |
产物归属与配置策略
- 主要归属:无。此技能仅供建议和参考。
- 写入策略:默认不创建或修改项目产物。
- 配置策略:本设计与配置无关。遵循仓库上下文、
.ai-factory/ARCHITECTURE.md和技能上下文覆盖项,而不是读取config.yaml。
评论
支持 Markdown