跳转到内容
返回

软件工程核心设计原则:构建可维护代码的基石

发布于:  at  00:00

软件工程核心设计原则:构建可维护代码的基石

随着项目规模增长,问题往往不是「不会写代码」,而是代码越来越难改、一个改动牵连多处、新人不知道规则在哪里。这些问题几乎都源自缺乏清晰一致的设计原则。本文深入探讨五大核心原则——SSOT、DRY、KISS、YAGNI、SRP——它们是构建可维护软件的永恒基石。


1. 原则全景

原则核心关注解决的问题
SSOT唯一权威来源避免逻辑不一致
DRY避免重复实现减少重复代码
KISS保持简单防止过度设计
YAGNI不提前实现避免无用复杂度
SRP单一职责降低修改成本

2. SSOT:Single Source of Truth

核心思想

某个事实,只能有一个权威来源。

SSOT 关注的是数据一致性和规则归属,确保系统中每个「真相」只有一个定义位置。

典型场景

反例:

// 前端硬编码角色列表
const roles = ["admin", "user", "guest"];

// 后端也定义了一份
enum Role {
  ADMIN,
  USER,
  GUEST,
}

正例:

// 后端 API 返回角色列表,前端直接使用
const roles = await fetchRoles();

3. DRY:Don’t Repeat Yourself

核心思想

相同的知识,只写一次。

DRY 关注的是代码结构和逻辑复用,目标是消除复制粘贴。

典型场景

反例:

// 权限检查散落在多处
if (user.role === "admin") {
  /* ... */
}
// 另一个文件
if (currentUser.role === "admin") {
  /* ... */
}

正例:

// 抽取为工具函数
function isAdmin(user: User): boolean {
  return user.role === "admin";
}

SSOT vs DRY

维度SSOTDRY
关注点事实来源实现方式
解决问题多版本真相重复代码
作用层级架构/数据层代码层

4. KISS:Keep It Simple, Stupid

核心思想

能简单解决,就不要复杂化。

KISS 原则由工程师 Kelly Johnson 提出,强调简单性优先。

反模式信号

当你看到这样的命名时,可能想多了:

AbstractFactoryStrategyManagerProviderFactory;

实践要点

反例:

// 过度设计:为简单配置引入复杂模式
class ConfigurationStrategyFactory {
  createStrategy(type: string): ConfigStrategy {
    /* ... */
  }
}

正例:

// 简单直接
const config = {
  apiUrl: process.env.API_URL,
  timeout: 5000,
};

5. YAGNI:You Aren’t Gonna Need It

核心思想

现在不需要的功能,不要提前实现。

典型误区

结果往往是:代码复杂度暴涨,真正需求来了反而原设计不合适。

反例:

// 过早优化:项目只有单一数据源
class MultiDatabaseConnectionPool {
  private pools: Map<string, ConnectionPool>;
  // 复杂的多数据库管理逻辑...
}

正例:

// 满足当前需求即可
const db = new Database(process.env.DATABASE_URL);

6. SRP:Single Responsibility Principle

核心思想

一个模块/类,只对一个变化原因负责。

判断标准

如果描述一个模块的功能需要用「和」连接多件事,它可能违反了 SRP。

反例:

class UserService {
  login(credentials: Credentials) {
    /* ... */
  }
  validatePassword(password: string) {
    /* ... */
  }
  sendWelcomeEmail(user: User) {
    /* ... */
  }
  generateReport(user: User) {
    /* ... */
  }
}

正例:

class AuthService {
  login(credentials: Credentials) {
    /* ... */
  }
  validatePassword(password: string) {
    /* ... */
  }
}

class NotificationService {
  sendWelcomeEmail(user: User) {
    /* ... */
  }
}

class ReportService {
  generateUserReport(user: User) {
    /* ... */
  }
}

7. 原则之间的关系

这些原则并非孤立存在,它们形成一个层次化的约束体系:

┌─────────────────────┐
│        SRP          │  ← 定义职责边界
└──────────┬──────────┘

┌─────────────────────┐
│        DRY          │  ← 在边界内复用
└──────────┬──────────┘

┌─────────────────────┐
│       SSOT          │  ← 确定谁说了算
└──────────┬──────────┘

┌─────────────────────┐
│    KISS + YAGNI     │  ← 约束整体复杂度
└─────────────────────┘

SRP 定边界 → DRY 促复用 → SSOT 定权威 → KISS/YAGNI 控复杂度


8. 工程实践清单

将这些原则转化为日常检查项:


9. 延伸阅读


这些原则不是教条,而是经过数十年验证的工程智慧。掌握它们的精神,比死记规则更重要。



下一页
Unix设计哲学:现代软件的永恒原则