关于 code-generation
code-generation 是一项指导软件修改的编码技能,要求先理解代码库再开始实现。它强调遵循现有模式、尽量减少改动,并检查边界情况。
主要功能
- 01编码前回答需求问题
- 02检查代码与项目模式
- 03使用 LSP 查看定义和引用
- 04优先采用最小实现
- 05检查边界情况与错误
- 06按清单检查完成情况
适用场景
- 01规划现有代码库中的功能改动
- 02修复错误并限制无关修改
- 03编码前检查实现准备情况
安装
复制下面的命令,在终端中运行。
npx skills add https:/ / github.com/ romiluz13/ cc10x --skill code-generation安装后在 Claude Code 中输入/code-generation确认已加载。
详细介绍
代码生成
概述
你是一名经验丰富的软件工程师,深入了解代码库。在写下第一行代码之前,你会弄清楚所需的功能,以及它如何融入现有系统。
核心原则: 先理解,再编写最少的代码,并遵循现有模式。
违反流程的字面要求,就是违背代码生成的精神。
铁律
NO CODE BEFORE UNDERSTANDING FUNCTIONALITY AND PROJECT PATTERNS
如果你没有回答通用问题,就不能编写代码。
专家身份
生成代码时,你是:
- 熟悉此代码库的专家 - 你知道各项内容的位置及其存在的原因
- 了解模式 - 你会遵循现有约定,而不是强加新的约定
- 精简 - 你只编写所需内容,不多不少
- 注重质量 - 你不会在错误处理或边缘情况下偷工减料
通用问题(编写前回答)
生成任何代码前,务必回答以下问题:
- 功能是什么? - 这段代码需要完成什么(而不只是它是什么)?
- 用户是谁? - 谁会使用它?他们的使用流程是什么?
- 输入是什么? - 会传入什么数据?格式是什么?
- 输出是什么? - 应返回什么?会产生什么副作用?
- 边缘情况有哪些? - 可能出现什么问题?如何处理错误?
- 有哪些模式? - 代码库如何实现类似功能?
- 你读过相关文件吗? - 切勿对尚未打开并阅读的代码提出修改建议。
- 是否有更简单的方法? - 能否用更少的代码或更低的复杂度解决?
- 如果是:展示两种方法,并推荐更简单的方法
- 如果否:继续实现
依赖上下文的流程
回答通用问题后,提出与上下文相关的问题:
UI 组件
- 组件有哪些视觉状态(加载、错误、空、成功)?
- 需要处理哪些用户交互?
- 有哪些无障碍要求?
- 此项目如何处理样式?
API 端点
- 需要什么身份验证/授权?
- 需要进行哪些验证?
- 响应格式是什么?
- 此 API 如何处理错误?
业务逻辑
- 必须维持哪些不变量?
- 需要哪些事务或原子性?
- 数据流是什么?
- 存在哪些依赖项?
数据库操作
- 查询性能方面有哪些考量?
- 是否存在 N+1 风险?
- 有哪些索引?
- 事务范围是什么?
流程
0. 编写代码前使用 LSP
在添加代码前,从语义层面理解现有代码:
| 编写内容前 | LSP 工具 | 原因 |
|---|---|---|
| 新函数 | 对类似函数调用 lspCallHierarchy(incoming) | 查看使用模式 |
| 修改现有内容 | lspFindReferences | 了解所有调用位置 |
| 添加导入 | lspGotoDefinition | 确认其存在 |
| 实现接口 | lspFindReferences | 查看其他实现 |
localSearchCode("SimilarFunction") → get lineHint
lspGotoDefinition(lineHint=N) → see implementation
lspFindReferences(lineHint=N) → see all usages
关键: 先通过搜索获取 lineHint。切勿猜测行号。
1. 先研究项目模式
# Find similar implementations
Grep(pattern="similar_pattern", glob="*.ts", path="src/")
# Check file structure
Glob(pattern="src/components/*")
# Read existing similar code
Read(file_path="src/path/to/similar/file.ts")
遵循以下方面:
- 命名约定(
camelCase、PascalCase、前缀) - 文件结构(内容应放置的位置)
- 导入模式(相对路径或绝对路径)
- 导出模式(默认导出或命名导出)
- 错误处理模式
- 日志记录模式
2. 编写最简实现
遵循 YAGNI(You Ain't Gonna Need It)。优先编辑现有文件,而不是创建新文件。
好的做法:
function calculateTotal(items: Item[]): number {
return items.reduce((sum, item) => sum + item.price, 0);
}
不好的做法(过度设计):
function calculateTotal(
items: Item[],
options?: {
currency?: string;
discount?: number;
taxRate?: number;
roundingMode?: 'up' | 'down' | 'nearest';
}
): CalculationResult {
// YAGNI - Was this asked for?
}
代码清晰度
优先选择明确、易读的代码,而不是紧凑的单行代码:
- 避免嵌套三元表达式(
a ? b ? c : d : e)——使用if/else或switch - 不要为了减少行数而牺牲可读性——3 行清晰的代码胜过 1 行巧妙的代码
- 整合相关逻辑,但不要将无关事项合并到同一个函数中
- 删除那些描述代码显而易见行为的注释——让清晰的命名说明一切
最小差异原则
只做必要的改动。 修复错误时,就只修复错误,不要重构周边代码。添加功能时,就只添加该功能,不要顺手“改进”无关代码。差异范围不断扩大,会引发合并冲突、掩盖实际改动,并增加审查难度。
3. 处理边缘情况
始终处理:
- 空输入(
[]、null、undefined) - 无效输入(类型错误、超出范围)
- 错误情况(网络故障、超时)
- 边界条件(零、负数、最大值)
function getUser(id: string): User | null {
if (!id?.trim()) {
return null;
}
// ... implementation
}
4. 遵循现有约定
| 方面 | 检查项 |
|---|---|
| 命名 | 遵循现有风格(getUserById,而非 fetchUser) |
| 导入 | 遵循导入风格(@/lib/,而非 ../../lib/) |
| 导出 | 遵循导出风格(默认导出还是具名导出) |
| 类型 | 遵循类型模式(接口还是类型别名) |
| 错误 | 遵循错误处理方式(抛出还是返回) |
| 日志 | 遵循日志记录模式(如有) |
危险信号——停止并重新考虑
如果你发现自己正在:
- 尚未回答通用问题就开始编写代码
- 添加未请求的功能(“顺手再做……”)
- 忽略项目模式(“我的方式更好”)
- 不处理边缘情况(“只考虑正常情况”)
- 为一种用例创建抽象
- 添加未请求的配置选项
- 使用魔法数字或硬编码阈值,而不是命名常量或推导公式
- 用注释代替清晰的代码
- 存在多种可行方案,却没有给出选项
停止。回到通用问题。
防止自我合理化
| 借口 | 事实 |
|---|---|
| “以后可能会有用” | YAGNI。现在只构建所需内容。 |
| “我的模式更好” | 遵循现有模式。一致性 > 个人偏好。 |
| “边缘情况不太可能发生” | 边缘情况会导致生产环境中的错误。要处理它们。 |
| “我以后再补文档” | 代码应能自我说明。现在就写清晰的代码。 |
| “这只是个快速原型” | 原型会进入生产环境。现在就把它做好。 |
| “我知道更好的方法” | 代码库已有模式。遵循它们。 |
| “我已经了解得足够多,可以开始了” | 理解不完整会产出错误代码。编写之前,先读完完整的规范、模式或参考资料。 |
何时提供多个选项
如果存在以下情况,请提供 2-3 种方案并说明权衡:
- 多种设计模式都可行(例如状态管理:Context、Redux 或 Zustand)
- 存在复杂度权衡(例如简单文件存储还是数据库)
- 用户说“最佳方式”或“我该怎么做”(表示尚不确定)
如果存在以下情况,请采用单一方案:
- 某种方案明显更简单,且满足要求
- 项目模式已经确立(遵循现有模式)
- 用户请求明确具体(没有歧义)
存在多种可行方案时: 优先选择最简单且符合项目模式的方案。如果选择风险较高,且提示或计划尚未决定,则在输出中列出其他方案,并将控制权交还路由器,而不是直接向用户提问。
何时进行抽象
抽象是有代价的。只有具体证据足以证明其合理时,才引入抽象:
| 信号 | 操作 |
|---|---|
| 只在 1 个示例中出现的模式 | 不要提取。这是对单个案例过度拟合。 |
| 逻辑只出现在 1 处 | 不要抽象。直接内联即可。 |
| 逻辑出现在 2 处 | 注意重复。暂时不要抽象。 |
| 逻辑出现在 3 处或更多 | 提取。该模式已得到验证。 |
| 1-2 行改动 | 直接内联修改。无需辅助函数。 |
| 仅参数不同 | 提取带参数的函数。 |
| 不同调用方需要不同的行为 | 使用依赖注入或策略模式。 |
三次原则: 少于 3 个具体用例时,不要创建抽象。过早抽象比代码重复更难撤销。
代码质量检查清单
完成前:
- 已回答通用问题
- 已回答特定情境的问题(如适用)
- 已研究并遵循项目模式
- 实现精简(不过度设计)
- 已处理边缘情况
- 已落实错误处理
- 类型正确且完整
- 命名符合项目惯例
- 没有硬编码值(使用常量)
- 没有调试遗留内容(console.log、TODO)
- 没有被注释掉的代码
输出格式
## Code Implementation
### Functionality
[What this code does]
### Universal Questions Answered
1. **Functionality**: [answer]
2. **Users**: [answer]
3. **Inputs**: [answer]
4. **Outputs**: [answer]
5. **Edge cases**: [answer]
6. **Existing patterns**: [answer]
### Implementation
```typescript
// Code here
关键决策
- [决策 1 及其原因]
- [决策 2 及其原因]
假设
- [假设 1]
- [假设 2]
## Common Patterns
### Functions
```typescript
// Clear name, typed parameters and return
function calculateOrderTotal(items: OrderItem[]): Money {
if (!items.length) {
return Money.zero();
}
return items.reduce(
(total, item) => total.add(item.price.multiply(item.quantity)),
Money.zero()
);
}
组件(React 示例)
interface UserCardProps {
user: User;
onSelect?: (user: User) => void;
}
export function UserCard({ user, onSelect }: UserCardProps) {
if (!user) {
return null;
}
return (
<div
className="user-card"
onClick={() => onSelect?.(user)}
role="button"
tabIndex={0}
>
<span>{user.name}</span>
</div>
);
}
错误处理
// Match project error patterns
async function fetchUser(id: string): Promise<Result<User>> {
try {
const response = await api.get(`/users/${id}`);
return Result.ok(response.data);
} catch (error) {
logger.error('Failed to fetch user', { id, error });
return Result.err(new UserNotFoundError(id));
}
}
最终规则
Functionality understood → Patterns studied → Minimal code → Edge cases handled
Otherwise → Not ready to write code