mcpField
A
ai-coding-discipline

ai-coding-discipline

github.com/luoling8192开发17249 次安装31 周前更新
代码仓库

关于 ai-coding-discipline

为 AI Agent 制定的一组编码规则,强调明确处理缺失数据、编写有效测试和遵循规范的修复流程。还涵盖错误处理、避免针对测试硬编码逻辑,以及在确认修复前保留调试日志。

主要功能

  1. 01避免静默使用回退值
  2. 02限制宽泛的错误捕获
  3. 03断言具体测试结果
  4. 04避免针对测试硬编码逻辑
  5. 05修复缺陷时采用红绿测试
  6. 06确认修复前保留调试日志

适用场景

  1. 01审查 AI 生成的代码更改
  2. 02改进业务行为测试
  3. 03采用测试先行的缺陷修复流程
  4. 04检查错误处理与回退逻辑

安装

复制下面的命令,在终端中运行。

$npx skills add https://github.com/luoling8192/ai-coding-principles --skill ai-coding-discipline

安装后在 Claude Code 中输入/ai-coding-discipline确认已加载。

详细介绍

AI 编码规范

这些规则优先于 AI 默认的编码倾向。编写或修改的所有代码都必须遵守。


规则 1:禁止静默回退

绝不要使用回退值来掩盖本不应缺失的数据。

// FORBIDDEN — hides upstream bugs
const price = product?.price ?? 0;
const userName = user?.name || "Unknown";

// CORRECT — fail fast when data contract is violated
if (product.price == null) {
  throw new Error(`Product ${product.id} is missing price`);
}
const price = product.price;

以下情况可以接受回退:

  • 按明确设计意图面向用户显示的内容(例如头像占位符)
  • 有文档说明默认值的可选配置
  • 在外部输入解析中,缺失属于有效状态的情况

编写 ??、|| 或 ?. 之前的检查清单:

  1. 此处的值是否确实可能为 null/undefined?
  2. 如果它为 null,回退值能否确保后续结果正确?
  3. 抛出错误是否能帮助我更快地发现 bug?

如果第 3 个问题的答案是肯定的,就抛出错误,不要回退。


规则 2:业务逻辑中禁止使用兜底式 try/catch

业务逻辑函数绝不能用 try/catch 包住所有代码。应让错误自然传播。

// FORBIDDEN — swallows all errors into a useless null
async function createOrder(data: OrderInput) {
  try {
    const user = await getUser(data.userId);
    const coupon = await validateCoupon(data.couponCode);
    const order = await saveOrder({ ...data, discount: coupon.value });
    return order;
  } catch (error) {
    console.log('Error creating order:', error);
    return null; // caller gets null, has no idea what failed
  }
}

// CORRECT — let errors bubble up, catch at the boundary
async function createOrder(data: OrderInput) {
  const user = await getUser(data.userId);
  const coupon = await validateCoupon(data.couponCode);
  const order = await saveOrder({ ...data, discount: coupon.value });
  return order;
}

// Catch ONLY at the API/controller boundary
app.post('/orders', async (req, res) => {
  try {
    const order = await createOrder(req.body);
    res.json(order);
  } catch (error) {
    logger.error('Order creation failed', { error, body: req.body });
    res.status(500).json({ error: 'Order creation failed' });
  }
});

以下情况适合使用 try/catch:

  • API 路由处理程序/控制器边界
  • 顶层事件处理程序(消息队列、定时任务)
  • 预期会出现部分失败,且已定义恢复方式的操作(例如逐项处理错误的批处理)
  • 你打算以不同方式处理的特定命名错误类型

绝不要只为返回 null、undefined、false 或空对象而捕获 Error。


规则 3:代码出错时测试必须失败

每项测试都必须验证具体的业务结果。如果删除核心逻辑后测试仍能通过,这项测试就毫无价值。

// FORBIDDEN — passes even if processOrder returns garbage
test('should process order', async () => {
  const result = await processOrder(mockOrder);
  expect(result).toBeDefined();
});

// CORRECT — verifies exact business behavior
test('should calculate total with 10% discount', async () => {
  const result = await processOrder({
    ...mockOrder,
    discount: 0.1,
  });
  expect(result.totalAmount).toBe(900);       // 1000 * 0.9
  expect(result.discountAmount).toBe(100);
  expect(result.status).toBe('confirmed');
});

测试质量检查清单:

  1. 如果删除函数体,这项测试会失败吗?如果不会,这项测试就毫无用处。
  2. 我测试的是行为,还是仅仅测试“某个东西存在”?
  3. 断言检查的是具体值,而不仅仅是真值吗?

禁止使用的弱断言(除非实际要求是测试是否存在):

  • 仅使用 toBeDefined()、toBeTruthy()、toBeFalsy() 作为断言
  • toHaveLength(expect.any(Number))
  • 只使用 expect(result).not.toBeNull(),而不进一步检查具体值

规则 4:禁止硬编码查找表实现

绝不要通过硬编码与测试用例匹配的返回值来实现业务逻辑。

// FORBIDDEN — fake implementation that "fits" the tests
function calculateDiscount(amount: number, level: string): number {
  if (amount === 1000 && level === 'gold') return 100;
  if (amount === 500 && level === 'silver') return 25;
  return 0;
}

// CORRECT — real logic
function calculateDiscount(amount: number, level: string): number {
  const rates: Record<string, number> = { gold: 0.1, silver: 0.05, bronze: 0.02 };
  const rate = rates[level] ?? 0;
  return amount * rate;
}

如何避免这种情况:

  • 使用多样化的测试数据:多个金额、边界情况和临界值
  • 在适当情况下添加基于属性的测试/模糊测试
  • 使用原始规范中未列出的值进行测试,以发现伪造的查找表实现

规则 5:红绿测试(TDD 顺序)

修复 bug 时,始终先编写会失败的测试,再修复代码。

Correct order:
1. Discover bug
2. Write a test that reproduces the bug
3. Run the test — confirm it FAILS (red)
4. Fix the code
5. Run the test — confirm it PASSES (green)

**这样做的重要性:**如果先修复代码再编写测试,你就无法确定测试是否能发现这个 bug。测试可能会因为错误的原因而通过。

**绝不要跳过第 3 步。**看到测试从红变绿,才能证明测试有效。


规则 6:修复期间绝不移除调试日志

调试时,只有在人类确认修复有效后,才能移除调试日志。

FORBIDDEN workflow:
1. Human asks to add debug logs
2. AI adds logs
3. Human runs code, shares log output
4. AI "finds the problem", applies fix AND removes debug logs in the same edit
5. Fix doesn't work — logs are gone, must re-add them

CORRECT workflow:
1. Human asks to add debug logs
2. AI adds logs
3. Human runs code, shares log output
4. AI applies fix ONLY — debug logs stay untouched
5. Human verifies the fix
6. Human decides when to remove debug logs (or asks AI to remove them)

规则:绝不要在修复所在的同一次提交中修改调试/诊断日志。这是两个独立事项。


快速参考:提交代码前的自检

最终确定任何代码变更之前,请检查以下清单:

检查项问题
回退值我是否使用了 ?? 或 || 来掩盖本不应缺失的值?
错误处理我是否在业务逻辑中添加了本应直接传播错误的 try/catch?
测试力度如果删除实现,我的测试是否仍能通过?
测试真实性我是否硬编码值来匹配测试用例,而没有实现真正的逻辑?
TDD 顺序对于 bug 修复:我是否在应用修复之前看到测试失败?
调试日志我是否在修复的同一次变更中移除了诊断日志?

如果任何一项的答案是“是”,请先修改再继续。

评论

支持 Markdown