software-architecture
Compare original and translation side by side
🇺🇸
Original
English🇨🇳
Translation
ChineseSoftware Architecture
软件架构
SOLID Principles
SOLID原则
Single Responsibility Principle (SRP)
单一职责原则(SRP)
A class should have only one reason to change.
typescript
// ❌ Bad: Multiple responsibilities
class User {
saveToDatabase() { }
sendEmail() { }
generateReport() { }
}
// ✅ Good: Single responsibility
class User { }
class UserRepository { save(user: User) { } }
class EmailService { send(to: string) { } }
class ReportGenerator { generate(user: User) { } }一个类应该只有一个引起变化的原因。
typescript
// ❌ Bad: Multiple responsibilities
class User {
saveToDatabase() { }
sendEmail() { }
generateReport() { }
}
// ✅ Good: Single responsibility
class User { }
class UserRepository { save(user: User) { } }
class EmailService { send(to: string) { } }
class ReportGenerator { generate(user: User) { } }Open/Closed Principle (OCP)
开闭原则(OCP)
Open for extension, closed for modification.
typescript
// ❌ Bad: Requires modification for new types
function calculateArea(shape: Shape) {
if (shape.type === 'circle') {
return Math.PI * shape.radius ** 2;
} else if (shape.type === 'rectangle') {
return shape.width * shape.height;
}
// Need to modify for new shapes
}
// ✅ Good: Extend without modification
interface Shape {
area(): number;
}
class Circle implements Shape {
constructor(private radius: number) {}
area() { return Math.PI * this.radius ** 2; }
}
class Rectangle implements Shape {
constructor(private width: number, private height: number) {}
area() { return this.width * this.height; }
}对扩展开放,对修改关闭。
typescript
// ❌ Bad: Requires modification for new types
function calculateArea(shape: Shape) {
if (shape.type === 'circle') {
return Math.PI * shape.radius ** 2;
} else if (shape.type === 'rectangle') {
return shape.width * shape.height;
}
// Need to modify for new shapes
}
// ✅ Good: Extend without modification
interface Shape {
area(): number;
}
class Circle implements Shape {
constructor(private radius: number) {}
area() { return Math.PI * this.radius ** 2; }
}
class Rectangle implements Shape {
constructor(private width: number, private height: number) {}
area() { return this.width * this.height; }
}Liskov Substitution Principle (LSP)
里氏替换原则(LSP)
Subtypes must be substitutable for their base types.
typescript
// ❌ Bad: Square violates Rectangle's contract
class Rectangle {
setWidth(w: number) { this.width = w; }
setHeight(h: number) { this.height = h; }
}
class Square extends Rectangle {
setWidth(w: number) { this.width = w; this.height = w; } // Violates LSP
}
// ✅ Good: Separate hierarchies
interface Shape {
area(): number;
}
class Rectangle implements Shape { }
class Square implements Shape { }子类必须能够替换其基类。
typescript
// ❌ Bad: Square violates Rectangle's contract
class Rectangle {
setWidth(w: number) { this.width = w; }
setHeight(h: number) { this.height = h; }
}
class Square extends Rectangle {
setWidth(w: number) { this.width = w; this.height = w; } // Violates LSP
}
// ✅ Good: Separate hierarchies
interface Shape {
area(): number;
}
class Rectangle implements Shape { }
class Square implements Shape { }Interface Segregation Principle (ISP)
接口隔离原则(ISP)
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 Eatable { eat(): void; }
interface Sleepable { sleep(): void; }
class Human implements Workable, Eatable, Sleepable { }
class Robot implements Workable { }客户端不应该依赖它不需要的接口。
typescript
// ❌ Bad: Fat interface
interface Worker {
work(): void;
eat(): void;
sleep(): void;
}
// ✅ Good: Segregated interfaces
interface Workable { work(): void; }
interface Eatable { eat(): void; }
interface Sleepable { sleep(): void; }
class Human implements Workable, Eatable, Sleepable { }
class Robot implements Workable { }Dependency Inversion Principle (DIP)
依赖倒置原则(DIP)
Depend on abstractions, not concretions.
typescript
// ❌ Bad: High-level depends on low-level
class UserService {
private database = new MySQLDatabase();
}
// ✅ Good: Both depend on abstraction
interface Database {
save(data: any): Promise<void>;
find(id: string): Promise<any>;
}
class UserService {
constructor(private database: Database) {}
}
// Now can inject any implementation
const service = new UserService(new MySQLDatabase());
const testService = new UserService(new MockDatabase());依赖于抽象,而非具体实现。
typescript
// ❌ Bad: High-level depends on low-level
class UserService {
private database = new MySQLDatabase();
}
// ✅ Good: Both depend on abstraction
interface Database {
save(data: any): Promise<void>;
find(id: string): Promise<any>;
}
class UserService {
constructor(private database: Database) {}
}
// Now can inject any implementation
const service = new UserService(new MySQLDatabase());
const testService = new UserService(new MockDatabase());Clean Architecture
Clean Architecture
┌─────────────────────────────────────────────────┐
│ Frameworks │
│ (Express, React, Database Drivers) │
├─────────────────────────────────────────────────┤
│ Interface Adapters │
│ (Controllers, Presenters, Gateways) │
├─────────────────────────────────────────────────┤
│ Application Layer │
│ (Use Cases, Application Services) │
├─────────────────────────────────────────────────┤
│ Domain Layer │
│ (Entities, Value Objects, Domain Services) │
└─────────────────────────────────────────────────┘
Dependencies point INWARD only.
Inner layers know nothing about outer layers.┌─────────────────────────────────────────────────┐
│ Frameworks │
│ (Express, React, Database Drivers) │
├─────────────────────────────────────────────────┤
│ Interface Adapters │
│ (Controllers, Presenters, Gateways) │
├─────────────────────────────────────────────────┤
│ Application Layer │
│ (Use Cases, Application Services) │
├─────────────────────────────────────────────────┤
│ Domain Layer │
│ (Entities, Value Objects, Domain Services) │
└─────────────────────────────────────────────────┘
依赖关系仅指向内部。
内层对外层一无所知。Domain Layer (Innermost)
领域层(最内层)
typescript
// entities/User.ts
export class User {
constructor(
public readonly id: string,
public readonly email: Email,
public name: string,
private password: HashedPassword
) {}
changeName(newName: string): void {
if (newName.length < 2) {
throw new DomainError('Name too short');
}
this.name = newName;
}
verifyPassword(plaintext: string): boolean {
return this.password.verify(plaintext);
}
}
// value-objects/Email.ts
export class Email {
constructor(private readonly value: string) {
if (!this.isValid(value)) {
throw new DomainError('Invalid email');
}
}
private isValid(email: string): boolean {
return /^[^\s@]+@[^\s@]+\.[^\s@]+$/.test(email);
}
toString(): string {
return this.value;
}
}typescript
// entities/User.ts
export class User {
constructor(
public readonly id: string,
public readonly email: Email,
public name: string,
private password: HashedPassword
) {}
changeName(newName: string): void {
if (newName.length < 2) {
throw new DomainError('Name too short');
}
this.name = newName;
}
verifyPassword(plaintext: string): boolean {
return this.password.verify(plaintext);
}
}
// value-objects/Email.ts
export class Email {
constructor(private readonly value: string) {
if (!this.isValid(value)) {
throw new DomainError('Invalid email');
}
}
private isValid(email: string): boolean {
return /^[^\s@]+@[^\s@]+\.[^\s@]+$/.test(email);
}
toString(): string {
return this.value;
}
}Application Layer (Use Cases)
应用层(用例)
typescript
// use-cases/CreateUser.ts
interface CreateUserInput {
email: string;
password: string;
name: string;
}
interface CreateUserOutput {
id: string;
email: string;
name: string;
}
export class CreateUserUseCase {
constructor(
private userRepository: UserRepository,
private passwordHasher: PasswordHasher,
private emailService: EmailService
) {}
async execute(input: CreateUserInput): Promise<CreateUserOutput> {
// Validate email uniqueness
const existing = await this.userRepository.findByEmail(input.email);
if (existing) {
throw new ApplicationError('Email already exists');
}
// Create domain object
const hashedPassword = await this.passwordHasher.hash(input.password);
const user = new User(
generateId(),
new Email(input.email),
input.name,
hashedPassword
);
// Persist
await this.userRepository.save(user);
// Side effects
await this.emailService.sendWelcome(user.email);
return {
id: user.id,
email: user.email.toString(),
name: user.name,
};
}
}typescript
// use-cases/CreateUser.ts
interface CreateUserInput {
email: string;
password: string;
name: string;
}
interface CreateUserOutput {
id: string;
email: string;
name: string;
}
export class CreateUserUseCase {
constructor(
private userRepository: UserRepository,
private passwordHasher: PasswordHasher,
private emailService: EmailService
) {}
async execute(input: CreateUserInput): Promise<CreateUserOutput> {
// Validate email uniqueness
const existing = await this.userRepository.findByEmail(input.email);
if (existing) {
throw new ApplicationError('Email already exists');
}
// Create domain object
const hashedPassword = await this.passwordHasher.hash(input.password);
const user = new User(
generateId(),
new Email(input.email),
input.name,
hashedPassword
);
// Persist
await this.userRepository.save(user);
// Side effects
await this.emailService.sendWelcome(user.email);
return {
id: user.id,
email: user.email.toString(),
name: user.name,
};
}
}Interface Adapters
接口适配器层
typescript
// controllers/UserController.ts
export class UserController {
constructor(private createUserUseCase: CreateUserUseCase) {}
async create(req: Request, res: Response): Promise<void> {
const result = await this.createUserUseCase.execute({
email: req.body.email,
password: req.body.password,
name: req.body.name,
});
res.status(201).json(result);
}
}
// repositories/PrismaUserRepository.ts
export class PrismaUserRepository implements UserRepository {
async save(user: User): Promise<void> {
await prisma.user.create({
data: {
id: user.id,
email: user.email.toString(),
name: user.name,
},
});
}
async findByEmail(email: string): Promise<User | null> {
const data = await prisma.user.findUnique({
where: { email },
});
return data ? this.toDomain(data) : null;
}
private toDomain(data: PrismaUser): User {
return new User(
data.id,
new Email(data.email),
data.name,
new HashedPassword(data.password)
);
}
}typescript
// controllers/UserController.ts
export class UserController {
constructor(private createUserUseCase: CreateUserUseCase) {}
async create(req: Request, res: Response): Promise<void> {
const result = await this.createUserUseCase.execute({
email: req.body.email,
password: req.body.password,
name: req.body.name,
});
res.status(201).json(result);
}
}
// repositories/PrismaUserRepository.ts
export class PrismaUserRepository implements UserRepository {
async save(user: User): Promise<void> {
await prisma.user.create({
data: {
id: user.id,
email: user.email.toString(),
name: user.name,
},
});
}
async findByEmail(email: string): Promise<User | null> {
const data = await prisma.user.findUnique({
where: { email },
});
return data ? this.toDomain(data) : null;
}
private toDomain(data: PrismaUser): User {
return new User(
data.id,
new Email(data.email),
data.name,
new HashedPassword(data.password)
);
}
}Design Patterns
设计模式
Repository Pattern
仓库模式
typescript
interface Repository<T> {
findById(id: string): Promise<T | null>;
findAll(): Promise<T[]>;
save(entity: T): Promise<void>;
delete(id: string): Promise<void>;
}typescript
interface Repository<T> {
findById(id: string): Promise<T | null>;
findAll(): Promise<T[]>;
save(entity: T): Promise<void>;
delete(id: string): Promise<void>;
}Factory Pattern
工厂模式
typescript
interface PaymentProcessor {
process(amount: number): Promise<void>;
}
class PaymentProcessorFactory {
create(type: 'stripe' | 'paypal'): PaymentProcessor {
switch (type) {
case 'stripe': return new StripeProcessor();
case 'paypal': return new PayPalProcessor();
}
}
}typescript
interface PaymentProcessor {
process(amount: number): Promise<void>;
}
class PaymentProcessorFactory {
create(type: 'stripe' | 'paypal'): PaymentProcessor {
switch (type) {
case 'stripe': return new StripeProcessor();
case 'paypal': return new PayPalProcessor();
}
}
}Strategy Pattern
策略模式
typescript
interface PricingStrategy {
calculate(basePrice: number): number;
}
class RegularPricing implements PricingStrategy {
calculate(basePrice: number) { return basePrice; }
}
class PremiumPricing implements PricingStrategy {
calculate(basePrice: number) { return basePrice * 0.9; }
}
class Order {
constructor(private pricingStrategy: PricingStrategy) {}
getTotal(basePrice: number) {
return this.pricingStrategy.calculate(basePrice);
}
}typescript
interface PricingStrategy {
calculate(basePrice: number): number;
}
class RegularPricing implements PricingStrategy {
calculate(basePrice: number) { return basePrice; }
}
class PremiumPricing implements PricingStrategy {
calculate(basePrice: number) { return basePrice * 0.9; }
}
class Order {
constructor(private pricingStrategy: PricingStrategy) {}
getTotal(basePrice: number) {
return this.pricingStrategy.calculate(basePrice);
}
}Observer Pattern
观察者模式
typescript
interface Observer<T> {
update(data: T): void;
}
class EventEmitter<T> {
private observers: Observer<T>[] = [];
subscribe(observer: Observer<T>): void {
this.observers.push(observer);
}
notify(data: T): void {
this.observers.forEach(o => o.update(data));
}
}typescript
interface Observer<T> {
update(data: T): void;
}
class EventEmitter<T> {
private observers: Observer<T>[] = [];
subscribe(observer: Observer<T>): void {
this.observers.push(observer);
}
notify(data: T): void {
this.observers.forEach(o => o.update(data));
}
}Architecture Decision Records (ADR)
架构决策记录(ADR)
Document significant decisions:
markdown
undefined记录重大决策:
markdown
undefinedADR-001: Use PostgreSQL for Primary Database
ADR-001:选用PostgreSQL作为主数据库
Status
状态
Accepted
已接受
Context
背景
Need to choose a primary database for user data storage.
需要为用户数据存储选择主数据库。
Decision
决策
Use PostgreSQL.
选用PostgreSQL。
Consequences
影响
Positive
积极影响
- Strong consistency guarantees
- Rich query capabilities
- Well-supported ORMs
- 强一致性保障
- 丰富的查询能力
- 支持完善的ORM
Negative
消极影响
- Requires more operational overhead than SQLite
- Horizontal scaling more complex than NoSQL
undefined- 相比SQLite需要更多运维成本
- 水平扩展比NoSQL更复杂
undefinedAnti-Patterns to Avoid
需避免的反模式
God Object
上帝对象
❌ One class that does everything
❌ 一个类包办所有功能
Spaghetti Code
面条代码
❌ No clear structure or flow
❌ 没有清晰的结构或流程
Golden Hammer
万能锤子
❌ Using same solution for every problem
❌ 用同一解决方案应对所有问题
Premature Optimization
过早优化
❌ Optimizing before measuring
❌ 在未做度量前就进行优化
Cargo Cult Programming
盲目跟风编程
❌ Using patterns without understanding why
❌ 不理解原理就使用模式