code-quality
36
总安装量
36
周安装量
#5692
全站排名
安装命令
npx skills add https://github.com/miles990/claude-software-skills --skill code-quality
Agent 安装分布
opencode
29
gemini-cli
27
codex
26
antigravity
24
github-copilot
22
Skill 文档
Code Quality
Overview
Principles and practices for writing maintainable, readable, and reliable code.
Clean Code Principles
Meaningful Names
// â Cryptic names
const d = new Date();
const u = getU();
const arr = data.filter(x => x.s === 'a');
// â
Descriptive names
const currentDate = new Date();
const currentUser = getCurrentUser();
const activeUsers = users.filter(user => user.status === 'active');
// â Hungarian notation (outdated)
const strName = 'John';
const arrItems = [];
const bIsActive = true;
// â
Let the type system handle types
const name = 'John';
const items: Item[] = [];
const isActive = true;
Functions
// â Does too much
function processUserData(userId: string) {
const user = db.findUser(userId);
const orders = db.findOrders(userId);
const total = orders.reduce((sum, o) => sum + o.amount, 0);
sendEmail(user.email, `Your total: ${total}`);
updateAnalytics(userId, total);
return { user, orders, total };
}
// â
Single responsibility
function getUser(userId: string): User {
return db.findUser(userId);
}
function getUserOrders(userId: string): Order[] {
return db.findOrders(userId);
}
function calculateTotal(orders: Order[]): number {
return orders.reduce((sum, o) => sum + o.amount, 0);
}
function sendOrderSummary(user: User, total: number): void {
sendEmail(user.email, `Your total: ${total}`);
}
// â Too many parameters
function createUser(name, email, age, role, department, manager, startDate) {}
// â
Use object parameter
interface CreateUserParams {
name: string;
email: string;
age?: number;
role: Role;
department: string;
managerId?: string;
startDate: Date;
}
function createUser(params: CreateUserParams): User {}
Comments
// â Redundant comment
// Increment counter by 1
counter++;
// â Outdated comment (code changed, comment didn't)
// Returns the user's full name
function getUserEmail(user: User) {
return user.email;
}
// â
Explains WHY, not WHAT
// Use binary search because the list is sorted and can have 100k+ items
const index = binarySearch(sortedItems, target);
// â
Warns about non-obvious behavior
// IMPORTANT: This function mutates the input array for performance reasons
function quickSort(arr: number[]): number[] {
// ...
}
// â
TODO with context
// TODO(john): Remove after migration completes - tracking in JIRA-1234
const legacyAdapter = new LegacyAdapter();
SOLID Principles
Single Responsibility Principle
// â Multiple responsibilities
class UserManager {
createUser(data: UserData) { /* DB logic */ }
validateEmail(email: string) { /* Validation logic */ }
sendWelcomeEmail(user: User) { /* Email logic */ }
generateReport(users: User[]) { /* Report logic */ }
}
// â
Single responsibility each
class UserRepository {
create(data: UserData): User { /* DB logic */ }
findById(id: string): User | null { /* DB logic */ }
}
class UserValidator {
validateEmail(email: string): boolean { /* Validation */ }
validatePassword(password: string): ValidationResult { /* Validation */ }
}
class EmailService {
sendWelcomeEmail(user: User): void { /* Email logic */ }
}
class UserReportGenerator {
generate(users: User[]): Report { /* Report logic */ }
}
Open/Closed Principle
// â Must modify to add new payment methods
class PaymentProcessor {
process(payment: Payment) {
if (payment.type === 'credit') {
// Credit card logic
} else if (payment.type === 'paypal') {
// PayPal logic
} else if (payment.type === 'crypto') {
// Crypto logic - had to modify existing code!
}
}
}
// â
Open for extension, closed for modification
interface PaymentMethod {
process(amount: number): Promise<PaymentResult>;
}
class CreditCardPayment implements PaymentMethod {
async process(amount: number): Promise<PaymentResult> { /* ... */ }
}
class PayPalPayment implements PaymentMethod {
async process(amount: number): Promise<PaymentResult> { /* ... */ }
}
// New payment method - no modification to existing code
class CryptoPayment implements PaymentMethod {
async process(amount: number): Promise<PaymentResult> { /* ... */ }
}
class PaymentProcessor {
constructor(private method: PaymentMethod) {}
async process(amount: number): Promise<PaymentResult> {
return this.method.process(amount);
}
}
Liskov Substitution Principle
// â Violates LSP - Square breaks Rectangle contract
class Rectangle {
constructor(public width: number, public height: number) {}
setWidth(w: number) { this.width = w; }
setHeight(h: number) { this.height = h; }
getArea() { return this.width * this.height; }
}
class Square extends Rectangle {
setWidth(w: number) {
this.width = w;
this.height = w; // Unexpected side effect!
}
setHeight(h: number) {
this.width = h;
this.height = h; // Unexpected side effect!
}
}
// â
Proper abstraction
interface Shape {
getArea(): number;
}
class Rectangle implements Shape {
constructor(private width: number, private height: number) {}
getArea() { return this.width * this.height; }
}
class Square implements Shape {
constructor(private side: number) {}
getArea() { return this.side * this.side; }
}
Interface Segregation Principle
// â Fat interface
interface Worker {
work(): void;
eat(): void;
sleep(): void;
attendMeeting(): void;
writeReport(): void;
}
// Robot can't eat or sleep!
class Robot implements Worker {
work() { /* ... */ }
eat() { throw new Error('Robots do not eat'); } // Forced to implement
sleep() { throw new Error('Robots do not sleep'); }
// ...
}
// â
Segregated interfaces
interface Workable {
work(): void;
}
interface Eatable {
eat(): void;
}
interface Sleepable {
sleep(): void;
}
class Human implements Workable, Eatable, Sleepable {
work() { /* ... */ }
eat() { /* ... */ }
sleep() { /* ... */ }
}
class Robot implements Workable {
work() { /* ... */ }
}
Dependency Inversion Principle
// â High-level depends on low-level
class OrderService {
private db = new MySQLDatabase(); // Concrete dependency
private mailer = new SendGridMailer(); // Concrete dependency
createOrder(data: OrderData) {
const order = this.db.insert('orders', data);
this.mailer.send(data.email, 'Order confirmed');
return order;
}
}
// â
Depend on abstractions
interface Database {
insert(table: string, data: unknown): unknown;
find(table: string, query: unknown): unknown[];
}
interface Mailer {
send(to: string, message: string): void;
}
class OrderService {
constructor(
private db: Database,
private mailer: Mailer
) {}
createOrder(data: OrderData) {
const order = this.db.insert('orders', data);
this.mailer.send(data.email, 'Order confirmed');
return order;
}
}
// Now we can inject any implementation
const service = new OrderService(
new PostgresDatabase(),
new SESMailer()
);
Code Review Best Practices
What to Look For
## Code Review Checklist
### Correctness
- [ ] Logic is correct and handles edge cases
- [ ] Error handling is appropriate
- [ ] No obvious bugs or regressions
### Design
- [ ] Code is at the right abstraction level
- [ ] No unnecessary complexity
- [ ] Follows existing patterns in codebase
### Readability
- [ ] Clear naming and intent
- [ ] Comments explain "why" not "what"
- [ ] Code is self-documenting where possible
### Testing
- [ ] Adequate test coverage
- [ ] Tests are meaningful (not just coverage padding)
- [ ] Edge cases are tested
### Performance
- [ ] No obvious N+1 queries or inefficiencies
- [ ] Appropriate data structures used
- [ ] Caching considered if needed
### Security
- [ ] Input validation present
- [ ] No secrets in code
- [ ] Authentication/authorization correct
Giving Feedback
# Good Review Comments
## â
Specific and actionable
"This loop has O(n²) complexity. Consider using a Map for O(n) lookup."
## â
Explain the why
"Let's extract this to a separate function - it makes the logic easier
to test and the main function more readable."
## â
Offer alternatives
"Instead of mutating the array, consider using `filter()` which returns
a new array: `const active = items.filter(i => i.active)`"
## â
Distinguish severity
- "nit: " - Minor style issue, optional
- "suggestion: " - Good to have, not blocking
- "blocking: " - Must fix before merge
# Avoid
## â Vague criticism
"This code is confusing"
## â Personal attacks
"You always make this mistake"
## â No explanation
"Use a different approach"
Code Metrics
Cyclomatic Complexity
// High complexity (10+) - hard to test and maintain
function processOrder(order: Order): Result {
if (order.status === 'pending') { // +1
if (order.paymentMethod === 'card') { // +1
if (order.amount > 1000) { // +1
// ...
} else if (order.amount > 100) { // +1
// ...
} else {
// ...
}
} else if (order.paymentMethod === 'cash') { // +1
// ...
}
} else if (order.status === 'processing') { // +1
// ...
}
// ... more branches
}
// Lower complexity - extract conditions
function processOrder(order: Order): Result {
const processor = getProcessor(order.paymentMethod);
const tier = getPricingTier(order.amount);
return processor.process(order, tier);
}
Metrics to Track
| Metric | Target | Why |
|---|---|---|
| Cyclomatic Complexity | < 10 per function | Testability |
| Function Length | < 50 lines | Readability |
| File Length | < 400 lines | Maintainability |
| Test Coverage | > 80% | Confidence |
| Duplication | < 3% | DRY principle |
Linting & Formatting
ESLint Configuration
// .eslintrc.js
module.exports = {
extends: [
'eslint:recommended',
'plugin:@typescript-eslint/recommended',
],
rules: {
// Prevent bugs
'no-unused-vars': 'error',
'@typescript-eslint/no-floating-promises': 'error',
'@typescript-eslint/no-misused-promises': 'error',
// Code quality
'complexity': ['warn', 10],
'max-lines-per-function': ['warn', 50],
'max-depth': ['warn', 3],
// Consistency
'prefer-const': 'error',
'no-var': 'error',
}
};
Pre-commit Hooks
// package.json
{
"husky": {
"hooks": {
"pre-commit": "lint-staged"
}
},
"lint-staged": {
"*.{ts,tsx}": [
"eslint --fix",
"prettier --write"
],
"*.{json,md}": [
"prettier --write"
]
}
}
Related Skills
- [[refactoring]] – Improving existing code
- [[testing-strategies]] – Ensuring quality through tests
- [[design-patterns]] – Proven solutions
Sharp Edgesï¼å¸¸è¦é·é±ï¼
éäºæ¯ç¨å¼ç¢¼åè³ªä¸æå¸¸è¦ä¸ä»£å¹æé«çé¯èª¤
SE-1: éåº¦å·¥ç¨ (Over-engineering)
- å´é度: high
- æ å¢: çºäºãæªä¾å¯è½éè¦ãèå¢å ä¸å¿ è¦çæ½è±¡åè¤é度
- åå : YAGNI åå被忽è¦ãè¨è¨æ¨¡å¼æ¿«ç¨ããè¬ä¸ä»¥å¾è¦…ãçå¿æ
- çç:
- ç°¡å®åè½éè¦æ¹å 10+ åæªæ¡
- æ°äººçä¸ææ¶æ§
- ç¨å¼ç¢¼æ¯éæ±è¤é 10 å
- 檢測:
Factory.*Factory|Abstract.*Abstract|interface.*\{.*\}(?=.*interface.*\{.*\})|Strategy.*Strategy - è§£æ³: YAGNIï¼You Aren’t Gonna Need Itï¼ãå 寫æç°¡å®ç實ä½ãéè¦æåéæ§
SE-2: å½åä¸ä¸è´
- å´é度: medium
- æ å¢: åä¸åæ¦å¿µå¨ä¸åå°æ¹ç¨ä¸ååç¨±ï¼æä¸åæ¦å¿µç¨ç¸ä¼¼å稱
- åå : æ²æçµ±ä¸è¡èªãå¤äººéç¼æ²æå°é½ãè¤è£½è²¼ä¸æ²æ¹å
- çç:
user,customer,client,accountæåä¸ä»¶äº- æå°ä¸å°ç¸éç¨å¼ç¢¼
- æ°äººç¶å¸¸åãéååé£åæä»éº¼å·®å¥ï¼ã
- 檢測:
(user|customer|client|account).*=.*find|(get|fetch|retrieve|load).*User - è§£æ³: 建ç«è¡èªè¡¨ï¼Ubiquitous Languageï¼ãCode Review ææª¢æ¥å½åãéæ§çµ±ä¸å½å
SE-3: 深層巢ç (Deep Nesting)
- å´é度: medium
- æ å¢: if-else æ callback å·¢çè¶ é 3-4 層ï¼é£ä»¥é±è®
- åå : æ²æææ© returnãæ²ææ½å彿¸ãcallback hell
- çç:
- éè¦æ©«åæ²åæè½çå°ç¨å¼ç¢¼
- å¾é£è¿½è¹¤åªå
}å°æåªå{ - Cyclomatic complexity è¶ é«
- 檢測:
\{.*\{.*\{.*\{|if.*if.*if.*if|\.then\(.*\.then\(.*\.then\( - è§£æ³: Guard clauseï¼ææ© returnï¼ãæ½å彿¸ãä½¿ç¨ async/await å代 callback
SE-4: ç¥å¥æ¸å/å串 (Magic Numbers)
- å´é度: medium
- æ å¢: ç¨å¼ç¢¼ä¸ç´æ¥ä½¿ç¨æç¾©ä¸æçæ¸åæå串
- åå : æ¶å¾å®ç¾©å¸¸æ¸ããåªç¨ä¸æ¬¡ä¸ç¨æ½åºä¾ã
- çç:
- çå°
86400ä¸ç¥éæ¯ä»éº¼ï¼ä¸å¤©çç§æ¸ï¼ - ä¿®æ¹æéè¦å ¨åæå° replace
- åä¸åæ¸åå¨ä¸åå°æ¹æç¾©ä¸åä½å¼ç¸å
- çå°
- 檢測:
\b(86400|3600|1000|60000|1024|65535)\b|status\s*===?\s*['"][^'"]+['"] - è§£æ³: æ½åçºææç¾©å稱ç常æ¸ãä½¿ç¨ enumãéä¸ç®¡çè¨å®å¼
SE-5: 大泥ç (Big Ball of Mud)
- å´é度: critical
- æ å¢: ç¨å¼ç¢¼æ²ææç¢ºæ¶æ§ï¼æææ±è¥¿æ··å¨ä¸èµ·ï¼å°è齿ä¾è³´
- åå : æ²ææ¨¡çµåè¨è¨ãè¶æéãå work å說ãã缺ä¹éæ§
- çç:
- æ¹ A æå£ B
- å®ä¸æªæ¡ 1000+ è¡
- æææ±è¥¿é½ import æææ±è¥¿
- 檢測:
import.*from.*\.\.\/\.\.\/\.\.\/|require\(.*\.\..*\.\..*\.\.\)|lines.*>\s*1000 - è§£æ³: åå±¤æ¶æ§ãæç¢ºç模çµéçã宿鿧ãå´æ ¼ç import è¦å
Validations
V-1: ç¦æ¢ console.log (çç¢ä»£ç¢¼)
- é¡å: regex
- å´é度: medium
- 模å¼:
console\.(log|debug|info)\( - è¨æ¯: console.log should not be in production code
- 修復建è°: Use a proper logger (winston, pino) or remove debug statements
- é©ç¨:
*.ts,*.js
V-2: ç¦æ¢ any é¡å
- é¡å: ast
- å´é度: high
- 模å¼:
TSAnyKeyword - è¨æ¯: ‘any’ type defeats TypeScript’s type safety
- 修復建è°: Use specific type, ‘unknown’, or generic type parameter
- é©ç¨:
*.ts,*.tsx
V-3: 彿¸åæ¸éå¤
- é¡å: regex
- å´é度: medium
- 模å¼:
function\s+\w+\s*\([^)]*,\s*[^)]*,\s*[^)]*,\s*[^)]*,\s*[^)]*\)|=>\s*\([^)]*,\s*[^)]*,\s*[^)]*,\s*[^)]*,\s*[^)]*\) - è¨æ¯: Function has more than 4 parameters – consider using an object
- 修復建è°: Replace multiple params with single options object:
function(options: Options) - é©ç¨:
*.ts,*.js
V-4: TODO ç¡è¿½è¹¤
- é¡å: regex
- å´é度: low
- 模å¼:
//\s*TODO(?!.*#\d|.*JIRA|.*\w+-\d+) - è¨æ¯: TODO comment without tracking reference
- 修復建è°: Add issue reference:
// TODO(#123): descriptionor create ticket - é©ç¨:
*.ts,*.js,*.tsx,*.jsx
V-5: 深層 import è·¯å¾
- é¡å: regex
- å´é度: medium
- 模å¼:
import.*from\s+['"]\.\.\/\.\.\/\.\.\/|require\s*\(\s*['"]\.\.\/\.\.\/\.\.\/ - è¨æ¯: Deep relative imports indicate poor module boundaries
- 修復建è°: Use path aliases:
import { X } from '@/modules/x' - é©ç¨:
*.ts,*.js,*.tsx,*.jsx