你正在 进阶版 · ⚡ 代码俱乐部 · ← 回到学院 · 进阶版主页 · 总入口

← 十二个项目

项目 06 · 一个能活过半年的工具

大压轴。给一个具体的人做一个工具,但工程标准是"半年后他还在用、不会突然炸"。这才是产品工程师的入门考试。

怎么算"成"?

从你 ship 那天起算,180 天后,那个用户还在用,且工具没出过让他放弃的 bug。

必须有的工程实践

必须避免的事

这个项目要让你学到什么

"做能跑的东西"是中阶版的本事。"做能活的东西"是进阶版的本事。后者难十倍,但是 AI 时代真的在乎工程美感的人,是少数。这一项做完,你已经领先大多数会写代码的人。

← 上一个下一所:智能体实验室 →

工程测验 什么是「CI/CD 管道」,为什么对工程项目这么重要?
你写好了代码,现在要部署。下面哪个说法最准确?
解释:CI/CD 的核心价值是「把人的疏漏变成机器的规则」。每次提交代码时,机器都要跑测试、检查类型、运行 linter、构建、最后才部署。如果某一步失败,整个流程停止。这样就不会有「忘记跑测试就提交」的情况。
分步引导 为一个 Vite + TypeScript 项目设置 CI/CD 的 5 步
  1. 选择 CI/CD 平台。免费选项:GitHub Actions、GitLab CI、Vercel。付费:Jenkins、CircleCI。
    看参考

    例:如果代码在 GitHub,用 GitHub Actions 最方便 —— 直接在仓库里创建 `.github/workflows/` 目录放 YAML 配置。

  2. 写测试用例。至少为每个主要函数写 1–2 个测试。用 Jest / Vitest 跑测试。
    看参考

    例:`npm install --save-dev vitest`,然后为 `fetchWithRetry.ts` 写 `fetchWithRetry.test.ts`。

  3. 创建 CI 配置文件(如 `.github/workflows/ci.yml`)。每次 push 时,自动跑:`npm ci` → `npm run test` → `npm run build` → `npm run lint`。
    看参考

    例:```yaml\non: [push]\njobs:\n test:\n runs-on: ubuntu-latest\n steps:\n - uses: actions/checkout@v3\n - run: npm ci\n - run: npm test\n - run: npm run build```

  4. 设置「分支保护」。要求 CI 通过才能合并 PR。这样就不会有未测试的代码进入 main。
    看参考

    例:GitHub 仓库设置 → Branches → Add rule → Require status checks to pass。

  5. 监控部署。每次成功构建后,自动推送到服务器(如 Vercel、Netlify、Heroku)。出错时发通知。
    看参考

    例:Vercel 自动和 GitHub 连接,push 到 main 就自动部署。

动手 写一个简单的测试用例(用 Vitest)
任务:为一个工具函数写一个完整的测试。包括:(1) 正常情况;(2) 边界情况;(3) 错误情况。用 `expect()` 和 `describe()` / `it()` 的格式。
参考实现

工程级参考答案(带完整注释):

import { describe, it, expect, beforeEach, afterEach } from 'vitest';

// 被测试的函数(更复杂的版本)
class DiscountCalculator {
  private history: Array<{ price: number; discount: number; result: number }> = [];
  
  calculate(price: number, discountPercent: number): number {
    if (!this.validate(price, discountPercent)) {
      throw new Error('Invalid input');
    }
    
    const result = price * (1 - discountPercent / 100);
    this.history.push({ price, discount: discountPercent, result });
    return result;
  }
  
  private validate(price: number, discountPercent: number): boolean {
    return price >= 0 && discountPercent >= 0 && discountPercent <= 100;
  }
  
  getHistory() {
    return [...this.history];
  }
  
  clearHistory() {
    this.history = [];
  }
}

describe('DiscountCalculator', () => {
  let calculator: DiscountCalculator;
  
  beforeEach(() => {
    calculator = new DiscountCalculator();
  });
  
  afterEach(() => {
    calculator.clearHistory();
  });
  
  describe('calculate', () => {
    it('正常情况:10元商品打 20% 折 = 8元', () => {
      expect(calculator.calculate(10, 20)).toBe(8);
    });
    
    it('多次调用应该记录历史', () => {
      calculator.calculate(10, 10);
      calculator.calculate(20, 50);
      expect(calculator.getHistory()).toHaveLength(2);
    });
    
    it('错误:负价格', () => {
      expect(() => calculator.calculate(-10, 20)).toThrow('Invalid input');
    });
  });
});
动手 为你的项目写一个完整的 CI/CD pipeline 配置
任务:写一个 GitHub Actions 的 workflow 文件(YAML)。应该包括:(1) 什么时候触发(push/PR);(2) 哪个 Node 版本;(3) 跑什么测试;(4) 成功后怎么部署。

在下面框里写你自己的 prompt(可以用中文):

→ 打开通义千问粘贴试 已复制 ✓
看参考 prompt

参考 prompt(这是一个模板,你可以改细节):

你是一个领域专家。请基于以下规则回答问题:

1. 只基于你的专业知识和常见做法回答,不编造。
2. 如果问题超出你的领域,明确说「这不在我的专业范围内」。
3. 给出的建议应该包括「为什么」和「什么时候不应该这样做」。
4. 对于有争议的做法,列出不同观点。

现在,开始回答用户的问题。