重要前提
安装AI Skills的关键前提是:必须科学上网,且开启TUN模式,这一点至关重要,直接决定安装能否顺利完成,在此郑重提醒三遍:科学上网,科学上网,科学上网。查看完整安装教程 →
refactoring by mgd34msu/goodvibes-plugin
npx skills add https://github.com/mgd34msu/goodvibes-plugin --skill refactoringscripts/
validate-refactoring.sh
references/
refactoring-patterns.md
此技能教你如何使用 GoodVibes 精准工具执行安全、系统化的代码重构。重构可在不改变外部行为的情况下改善代码结构和可维护性,使未来的开发更快并减少错误。
在以下情况加载此技能:
any 的使用)触发短语:"refactor this code", "reduce duplication", "extract function", "simplify conditionals", "improve types", "reorganize", "clean up code"。
在重构之前,映射当前代码结构并识别重构机会。
使用 discover 查找需要重构的常见代码异味。
discover:
queries:
# 大文件 (> 300 行)
- id: large_files
type: glob
patterns: ["src/**/*.{ts,tsx,js,jsx}"]
# 代码重复
- id: duplicate_patterns
type: grep
pattern: "(function|const|class)\\s+\\w+"
glob: "**/*.{ts,tsx,js,jsx}"
# 类型安全问题
- id: any_usage
type: grep
pattern: ":\\s*any(\\s|;|,|\\))"
glob: "**/*.{ts,tsx}"
# 复杂条件语句
- id: nested_conditions
type: grep
pattern: "if\\s*\\(.*if\\s*\\("
glob: "**/*.{ts,tsx,js,jsx}"
verbosity: files_only
广告位招租
在这里展示您的产品或服务
触达数万 AI 开发者,精准高效
这揭示了什么:
使用 precision_grep 映射代码在整个代码库中的使用情况。
precision_grep:
queries:
- id: function_usage
pattern: "importFunctionName\\("
glob: "**/*.{ts,tsx,js,jsx}"
output:
format: locations
verbosity: standard
为什么这很重要:
只有在测试验证行为得以保留时,重构才是安全的。
discover:
queries:
- id: test_files
type: glob
patterns: ["**/*.test.{ts,tsx}", "**/*.spec.{ts,tsx}"]
- id: source_files
type: glob
patterns: ["src/**/*.{ts,tsx}"]
verbosity: files_only
关键规则:
大型函数和组件难以测试和维护。提取可重用的部分。
寻找重复的逻辑或执行单一任务的代码块。
precision_read:
files:
- path: "src/components/UserProfile.tsx"
extract: symbols
verbosity: standard
提取候选对象:
重构前(重复的验证逻辑):
// In user-routes.ts
export async function POST(request: Request) {
const body = await request.json();
if (!body.email || !body.email.includes('@')) {
return Response.json({ error: 'Invalid email' }, { status: 400 });
}
// ... rest of logic
}
// In profile-routes.ts
export async function PUT(request: Request) {
const body = await request.json();
if (!body.email || !body.email.includes('@')) {
return Response.json({ error: 'Invalid email' }, { status: 400 });
}
// ... rest of logic
}
重构后(提取的验证逻辑):
// lib/validation.ts
import { z } from 'zod';
export const emailSchema = z.string().email();
export function validateEmail(email: unknown): { valid: true; email: string } | { valid: false; error: string } {
const result = emailSchema.safeParse(email);
if (!result.success) {
return { valid: false, error: 'Invalid email format' };
}
return { valid: true, email: result.data };
}
// user-routes.ts
import { validateEmail } from '@/lib/validation';
export async function POST(request: Request) {
const body = await request.json();
const emailResult = validateEmail(body.email);
if (!emailResult.valid) {
return Response.json({ error: emailResult.error }, { status: 400 });
}
// ... rest of logic using emailResult.email
}
使用 precision_edit 执行提取:
precision_edit:
operations:
- action: replace
path: "src/api/user-routes.ts"
old_text: |
const body = await request.json();
if (!body.email || !body.email.includes('@')) {
return Response.json({ error: 'Invalid email' }, { status: 400 });
}
new_text: |
const body = await request.json();
const emailResult = validateEmail(body.email);
if (!emailResult.valid) {
return Response.json({ error: emailResult.error }, { status: 400 });
}
verbosity: minimal
重构前(承担多个职责的大型组件):
function UserProfile({ userId }: { userId: string }) {
const [user, setUser] = useState<User | null>(null);
const [posts, setPosts] = useState<Post[]>([]);
const [followers, setFollowers] = useState<User[]>([]);
useEffect(() => {
fetch(`/api/users/${userId}`).then(r => r.json()).then(setUser);
fetch(`/api/users/${userId}/posts`).then(r => r.json()).then(setPosts);
fetch(`/api/users/${userId}/followers`).then(r => r.json()).then(setFollowers);
}, [userId]);
if (!user) return <div>Loading...</div>;
return (
<div>
<h1>{user.name}</h1>
<p>{user.bio}</p>
<div>
<h2>Posts</h2>
{posts.map(post => (
<div key={post.id}>
<h3>{post.title}</h3>
<p>{post.content}</p>
</div>
))}
</div>
<div>
<h2>Followers</h2>
{followers.map(follower => (
<div key={follower.id}>
<img src={follower.avatar} alt="" />
<span>{follower.name}</span>
</div>
))}
</div>
</div>
);
}
重构后(提取的组件和钩子):
// hooks/useUser.ts
export function useUser(userId: string) {
const [user, setUser] = useState<User | null>(null);
const [loading, setLoading] = useState(true);
useEffect(() => {
fetch(`/api/users/${userId}`)
.then(r => r.json())
.then(data => {
setUser(data);
setLoading(false);
});
}, [userId]);
return { user, loading };
}
// components/UserPosts.tsx
export function UserPosts({ userId }: { userId: string }) {
const [posts, setPosts] = useState<Post[]>([]);
useEffect(() => {
fetch(`/api/users/${userId}/posts`).then(r => r.json()).then(setPosts);
}, [userId]);
return (
<div>
<h2>Posts</h2>
{posts.map(post => (
<PostCard key={post.id} post={post} />
))}
</div>
);
}
// components/UserFollowers.tsx
export function UserFollowers({ userId }: { userId: string }) {
const [followers, setFollowers] = useState<User[]>([]);
useEffect(() => {
fetch(`/api/users/${userId}/followers`).then(r => r.json()).then(setFollowers);
}, [userId]);
return (
<div>
<h2>Followers</h2>
{followers.map(follower => (
<FollowerCard key={follower.id} user={follower} />
))}
</div>
);
}
// components/UserProfile.tsx
function UserProfile({ userId }: { userId: string }) {
const { user, loading } = useUser(userId);
if (loading || !user) return <div>Loading...</div>;
return (
<div>
<h1>{user.name}</h1>
<p>{user.bio}</p>
<UserPosts userId={userId} />
<UserFollowers userId={userId} />
</div>
);
}
好处:
糟糕的命名和文件组织会拖慢开发速度。
重命名变量、函数和文件,使其具有描述性。
糟糕的命名:
function getData(id: string) { ... } // 太泛泛
const x = getUserById(userId); // 不明确的缩写
let flag = true; // 这个标志代表什么?
良好的命名:
function getUserProfile(userId: string) { ... } // 具体,意图清晰
const userProfile = getUserById(userId); // 描述性的
let isEmailVerified = true; // 布尔命名约定
使用带 replace_all 的 precision_edit 进行重命名:
precision_edit:
operations:
- action: replace
path: "src/lib/user.ts"
old_text: "function getData"
new_text: "function getUserProfile"
replace_all: true
verbosity: minimal
使用基于功能或基于层的结构将相关文件分组。
重构前(扁平结构):
src/
user-routes.ts
user-service.ts
user-repository.ts
post-routes.ts
post-service.ts
post-repository.ts
重构后(基于功能的结构):
src/
features/
users/
api/
routes.ts
services/
user-service.ts
repositories/
user-repository.ts
types/
user.types.ts
index.ts # 桶导出
posts/
api/
routes.ts
services/
post-service.ts
repositories/
post-repository.ts
types/
post.types.ts
index.ts
好处:
使用 precision_write 创建桶导出:
precision_write:
files:
- path: "src/features/users/index.ts"
content: |
export * from './types/user.types';
export * from './services/user-service';
export * from './repositories/user-repository';
verbosity: minimal
嵌套的条件语句和复杂的布尔逻辑容易出错。
重构前(嵌套条件语句):
function processOrder(order: Order) {
if (order.status === 'pending') {
if (order.items.length > 0) {
if (order.paymentConfirmed) {
// Process order
return processPayment(order);
} else {
throw new Error('Payment not confirmed');
}
} else {
throw new Error('Order has no items');
}
} else {
throw new Error('Order is not pending');
}
}
重构后(卫语句):
function processOrder(order: Order) {
if (order.status !== 'pending') {
throw new Error('Order is not pending');
}
if (order.items.length === 0) {
throw new Error('Order has no items');
}
if (!order.paymentConfirmed) {
throw new Error('Payment not confirmed');
}
return processPayment(order);
}
好处:
重构前(复杂的布尔逻辑):
if (user.role === 'admin' || (user.role === 'moderator' && user.permissions.includes('delete')) || user.id === post.authorId) {
deletePost(post.id);
}
重构后(命名函数):
function canDeletePost(user: User, post: Post): boolean {
if (user.role === 'admin') return true;
if (user.role === 'moderator' && user.permissions.includes('delete')) return true;
if (user.id === post.authorId) return true;
return false;
}
if (canDeletePost(user, post)) {
deletePost(post.id);
}
好处:
重构前(冗长的 switch 语句):
function calculateShipping(order: Order): number {
switch (order.shippingMethod) {
case 'standard':
return order.weight * 0.5;
case 'express':
return order.weight * 1.5 + 10;
case 'overnight':
return order.weight * 3 + 25;
case 'international':
return order.weight * 5 + 50;
default:
throw new Error('Unknown shipping method');
}
}
重构后(策略模式):
interface ShippingStrategy {
calculate(weight: number): number;
}
class StandardShipping implements ShippingStrategy {
calculate(weight: number): number {
return weight * 0.5;
}
}
class ExpressShipping implements ShippingStrategy {
calculate(weight: number): number {
return weight * 1.5 + 10;
}
}
class OvernightShipping implements ShippingStrategy {
calculate(weight: number): number {
return weight * 3 + 25;
}
}
class InternationalShipping implements ShippingStrategy {
calculate(weight: number): number {
return weight * 5 + 50;
}
}
const shippingStrategies: Record<string, ShippingStrategy> = {
standard: new StandardShipping(),
express: new ExpressShipping(),
overnight: new OvernightShipping(),
international: new InternationalShipping(),
};
function calculateShipping(order: Order): number {
const strategy = shippingStrategies[order.shippingMethod];
if (!strategy) {
throw new Error('Unknown shipping method');
}
return strategy.calculate(order.weight);
}
好处:
强类型在编译时捕获错误。
any 类型查找所有 any 的使用:
precision_grep:
queries:
- id: any_usage
pattern: ":\\s*any(\\s|;|,|\\))"
glob: "**/*.{ts,tsx}"
output:
format: locations
verbosity: standard
重构前(不安全):
function processData(data: any) {
return data.value.toUpperCase(); // 如果 value 不是字符串,运行时错误
}
重构后(类型安全):
interface DataWithValue {
value: string;
}
function processData(data: DataWithValue): string {
return data.value.toUpperCase();
}
重构前(弱类型):
interface ApiResponse {
success: boolean;
data?: User;
error?: string;
}
function handleResponse(response: ApiResponse) {
if (response.success) {
console.log(response.data.name); // TypeScript 无法保证 data 存在
}
}
重构后(可辨识联合类型):
type ApiResponse =
| { success: true; data: User }
| { success: false; error: string };
function handleResponse(response: ApiResponse) {
if (response.success) {
console.log(response.data.name); // TypeScript 知道这里 data 存在
} else {
console.error(response.error); // TypeScript 知道这里 error 存在
}
}
好处:
重构前(过于泛化):
function getProperty<T>(obj: T, key: string) {
return obj[key]; // 类型错误:没有索引签名
}
重构后(适当的约束):
function getProperty<T extends Record<string, unknown>, K extends keyof T>(
obj: T,
key: K
): T[K] {
return obj[key];
}
const user = { name: 'Alice', age: 30 };
const name = getProperty(user, 'name'); // 类型是 string
const age = getProperty(user, 'age'); // 类型是 number
好处:
通过依赖抽象而不是具体实现来解耦代码。
重构前(紧密耦合):
import { PrismaClient } from '@prisma/client';
class UserService {
private prisma = new PrismaClient();
async getUser(id: string) {
return this.prisma.user.findUnique({ where: { id } });
}
}
重构后(依赖注入):
interface UserRepository {
findById(id: string): Promise<User | null>;
create(data: CreateUserInput): Promise<User>;
update(id: string, data: UpdateUserInput): Promise<User>;
}
class PrismaUserRepository implements UserRepository {
constructor(private prisma: PrismaClient) {}
async findById(id: string): Promise<User | null> {
return this.prisma.user.findUnique({ where: { id } });
}
async create(data: CreateUserInput): Promise<User> {
return this.prisma.user.create({ data });
}
async update(id: string, data: UpdateUserInput): Promise<User> {
return this.prisma.user.update({ where: { id }, data });
}
}
class UserService {
constructor(private userRepo: UserRepository) {}
async getUser(id: string) {
return this.userRepo.findById(id);
}
}
// 用法
const prisma = new PrismaClient();
const userRepo = new PrismaUserRepository(prisma);
const userService = new UserService(userRepo);
好处:
重构前(难以测试):
function sendEmail(to: string, subject: string, body: string) {
const client = new SendGridClient(process.env.SENDGRID_API_KEY!); // 不好:非空断言绕过了运行时验证
client.send({ to, subject, body });
}
重构后(工厂注入):
interface EmailClient {
send(email: { to: string; subject: string; body: string }): Promise<void>;
}
class SendGridEmailClient implements EmailClient {
constructor(private apiKey: string) {}
async send(email: { to: string; subject: string; body: string }) {
// SendGrid 实现
}
}
class MockEmailClient implements EmailClient {
async send(email: { to: string; subject: string; body: string }) {
console.log('Mock email sent:', email);
}
}
function createEmailClient(): EmailClient {
if (process.env.NODE_ENV === 'test') {
return new MockEmailClient();
}
const apiKey = process.env.SENDGRID_API_KEY;
if (!apiKey) {
throw new Error('SENDGRID_API_KEY environment variable is required');
}
return new SendGridEmailClient(apiKey);
}
function sendEmail(client: EmailClient, to: string, subject: string, body: string) {
return client.send({ to, subject, body });
}
好处:
数据库模式和查询需要仔细重构。
检查现有模式:
precision_read:
files:
- path: "prisma/schema.prisma"
extract: content
verbosity: standard
重构前(缺少索引):
model Post {
id String @id @default(cuid())
title String
published Boolean @default(false)
authorId String
createdAt DateTime @default(now())
}
重构后(带索引):
model Post {
id String @id @default(cuid())
title String
published Boolean @default(false)
authorId String
createdAt DateTime @default(now())
@@index([authorId])
@@index([published, createdAt])
}
何时添加索引:
重构前(非规范化):
model Order {
id String @id
customerName String
customerEmail String
customerPhone String
}
重构后(规范化):
model Customer {
id String @id
name String
email String @unique
phone String
orders Order[]
}
model Order {
id String @id
customerId String
customer Customer @relation(fields: [customerId], references: [id])
@@index([customerId])
}
好处:
重构前(N+1 查询):
const posts = await prisma.post.findMany();
for (const post of posts) {
const author = await prisma.user.findUnique({ where: { id: post.authorId } });
console.log(`${post.title} by ${author.name}`); // 注意:在生产环境中使用结构化日志记录器
}
重构后(预加载):
const posts = await prisma.post.findMany({
include: {
author: true,
},
});
for (const post of posts) {
console.log(`${post.title} by ${post.author.name}`); // 注意:在生产环境中使用结构化日志记录器
}
使用 discover 查找 N+1 模式:
discover:
queries:
- id: n_plus_one
type: grep
pattern: "(for|forEach|map).*await.*(prisma|db|query|find)"
glob: "**/*.{ts,tsx,js,jsx}"
verbosity: locations
只有在测试验证后,重构才是安全的。
建立基线:在开始之前测试必须通过。
precision_exec:
commands:
- cmd: "npm run test"
verbosity: standard
如果测试失败,先修复它们。
进行小改动,并在每一步之后进行验证。
工作流:
使用 precision_exec 进行验证:
precision_exec:
commands:
- cmd: "npm run typecheck"
- cmd: "npm run lint"
- cmd: "npm run test"
verbosity: standard
如果覆盖率下降,请添加测试。
precision_exec:
commands:
- cmd: "npm run test -- --coverage"
verbosity: standard
检查覆盖率:
重构后的代码需要更新文档。
重构前(过时的):
/**
* Gets user data from the database
*/
function getData(id: string) { ... } // 函数已重命名
重构后(当前的):
/**
* 通过 ID 检索用户个人资料,包括相关帖子和关注者
* @param userId - 用户的唯一标识符
* @returns 包含帖子和关注者的用户个人资料,如果未找到则返回 null
*/
function getUserProfile(userId: string): Promise<UserProfile | null> { ... }
如果文件结构发生变化,请更新文档。
示例更新:
运行验证脚本以确保重构质量。
./scripts/validate-refactoring.sh /path/to/project
该脚本验证:
any 类型)有关详细的重构前/后示例,请参阅 references/refactoring-patterns.md。
快速参考:
时机: 函数太长或做多件事
修复: 将逻辑块提取到单独的函数中
时机: 名称不清晰或具有误导性
修复: 重命名为具有描述性并遵循约定
时机: 基于类型的 switch 语句
修复: 使用策略模式或类层次结构
时机: 函数参数过多
修复: 将相关参数分组到一个对象中
时机: 没有上下文的硬编码数字
修复: 提取到命名常量
时机: 所有分支中都有相同的代码
修复: 将公共代码移到条件语句外部
在整个代码库中查找重构候选对象。
示例:查找重复
discover:
queries:
- id: validation_patterns
type: grep
pattern: "if.*!.*email.*includes"
glob: "**/*.{ts,tsx}"
- id: large_functions
type: symbols
query: "function"
verbosity: locations
执行安全、原子性的重构编辑。
示例:提取函数
precision_edit:
operations:
- action: replace
path: "src/api/user.ts"
old_text: |
if (!email || !email.includes('@')) {
return { error: 'Invalid email' };
}
new_text: |
const emailValidation = validateEmail(email);
if (!emailValidation.valid) {
return { error: emailValidation.error };
}
verbosity: minimal
验证重构不会破坏任何东西。
precision_exec:
commands:
- cmd: "npm run typecheck"
- cmd: "npm run lint -- --fix"
- cmd: "npm run test"
verbosity: standard
使用 scripts/validate-refactoring.sh 验证重构质量。
./scripts/validate-refactoring.sh /path/to/project
该脚本检查:
any 类型)重构前:
重构过程中:
重构后:
适合重构的时机:
不适合重构的时机:
使用 discover 查找模式,然后使用 precision_edit 修复它们。
# Step 1: Find all console.log statements
discover:
queries:
- id: console_logs
type: grep
pattern: "console\\.log\\("
glob: "src/**/*.{ts,tsx}"
verbosity: locations
# Step 2: Replace with proper logger
precision_edit:
operations:
- action: replace
path: "src/file1.ts"
old_text: "console.log("
new_text: "logger.info("
replace_all: true
verbosity: minimal
使用批量操作同时重构多个文件。
precision_edit:
operations:
- action: replace
path: "src/api/user.ts"
old_text: "getData"
new_text: "getUserProfile"
replace_all: true
- action: replace
path: "src/api/post.ts"
old_text: "getData"
new_text: "getPostDetails"
replace_all: true
verbosity: minimal
随时间跟踪改进情况。
重构前测量:
precision_exec:
commands:
- cmd: "find src -not -path '*/node_modules/*' -not -path '*/dist/*' -name '*.ts' -exec wc -l {} + | tail -1"
- cmd: "grep -r --include='*.ts' --exclude-dir=node_modules --exclude-dir=dist --exclude-dir=.git --exclude-dir=.next -- 'any' src | wc -l"
verbosity: standard
重构后测量并进行比较:
any 使用次数(应该减少)references/refactoring-patterns.md - 带有示例的常见重构模式scripts/validate-refactoring.sh - 自动化重构验证每周安装次数
53
仓库
GitHub 星标数
6
首次出现
2026年2月17日
安全审计
安装于
opencode53
gemini-cli53
github-copilot53
amp53
codex53
kimi-cli53
scripts/
validate-refactoring.sh
references/
refactoring-patterns.md
This skill teaches you how to perform safe, systematic code refactoring using GoodVibes precision tools. Refactoring improves code structure and maintainability without changing external behavior, making future development faster and reducing bugs.
Load this skill when:
any usage)Trigger phrases: "refactor this code", "reduce duplication", "extract function", "simplify conditionals", "improve types", "reorganize", "clean up code".
Before refactoring, map the current code structure and identify refactoring opportunities.
Use discover to find common code smells that need refactoring.
discover:
queries:
# Large files (> 300 lines)
- id: large_files
type: glob
patterns: ["src/**/*.{ts,tsx,js,jsx}"]
# Code duplication
- id: duplicate_patterns
type: grep
pattern: "(function|const|class)\\s+\\w+"
glob: "**/*.{ts,tsx,js,jsx}"
# Type safety issues
- id: any_usage
type: grep
pattern: ":\\s*any(\\s|;|,|\\))"
glob: "**/*.{ts,tsx}"
# Complex conditionals
- id: nested_conditions
type: grep
pattern: "if\\s*\\(.*if\\s*\\("
glob: "**/*.{ts,tsx,js,jsx}"
verbosity: files_only
What this reveals:
Use precision_grep to map how code is used across the codebase.
precision_grep:
queries:
- id: function_usage
pattern: "importFunctionName\\("
glob: "**/*.{ts,tsx,js,jsx}"
output:
format: locations
verbosity: standard
Why this matters:
Refactoring is only safe when tests validate behavior preservation.
discover:
queries:
- id: test_files
type: glob
patterns: ["**/*.test.{ts,tsx}", "**/*.spec.{ts,tsx}"]
- id: source_files
type: glob
patterns: ["src/**/*.{ts,tsx}"]
verbosity: files_only
Critical rule:
Large functions and components are hard to test and maintain. Extract reusable pieces.
Look for repeated logic or code blocks that do one thing.
precision_read:
files:
- path: "src/components/UserProfile.tsx"
extract: symbols
verbosity: standard
Extraction candidates:
Before (duplicated validation logic):
// In user-routes.ts
export async function POST(request: Request) {
const body = await request.json();
if (!body.email || !body.email.includes('@')) {
return Response.json({ error: 'Invalid email' }, { status: 400 });
}
// ... rest of logic
}
// In profile-routes.ts
export async function PUT(request: Request) {
const body = await request.json();
if (!body.email || !body.email.includes('@')) {
return Response.json({ error: 'Invalid email' }, { status: 400 });
}
// ... rest of logic
}
After (extracted validation):
// lib/validation.ts
import { z } from 'zod';
export const emailSchema = z.string().email();
export function validateEmail(email: unknown): { valid: true; email: string } | { valid: false; error: string } {
const result = emailSchema.safeParse(email);
if (!result.success) {
return { valid: false, error: 'Invalid email format' };
}
return { valid: true, email: result.data };
}
// user-routes.ts
import { validateEmail } from '@/lib/validation';
export async function POST(request: Request) {
const body = await request.json();
const emailResult = validateEmail(body.email);
if (!emailResult.valid) {
return Response.json({ error: emailResult.error }, { status: 400 });
}
// ... rest of logic using emailResult.email
}
Useprecision_edit to perform the extraction:
precision_edit:
operations:
- action: replace
path: "src/api/user-routes.ts"
old_text: |
const body = await request.json();
if (!body.email || !body.email.includes('@')) {
return Response.json({ error: 'Invalid email' }, { status: 400 });
}
new_text: |
const body = await request.json();
const emailResult = validateEmail(body.email);
if (!emailResult.valid) {
return Response.json({ error: emailResult.error }, { status: 400 });
}
verbosity: minimal
Before (large component with multiple responsibilities):
function UserProfile({ userId }: { userId: string }) {
const [user, setUser] = useState<User | null>(null);
const [posts, setPosts] = useState<Post[]>([]);
const [followers, setFollowers] = useState<User[]>([]);
useEffect(() => {
fetch(`/api/users/${userId}`).then(r => r.json()).then(setUser);
fetch(`/api/users/${userId}/posts`).then(r => r.json()).then(setPosts);
fetch(`/api/users/${userId}/followers`).then(r => r.json()).then(setFollowers);
}, [userId]);
if (!user) return <div>Loading...</div>;
return (
<div>
<h1>{user.name}</h1>
<p>{user.bio}</p>
<div>
<h2>Posts</h2>
{posts.map(post => (
<div key={post.id}>
<h3>{post.title}</h3>
<p>{post.content}</p>
</div>
))}
</div>
<div>
<h2>Followers</h2>
{followers.map(follower => (
<div key={follower.id}>
<img src={follower.avatar} alt="" />
<span>{follower.name}</span>
</div>
))}
</div>
</div>
);
}
After (extracted components and hooks):
// hooks/useUser.ts
export function useUser(userId: string) {
const [user, setUser] = useState<User | null>(null);
const [loading, setLoading] = useState(true);
useEffect(() => {
fetch(`/api/users/${userId}`)
.then(r => r.json())
.then(data => {
setUser(data);
setLoading(false);
});
}, [userId]);
return { user, loading };
}
// components/UserPosts.tsx
export function UserPosts({ userId }: { userId: string }) {
const [posts, setPosts] = useState<Post[]>([]);
useEffect(() => {
fetch(`/api/users/${userId}/posts`).then(r => r.json()).then(setPosts);
}, [userId]);
return (
<div>
<h2>Posts</h2>
{posts.map(post => (
<PostCard key={post.id} post={post} />
))}
</div>
);
}
// components/UserFollowers.tsx
export function UserFollowers({ userId }: { userId: string }) {
const [followers, setFollowers] = useState<User[]>([]);
useEffect(() => {
fetch(`/api/users/${userId}/followers`).then(r => r.json()).then(setFollowers);
}, [userId]);
return (
<div>
<h2>Followers</h2>
{followers.map(follower => (
<FollowerCard key={follower.id} user={follower} />
))}
</div>
);
}
// components/UserProfile.tsx
function UserProfile({ userId }: { userId: string }) {
const { user, loading } = useUser(userId);
if (loading || !user) return <div>Loading...</div>;
return (
<div>
<h1>{user.name}</h1>
<p>{user.bio}</p>
<UserPosts userId={userId} />
<UserFollowers userId={userId} />
</div>
);
}
Benefits:
Poor naming and file organization slow development.
Rename variables, functions, and files to be descriptive.
Bad naming:
function getData(id: string) { ... } // Too generic
const x = getUserById(userId); // Unclear abbreviation
let flag = true; // What does this flag represent?
Good naming:
function getUserProfile(userId: string) { ... } // Specific, clear intent
const userProfile = getUserById(userId); // Descriptive
let isEmailVerified = true; // Boolean naming convention
Useprecision_edit with replace_all for renaming:
precision_edit:
operations:
- action: replace
path: "src/lib/user.ts"
old_text: "function getData"
new_text: "function getUserProfile"
replace_all: true
verbosity: minimal
Group related files together using feature-based or layer-based structure.
Before (flat structure):
src/
user-routes.ts
user-service.ts
user-repository.ts
post-routes.ts
post-service.ts
post-repository.ts
After (feature-based structure):
src/
features/
users/
api/
routes.ts
services/
user-service.ts
repositories/
user-repository.ts
types/
user.types.ts
index.ts # Barrel export
posts/
api/
routes.ts
services/
post-service.ts
repositories/
post-repository.ts
types/
post.types.ts
index.ts
Benefits:
Useprecision_write to create barrel exports:
precision_write:
files:
- path: "src/features/users/index.ts"
content: |
export * from './types/user.types';
export * from './services/user-service';
export * from './repositories/user-repository';
verbosity: minimal
Nested conditionals and complex boolean logic are error-prone.
Before (nested conditionals):
function processOrder(order: Order) {
if (order.status === 'pending') {
if (order.items.length > 0) {
if (order.paymentConfirmed) {
// Process order
return processPayment(order);
} else {
throw new Error('Payment not confirmed');
}
} else {
throw new Error('Order has no items');
}
} else {
throw new Error('Order is not pending');
}
}
After (guard clauses):
function processOrder(order: Order) {
if (order.status !== 'pending') {
throw new Error('Order is not pending');
}
if (order.items.length === 0) {
throw new Error('Order has no items');
}
if (!order.paymentConfirmed) {
throw new Error('Payment not confirmed');
}
return processPayment(order);
}
Benefits:
Before (complex boolean logic):
if (user.role === 'admin' || (user.role === 'moderator' && user.permissions.includes('delete')) || user.id === post.authorId) {
deletePost(post.id);
}
After (named function):
function canDeletePost(user: User, post: Post): boolean {
if (user.role === 'admin') return true;
if (user.role === 'moderator' && user.permissions.includes('delete')) return true;
if (user.id === post.authorId) return true;
return false;
}
if (canDeletePost(user, post)) {
deletePost(post.id);
}
Benefits:
Before (long switch statement):
function calculateShipping(order: Order): number {
switch (order.shippingMethod) {
case 'standard':
return order.weight * 0.5;
case 'express':
return order.weight * 1.5 + 10;
case 'overnight':
return order.weight * 3 + 25;
case 'international':
return order.weight * 5 + 50;
default:
throw new Error('Unknown shipping method');
}
}
After (strategy pattern):
interface ShippingStrategy {
calculate(weight: number): number;
}
class StandardShipping implements ShippingStrategy {
calculate(weight: number): number {
return weight * 0.5;
}
}
class ExpressShipping implements ShippingStrategy {
calculate(weight: number): number {
return weight * 1.5 + 10;
}
}
class OvernightShipping implements ShippingStrategy {
calculate(weight: number): number {
return weight * 3 + 25;
}
}
class InternationalShipping implements ShippingStrategy {
calculate(weight: number): number {
return weight * 5 + 50;
}
}
const shippingStrategies: Record<string, ShippingStrategy> = {
standard: new StandardShipping(),
express: new ExpressShipping(),
overnight: new OvernightShipping(),
international: new InternationalShipping(),
};
function calculateShipping(order: Order): number {
const strategy = shippingStrategies[order.shippingMethod];
if (!strategy) {
throw new Error('Unknown shipping method');
}
return strategy.calculate(order.weight);
}
Benefits:
Strong typing catches bugs at compile time.
any TypesFind allany usage:
precision_grep:
queries:
- id: any_usage
pattern: ":\\s*any(\\s|;|,|\\))"
glob: "**/*.{ts,tsx}"
output:
format: locations
verbosity: standard
Before (unsafe):
function processData(data: any) {
return data.value.toUpperCase(); // Runtime error if value is not a string
}
After (type-safe):
interface DataWithValue {
value: string;
}
function processData(data: DataWithValue): string {
return data.value.toUpperCase();
}
Before (weak typing):
interface ApiResponse {
success: boolean;
data?: User;
error?: string;
}
function handleResponse(response: ApiResponse) {
if (response.success) {
console.log(response.data.name); // TypeScript can't guarantee data exists
}
}
After (discriminated union):
type ApiResponse =
| { success: true; data: User }
| { success: false; error: string };
function handleResponse(response: ApiResponse) {
if (response.success) {
console.log(response.data.name); // TypeScript knows data exists here
} else {
console.error(response.error); // TypeScript knows error exists here
}
}
Benefits:
Before (too generic):
function getProperty<T>(obj: T, key: string) {
return obj[key]; // Type error: no index signature
}
After (proper constraints):
function getProperty<T extends Record<string, unknown>, K extends keyof T>(
obj: T,
key: K
): T[K] {
return obj[key];
}
const user = { name: 'Alice', age: 30 };
const name = getProperty(user, 'name'); // Type is string
const age = getProperty(user, 'age'); // Type is number
Benefits:
Decouple code by depending on abstractions, not implementations.
Before (tight coupling):
import { PrismaClient } from '@prisma/client';
class UserService {
private prisma = new PrismaClient();
async getUser(id: string) {
return this.prisma.user.findUnique({ where: { id } });
}
}
After (dependency injection):
interface UserRepository {
findById(id: string): Promise<User | null>;
create(data: CreateUserInput): Promise<User>;
update(id: string, data: UpdateUserInput): Promise<User>;
}
class PrismaUserRepository implements UserRepository {
constructor(private prisma: PrismaClient) {}
async findById(id: string): Promise<User | null> {
return this.prisma.user.findUnique({ where: { id } });
}
async create(data: CreateUserInput): Promise<User> {
return this.prisma.user.create({ data });
}
async update(id: string, data: UpdateUserInput): Promise<User> {
return this.prisma.user.update({ where: { id }, data });
}
}
class UserService {
constructor(private userRepo: UserRepository) {}
async getUser(id: string) {
return this.userRepo.findById(id);
}
}
// Usage
const prisma = new PrismaClient();
const userRepo = new PrismaUserRepository(prisma);
const userService = new UserService(userRepo);
Benefits:
Before (hard to test):
function sendEmail(to: string, subject: string, body: string) {
const client = new SendGridClient(process.env.SENDGRID_API_KEY!); // BAD: Non-null assertion bypasses runtime validation
client.send({ to, subject, body });
}
After (factory injection):
interface EmailClient {
send(email: { to: string; subject: string; body: string }): Promise<void>;
}
class SendGridEmailClient implements EmailClient {
constructor(private apiKey: string) {}
async send(email: { to: string; subject: string; body: string }) {
// SendGrid implementation
}
}
class MockEmailClient implements EmailClient {
async send(email: { to: string; subject: string; body: string }) {
console.log('Mock email sent:', email);
}
}
function createEmailClient(): EmailClient {
if (process.env.NODE_ENV === 'test') {
return new MockEmailClient();
}
const apiKey = process.env.SENDGRID_API_KEY;
if (!apiKey) {
throw new Error('SENDGRID_API_KEY environment variable is required');
}
return new SendGridEmailClient(apiKey);
}
function sendEmail(client: EmailClient, to: string, subject: string, body: string) {
return client.send({ to, subject, body });
}
Benefits:
Database schemas and queries need careful refactoring.
Check existing schema:
precision_read:
files:
- path: "prisma/schema.prisma"
extract: content
verbosity: standard
Before (missing indexes):
model Post {
id String @id @default(cuid())
title String
published Boolean @default(false)
authorId String
createdAt DateTime @default(now())
}
After (with indexes):
model Post {
id String @id @default(cuid())
title String
published Boolean @default(false)
authorId String
createdAt DateTime @default(now())
@@index([authorId])
@@index([published, createdAt])
}
When to add indexes:
Before (denormalized):
model Order {
id String @id
customerName String
customerEmail String
customerPhone String
}
After (normalized):
model Customer {
id String @id
name String
email String @unique
phone String
orders Order[]
}
model Order {
id String @id
customerId String
customer Customer @relation(fields: [customerId], references: [id])
@@index([customerId])
}
Benefits:
Before (N+1 query):
const posts = await prisma.post.findMany();
for (const post of posts) {
const author = await prisma.user.findUnique({ where: { id: post.authorId } });
console.log(`${post.title} by ${author.name}`); // Note: Use structured logger in production
}
After (eager loading):
const posts = await prisma.post.findMany({
include: {
author: true,
},
});
for (const post of posts) {
console.log(`${post.title} by ${post.author.name}`); // Note: Use structured logger in production
}
Usediscover to find N+1 patterns:
discover:
queries:
- id: n_plus_one
type: grep
pattern: "(for|forEach|map).*await.*(prisma|db|query|find)"
glob: "**/*.{ts,tsx,js,jsx}"
verbosity: locations
Refactoring is only safe when validated by tests.
Establish baseline: tests must pass before you start.
precision_exec:
commands:
- cmd: "npm run test"
verbosity: standard
If tests fail, fix them first.
Make small changes and validate after each step.
Workflow:
Useprecision_exec to validate:
precision_exec:
commands:
- cmd: "npm run typecheck"
- cmd: "npm run lint"
- cmd: "npm run test"
verbosity: standard
If coverage drops, add tests.
precision_exec:
commands:
- cmd: "npm run test -- --coverage"
verbosity: standard
Check coverage:
Refactored code needs updated documentation.
Before (outdated):
/**
* Gets user data from the database
*/
function getData(id: string) { ... } // Function was renamed
After (current):
/**
* Retrieves a user profile by ID including related posts and followers
* @param userId - The unique identifier for the user
* @returns User profile with posts and followers, or null if not found
*/
function getUserProfile(userId: string): Promise<UserProfile | null> { ... }
If file structure changed, update documentation.
Example updates:
Run the validation script to ensure refactoring quality.
./scripts/validate-refactoring.sh /path/to/project
The script validates:
any types)See references/refactoring-patterns.md for detailed before/after examples.
Quick reference:
When: Function is too long or does multiple things
Fix: Extract logical blocks into separate functions
When: Name is unclear or misleading
Fix: Rename to be descriptive and follow conventions
When: Switch statement based on type
Fix: Use strategy pattern or class hierarchy
When: Function has too many parameters
Fix: Group related parameters into an object
When: Hardcoded numbers without context
Fix: Extract to named constants
When: Same code in all branches
Fix: Move common code outside conditional
Find refactoring candidates across the codebase.
Example: Find duplication
discover:
queries:
- id: validation_patterns
type: grep
pattern: "if.*!.*email.*includes"
glob: "**/*.{ts,tsx}"
- id: large_functions
type: symbols
query: "function"
verbosity: locations
Perform safe, atomic refactoring edits.
Example: Extract function
precision_edit:
operations:
- action: replace
path: "src/api/user.ts"
old_text: |
if (!email || !email.includes('@')) {
return { error: 'Invalid email' };
}
new_text: |
const emailValidation = validateEmail(email);
if (!emailValidation.valid) {
return { error: emailValidation.error };
}
verbosity: minimal
Validate refactoring doesn't break anything.
precision_exec:
commands:
- cmd: "npm run typecheck"
- cmd: "npm run lint -- --fix"
- cmd: "npm run test"
verbosity: standard
Use scripts/validate-refactoring.sh to validate refactoring quality.
./scripts/validate-refactoring.sh /path/to/project
The script checks:
any types)Before refactoring:
During refactoring:
After refactoring:
Good times to refactor:
Bad times to refactor:
Use discover to find patterns, then precision_edit to fix them.
# Step 1: Find all console.log statements
discover:
queries:
- id: console_logs
type: grep
pattern: "console\\.log\\("
glob: "src/**/*.{ts,tsx}"
verbosity: locations
# Step 2: Replace with proper logger
precision_edit:
operations:
- action: replace
path: "src/file1.ts"
old_text: "console.log("
new_text: "logger.info("
replace_all: true
verbosity: minimal
Refactor multiple files simultaneously using batch operations.
precision_edit:
operations:
- action: replace
path: "src/api/user.ts"
old_text: "getData"
new_text: "getUserProfile"
replace_all: true
- action: replace
path: "src/api/post.ts"
old_text: "getData"
new_text: "getPostDetails"
replace_all: true
verbosity: minimal
Track improvement over time.
Measure before refactoring:
precision_exec:
commands:
- cmd: "find src -not -path '*/node_modules/*' -not -path '*/dist/*' -name '*.ts' -exec wc -l {} + | tail -1"
- cmd: "grep -r --include='*.ts' --exclude-dir=node_modules --exclude-dir=dist --exclude-dir=.git --exclude-dir=.next -- 'any' src | wc -l"
verbosity: standard
Measure after refactoring and compare:
any usage count (should decrease)references/refactoring-patterns.md - Common refactoring patterns with examplesscripts/validate-refactoring.sh - Automated refactoring validationWeekly Installs
53
Repository
GitHub Stars
6
First Seen
Feb 17, 2026
Security Audits
Gen Agent Trust HubFailSocketPassSnykPass
Installed on
opencode53
gemini-cli53
github-copilot53
amp53
codex53
kimi-cli53
React 组合模式指南:Vercel 组件架构最佳实践,提升代码可维护性
125,600 周安装