code-quality-principles
Compare original and translation side by side
🇺🇸
Original
English🇨🇳
Translation
ChineseTable of Contents
目录
Code Quality Principles
代码质量原则
Guidance on KISS, YAGNI, and SOLID principles with language-specific examples.
提供KISS、YAGNI和SOLID原则的相关指导,以及各语言的示例。
When To Use
适用场景
- Improving code readability and maintainability
- Applying SOLID, KISS, YAGNI principles during refactoring
- 提升代码的可读性与可维护性
- 在重构过程中应用SOLID、KISS、YAGNI原则
When NOT To Use
不适用场景
- Throwaway scripts or one-time data migrations
- Performance-critical code where readability trades are justified
- 一次性脚本或临时数据迁移任务
- 性能优先的代码场景,此时可读性可以适当让步
KISS (Keep It Simple, Stupid)
KISS(保持简单,别搞复杂)
Principle: Avoid unnecessary complexity. Prefer obvious solutions over clever ones.
原则:避免不必要的复杂度。优先选择直观的解决方案,而非巧妙但晦涩的实现。
Guidelines
指导准则
| Prefer | Avoid |
|---|---|
| Simple conditionals | Complex regex for simple checks |
| Explicit code | Magic numbers/strings |
| Standard patterns | Clever shortcuts |
| Direct solutions | Over-abstracted layers |
| 推荐 | 避免 |
|---|---|
| 简单条件判断 | 用复杂正则处理简单检查 |
| 显式代码 | 魔法数字/字符串 |
| 标准设计模式 | 取巧的捷径 |
| 直接解决方案 | 过度抽象的层级 |
Python Example
Python 示例
python
undefinedpython
undefinedBad: Overly clever one-liner
Bad: Overly clever one-liner
users = [u for u in (db.get(id) for id in ids) if u and u.active and not u.banned]
users = [u for u in (db.get(id) for id in ids) if u and u.active and not u.banned]
Good: Clear and readable
Good: Clear and readable
users = []
for user_id in ids:
user = db.get(user_id)
if user and user.active and not user.banned:
users.append(user)
undefinedusers = []
for user_id in ids:
user = db.get(user_id)
if user and user.active and not user.banned:
users.append(user)
undefinedRust Example
Rust 示例
rust
// Bad: Unnecessary complexity
fn process(data: &[u8]) -> Result<Vec<u8>, Box<dyn std::error::Error>> {
data.iter()
.map(|&b| b.checked_add(1).ok_or("overflow"))
.collect::<Result<Vec<_>, _>>()
.map_err(|e| e.into())
}
// Good: Simple and clear
fn process(data: &[u8]) -> Result<Vec<u8>, &'static str> {
let mut result = Vec::with_capacity(data.len());
for &byte in data {
result.push(byte.checked_add(1).ok_or("overflow")?);
}
Ok(result)
}rust
// Bad: Unnecessary complexity
fn process(data: &[u8]) -> Result<Vec<u8>, Box<dyn std::error::Error>> {
data.iter()
.map(|&b| b.checked_add(1).ok_or("overflow"))
.collect::<Result<Vec<_>, _>>()
.map_err(|e| e.into())
}
// Good: Simple and clear
fn process(data: &[u8]) -> Result<Vec<u8>, &'static str> {
let mut result = Vec::with_capacity(data.len());
for &byte in data {
result.push(byte.checked_add(1).ok_or("overflow")?);
}
Ok(result)
}YAGNI (You Aren't Gonna Need It)
YAGNI(你不会用到它)
Principle: Don't implement features until they are actually needed.
原则:除非确实需要,否则不要实现新功能。
Guidelines
指导准则
| Do | Don't |
|---|---|
| Solve current problem | Build for hypothetical futures |
| Add when 3rd use case appears | Create abstractions for 1 use case |
| Delete dead code | Keep "just in case" code |
| Minimal viable solution | Premature optimization |
| 建议做法 | 避免做法 |
|---|---|
| 解决当前问题 | 为假设的未来需求做开发 |
| 出现第三个用例时再添加 | 只为一个用例创建抽象 |
| 删除无用代码 | 保留“以防万一”的代码 |
| 最小可行解决方案 | 过早优化 |
Python Example
Python 示例
python
undefinedpython
undefinedBad: Premature abstraction for one use case
Bad: Premature abstraction for one use case
class AbstractDataProcessor:
def process(self, data): ...
def validate(self, data): ...
def transform(self, data): ...
class CSVProcessor(AbstractDataProcessor):
def process(self, data):
return self.transform(self.validate(data))
class AbstractDataProcessor:
def process(self, data): ...
def validate(self, data): ...
def transform(self, data): ...
class CSVProcessor(AbstractDataProcessor):
def process(self, data):
return self.transform(self.validate(data))
Good: Simple function until more cases appear
Good: Simple function until more cases appear
def process_csv(data: list[str]) -> list[dict]:
return [parse_row(row) for row in data if row.strip()]
undefineddef process_csv(data: list[str]) -> list[dict]:
return [parse_row(row) for row in data if row.strip()]
undefinedTypeScript Example
TypeScript 示例
typescript
// Bad: Over-engineered config system
interface ConfigProvider<T> {
get<K extends keyof T>(key: K): T[K];
set<K extends keyof T>(key: K, value: T[K]): void;
watch<K extends keyof T>(key: K, callback: (v: T[K]) => void): void;
}
// Good: Simple config for current needs
const config = {
apiUrl: process.env.API_URL || 'http://localhost:3000',
timeout: 5000,
};typescript
// Bad: Over-engineered config system
interface ConfigProvider<T> {
get<K extends keyof T>(key: K): T[K];
set<K extends keyof T>(key: K, value: T[K]): void;
watch<K extends keyof T>(key: K, callback: (v: T[K]) => void): void;
}
// Good: Simple config for current needs
const config = {
apiUrl: process.env.API_URL || 'http://localhost:3000',
timeout: 5000,
};SOLID Principles
SOLID 原则
Single Responsibility Principle
单一职责原则
Each module/class should have one reason to change.
python
undefined每个模块/类应该只有一个修改的理由。
python
undefinedBad: Multiple responsibilities
Bad: Multiple responsibilities
class UserManager:
def create_user(self, data): ...
def send_welcome_email(self, user): ... # Email responsibility
def generate_report(self, users): ... # Reporting responsibility
class UserManager:
def create_user(self, data): ...
def send_welcome_email(self, user): ... # Email responsibility
def generate_report(self, users): ... # Reporting responsibility
Good: Separated responsibilities
Good: Separated responsibilities
class UserRepository:
def create(self, data): ...
class EmailService:
def send_welcome(self, user): ...
class UserReportGenerator:
def generate(self, users): ...
undefinedclass UserRepository:
def create(self, data): ...
class EmailService:
def send_welcome(self, user): ...
class UserReportGenerator:
def generate(self, users): ...
undefinedOpen/Closed Principle
开闭原则
Open for extension, closed for modification.
python
undefined对扩展开放,对修改关闭。
python
undefinedBad: Requires modification for new types
Bad: Requires modification for new types
def calculate_area(shape):
if shape.type == "circle":
return 3.14 * shape.radius ** 2
elif shape.type == "rectangle":
return shape.width * shape.height
# Must modify to add new shapes
def calculate_area(shape):
if shape.type == "circle":
return 3.14 * shape.radius ** 2
elif shape.type == "rectangle":
return shape.width * shape.height
# Must modify to add new shapes
Good: Extensible without modification
Good: Extensible without modification
from abc import ABC, abstractmethod
class Shape(ABC):
@abstractmethod
def area(self) -> float: ...
class Circle(Shape):
def init(self, radius: float):
self.radius = radius
def area(self) -> float:
return 3.14 * self.radius ** 2
undefinedfrom abc import ABC, abstractmethod
class Shape(ABC):
@abstractmethod
def area(self) -> float: ...
class Circle(Shape):
def init(self, radius: float):
self.radius = radius
def area(self) -> float:
return 3.14 * self.radius ** 2
undefinedLiskov Substitution Principle
里氏替换原则
Subtypes must be substitutable for their base types.
python
undefined子类必须能够替换其基类使用。
python
undefinedBad: Violates LSP - Square changes Rectangle behavior
Bad: Violates LSP - Square changes Rectangle behavior
class Rectangle:
def set_width(self, w): self.width = w
def set_height(self, h): self.height = h
class Square(Rectangle): # Breaks when used as Rectangle
def set_width(self, w):
self.width = self.height = w # Unexpected side effect
class Rectangle:
def set_width(self, w): self.width = w
def set_height(self, h): self.height = h
class Square(Rectangle): # Breaks when used as Rectangle
def set_width(self, w):
self.width = self.height = w # Unexpected side effect
Good: Separate types with common interface
Good: Separate types with common interface
class Shape(ABC):
@abstractmethod
def area(self) -> float: ...
class Rectangle(Shape):
def init(self, width: float, height: float): ...
class Square(Shape):
def init(self, side: float): ...
undefinedclass Shape(ABC):
@abstractmethod
def area(self) -> float: ...
class Rectangle(Shape):
def init(self, width: float, height: float): ...
class Square(Shape):
def init(self, side: float): ...
undefinedInterface Segregation Principle
接口隔离原则
Clients shouldn't depend on interfaces they don't use.
typescript
// Bad: Fat interface
interface Worker {
work(): void;
eat(): void;
sleep(): void;
}
// Good: Segregated interfaces
interface Workable {
work(): void;
}
interface Feedable {
eat(): void;
}
// Clients only implement what they need
class Robot implements Workable {
work(): void { /* ... */ }
}客户端不应该依赖它不需要的接口。
typescript
// Bad: Fat interface
interface Worker {
work(): void;
eat(): void;
sleep(): void;
}
// Good: Segregated interfaces
interface Workable {
work(): void;
}
interface Feedable {
eat(): void;
}
// Clients only implement what they need
class Robot implements Workable {
work(): void { /* ... */ }
}Dependency Inversion Principle
依赖倒置原则
Depend on abstractions, not concretions.
python
undefined依赖抽象,而非具体实现。
python
undefinedBad: Direct dependency on concrete class
Bad: Direct dependency on concrete class
class OrderService:
def init(self):
self.db = PostgresDatabase() # Tight coupling
class OrderService:
def init(self):
self.db = PostgresDatabase() # Tight coupling
Good: Depend on abstraction
Good: Depend on abstraction
from abc import ABC, abstractmethod
class Database(ABC):
@abstractmethod
def save(self, data): ...
class OrderService:
def init(self, db: Database):
self.db = db # Injected abstraction
undefinedfrom abc import ABC, abstractmethod
class Database(ABC):
@abstractmethod
def save(self, data): ...
class OrderService:
def init(self, db: Database):
self.db = db # Injected abstraction
undefinedQuick Reference
快速参考
| Principle | Question to Ask | Red Flag |
|---|---|---|
| KISS | "Is there a simpler way?" | Complex solution for simple problem |
| YAGNI | "Do I need this right now?" | Building for hypothetical use cases |
| SRP | "What's the one reason to change?" | Class doing multiple jobs |
| OCP | "Can I extend without modifying?" | Switch statements for types |
| LSP | "Can subtypes replace base types?" | Overridden methods with side effects |
| ISP | "Does client need all methods?" | Empty method implementations |
| DIP | "Am I depending on abstractions?" | |
| 原则 | 自问问题 | 危险信号 |
|---|---|---|
| KISS | “有没有更简单的方式?” | 用复杂方案解决简单问题 |
| YAGNI | “我现在就需要这个吗?” | 为假设的用例做开发 |
| SRP | “它只有一个修改理由吗?” | 一个类负责多项工作 |
| OCP | “我能在不修改的情况下扩展它吗?” | 针对类型的switch语句 |
| LSP | “子类能替换基类使用吗?” | 重写的方法有意外副作用 |
| ISP | “客户端需要所有方法吗?” | 空方法实现 |
| DIP | “我依赖的是抽象吗?” | 业务逻辑中使用 |
When Principles Conflict
当原则发生冲突时
- KISS vs SOLID: For small projects, KISS wins. Add SOLID patterns as complexity grows.
- YAGNI vs DIP: Don't add abstractions until you have 2+ implementations.
- Readability vs DRY: Prefer slight duplication over wrong abstraction.
- KISS vs SOLID:小型项目中优先遵循KISS。随着复杂度提升,再引入SOLID模式。
- YAGNI vs DIP:除非有2个及以上实现,否则不要添加抽象。
- 可读性 vs DRY:宁愿接受轻微重复,也不要错误的抽象。
Integration with Code Review
与代码评审的结合
When reviewing code, check:
- No unnecessary complexity (KISS)
- No speculative features (YAGNI)
- Each class has single responsibility (SRP)
- No god classes (> 500 lines)
- Dependencies are injected, not created (DIP)
Verification: Run to check line counts and to count classes per file.
wc -l <file>grep -c "class " <file>评审代码时,检查以下内容:
- 无不必要的复杂度(KISS)
- 无投机性功能(YAGNI)
- 每个类只有单一职责(SRP)
- 无上帝类(超过500行)
- 依赖是注入的,而非直接创建的(DIP)
验证方法:运行检查代码行数,运行统计每个文件中的类数量。
wc -l <file>grep -c "class " <file>