输出2份设计原则

63 阅读10分钟

软件设计原则 (Software Design Principles)

这些原则的共同目标:写出易读、易维护、易扩展的代码


一、基础原则

KISS (Keep It Simple, Stupid)

保持简单

  • 代码越简单越好,避免不必要的复杂性
  • 能用 3 行代码解决的问题,不要写 30 行
  • 简单的方案通常更容易维护和调试
// Bad - 过度设计
const isEven = (n) => new Promise((resolve) =>
  setTimeout(() => resolve(n % 2 === 0), 0));

// Good - 简单直接
const isEven = (n) => n % 2 === 0;

YAGNI (You Aren't Gonna Need It)

你不会需要它

  • 不要为"将来可能需要"的功能写代码
  • 只实现当前确实需要的功能
  • 预测未来需求往往是错的,白费功夫
// Bad - 预设了很多用不到的配置
function createUser(name, options = {
  enableNotifications: true,
  theme: 'dark',
  language: 'zh',
  timezone: 'Asia/Shanghai',
  // ... 20 个可能永远用不到的选项
}) { ... }

// Good - 只做需要的
function createUser(name) { ... }

DRY (Don't Repeat Yourself)

不要重复自己

  • 相同逻辑只写一次,避免复制粘贴代码
  • 重复代码意味着修改时要改多处,容易遗漏
// Bad - 重复代码
function validateEmail(email) {
  const regex = /^[^\s@]+@[^\s@]+\.[^\s@]+$/;
  return regex.test(email);
}
function validateUserEmail(email) {
  const regex = /^[^\s@]+@[^\s@]+\.[^\s@]+$/;
  return regex.test(email);
}

// Good - 复用
function validateEmail(email) {
  const regex = /^[^\s@]+@[^\s@]+\.[^\s@]+$/;
  return regex.test(email);
}
// 其他地方直接调用 validateEmail()

WET (Write Everything Twice)

写两遍再抽象 - DRY 的平衡

  • 过早抽象比重复更糟糕
  • 等代码重复 2-3 次再考虑抽象
  • 避免为了 DRY 而创建不合理的抽象

二、SOLID 原则(面向对象五大原则)

S - Single Responsibility Principle (SRP)

单一职责原则

一个类/函数只做一件事,只有一个修改的理由。

// Bad - 一个类做太多事
class User {
  saveToDatabase() { ... }
  sendEmail() { ... }
  generateReport() { ... }
}

// Good - 职责分离
class User { ... }
class UserRepository { saveToDatabase() { ... } }
class EmailService { sendEmail() { ... } }
class ReportGenerator { generateReport() { ... } }

O - Open/Closed Principle (OCP)

开闭原则

对扩展开放,对修改关闭。添加新功能时,不应修改现有代码。

// Bad - 每次加新类型都要改这个函数
function calculateArea(shape) {
  if (shape.type === 'circle') {
    return Math.PI * shape.radius ** 2;
  } else if (shape.type === 'rectangle') {
    return shape.width * shape.height;
  }
  // 新增类型要改这里...
}

// Good - 通过多态扩展
class Shape {
  area() { throw new Error('Must implement'); }
}
class Circle extends Shape {
  area() { return Math.PI * this.radius ** 2; }
}
class Rectangle extends Shape {
  area() { return this.width * this.height; }
}

L - Liskov Substitution Principle (LSP)

里氏替换原则

子类可以替换父类,程序行为不变。

// Bad - 子类破坏了父类的契约
class Bird {
  fly() { return 'flying'; }
}
class Penguin extends Bird {
  fly() { throw new Error('Cannot fly'); } // 违反 LSP
}

// Good - 重新设计继承关系
class Bird { ... }
class FlyingBird extends Bird {
  fly() { return 'flying'; }
}
class Penguin extends Bird {
  swim() { return 'swimming'; }
}

I - Interface Segregation Principle (ISP)

接口隔离原则

接口要小而专一,不要强迫实现不需要的方法。

// Bad - 臃肿的接口
interface Worker {
  work(): void;
  eat(): void;
  sleep(): void;
}

// Good - 拆分接口
interface Workable {
  work(): void;
}
interface Eatable {
  eat(): void;
}
// 按需实现
class Robot implements Workable {
  work() { ... }
}

D - Dependency Inversion Principle (DIP)

依赖倒置原则

依赖抽象而非具体实现。高层模块不应依赖低层模块。

// Bad - 直接依赖具体实现
class UserService {
  constructor() {
    this.db = new MySQLDatabase(); // 紧耦合
  }
}

// Good - 依赖抽象
class UserService {
  constructor(database) { // 注入抽象
    this.db = database;
  }
}
// 可以传入任何实现了 Database 接口的对象
new UserService(new MySQLDatabase());
new UserService(new PostgreSQLDatabase());

三、其他重要原则

LoD / Law of Demeter

迪米特法则 / 最少知识原则

对象只与直接朋友通信,不要链式调用陌生对象。

// Bad - 知道太多内部结构
order.getCustomer().getAddress().getCity();

// Good - 只问直接对象
order.getShippingCity();

Separation of Concerns (SoC)

关注点分离

不同功能的代码分开放,各司其职。

典型应用:MVC 模式
- Model: 数据和业务逻辑
- View: 界面展示
- Controller: 处理用户输入

SLAP (Single Level of Abstraction Principle)

单一抽象层次原则

一个函数内的代码应该在同一抽象层级。

// Bad - 混合抽象层次
function processOrder(order) {
  // 高层抽象
  validateOrder(order);
  // 突然变成低层细节
  const connection = mysql.createConnection({...});
  connection.query('INSERT INTO orders...');
  // 又回到高层
  sendConfirmationEmail(order);
}

// Good - 保持同一层次
function processOrder(order) {
  validateOrder(order);
  saveOrder(order);
  sendConfirmationEmail(order);
}

四、速查表

原则缩写一句话总结
Keep It Simple, StupidKISS保持简单
You Aren't Gonna Need ItYAGNI不需要就别写
Don't Repeat YourselfDRY别重复
Write Everything TwiceWET别过早抽象
Single ResponsibilitySRP一个类只做一件事
Open/ClosedOCP扩展开放,修改关闭
Liskov SubstitutionLSP子类能替换父类
Interface SegregationISP接口要小而专
Dependency InversionDIP依赖抽象不依赖具体
Law of DemeterLoD少管闲事
Separation of ConcernsSoC各管各的
Single Level of AbstractionSLAP同一抽象层次

五、如何应用

  1. 不要教条:原则是指导,不是铁律
  2. 权衡取舍:有时原则之间会冲突,需要判断
  3. 渐进改进:先让代码工作,再逐步优化
  4. 团队共识:原则的应用程度需要团队达成一致

"任何傻瓜都能写出计算机能理解的代码。优秀的程序员写出人类能理解的代码。" — Martin Fowler


产品设计原则 (Product Design Principles)

这些原则的共同目标:创造用户真正需要、易用且有价值的产品


一、用户体验基础原则

尼尔森十大可用性原则 (Nielsen's 10 Usability Heuristics)

Jakob Nielsen 于 1994 年提出,至今仍是 UX 设计的黄金标准。

#原则说明
1系统状态可见性让用户知道正在发生什么(加载中、已保存、出错了)
2系统与现实匹配使用用户熟悉的语言和概念,而非技术术���
3用户控制与自由提供"撤销"和"退出",让用户能纠正错误
4一致性与标准相同的操作产生相同的结果,遵循平台惯例
5错误预防比起好的错误提示,更好的是从源头防止错误
6识别而非回忆让选项可见,减少用户记忆负担
7灵活性与效率为新手和专家都提供合适的操作方式
8美学与极简设计只展示必要信息,避免视觉噪音
9帮助用户识别和恢复错误错误提示要说人话,并提供解决方案
10帮助与文档最好不需要文档,但必要时要易于搜索和理解

格式塔原则 (Gestalt Principles)

视觉感知心理学原则

原则说明应用
接近性靠近的元素被视为一组表单分组、导航菜单
相似性相似的元素被视为一组按钮样式、图标风格
连续性眼睛会沿着路径移动流程图、时间线
闭合性大脑会补全不完整的形状Logo 设计、图标
图底关系区分前景和背景弹窗、卡片阴影
共同命运一起移动的元素被视为一组动画、拖拽排序

二、交互设计原则

费茨定律 (Fitts's Law)

点击目标的时间与距离和大小有关

时间 = a + b × log₂(距离/大小 + 1)

应用:

  • 重要按钮要足够大
  • 常用功能放在容易触达的位置
  • 移动端按钮最小 44×44px

希克定律 (Hick's Law)

选择越多,决策时间越长

时间 = a + b × log₂(n + 1)  // n = 选项数量

应用:

  • 减少选项数量(推荐 5-7 个)
  • 分类和分组选项
  • 提供默认选项和推荐

米勒定律 (Miller's Law)

短期记忆容量约为 7±2 个单元

应用:

  • 导航菜单不超过 7 项
  • 电话号码分段显示:138-0000-0000
  • 步骤流程控制在 5-7 步

雅各布定律 (Jakob's Law)

用户把大部分时间花在其他网站上

用户期望你的产品和他们熟悉的产品一样工作。

应用:

  • 遵循平台设计规范(iOS HIG、Material Design)
  • 不要重新发明轮子(购物车图标、汉堡菜单)
  • 创新要渐进,不要颠覆用户认知

多尔蒂门槛 (Doherty Threshold)

响应时间 < 400ms 时,用户会保持专注

响应时间用户感受
< 100ms即时
100-300ms流畅
300-1000ms可接受
> 1000ms需要加载提示
> 10s用户可能离开

奥卡姆剃刀 (Occam's Razor)

如无必要,勿增实体

最简单的解决方案通常是最好的。

应用:

  • 功能做减法
  • 界面元素最小化
  • 流程步骤最少化

三、产品策略原则

MVP (Minimum Viable Product)

最小可行产品

用最少的功能验证核心假设,快速获取用户反馈。

传统方式:花 6 个月做完整产品 → 发现没人要
MVP 方式:花 2 周做核心功能 → 验证 → 迭代

80/20 法则 (Pareto Principle)

80% 的结果来自 20% 的原因

应用:

  • 80% 用户只用 20% 功能 → 优化核心功能
  • 80% 问题来自 20% 原因 → 聚焦关键问题
  • 80% 收入来自 20% 用户 → 服务好核心用户

峰终定律 (Peak-End Rule)

用户记住的是体验的峰值和结尾

应用:

  • 创造"哇"时刻(峰值体验)
  • 优化结束体验(感谢页、确认邮件)
  • 即使过程有问题,好的结尾也能挽回印象

宜家效应 (IKEA Effect)

用户对自己参与创造的东西估值更高

应用:

  • 让用户自定义(头像、主题、布局)
  • 引导用户完成设置流程
  • 用户生成内容(UGC)

损失厌恶 (Loss Aversion)

失去的痛苦 > 获得的快乐(约 2 倍)

应用:

  • "还剩 3 件" 比 "库存充足" 更有效
  • 免费试用到期提醒
  • 积分/等级即将过期

四、设计系统原则

原子设计 (Atomic Design)

从小到大构建设计系统

原子 → 分子 → 组织 → 模板 → 页面
(按钮) (搜索框) (导航栏) (列表页) (首页)

设计一致性三层次

层次说明示例
视觉一致性颜色、字体、间距统一品牌色、字号规范
功能一致性相同组件行为一致所有删除都需确认
外部一致性符合平台/行业惯例iOS 返回在左上角

五、无障碍设计原则 (Accessibility - A11Y)

WCAG 四大原则

原则说明
可感知信息能被所有感官获取(文字、语音、触觉)
可操作所有功能可通过键盘操作
可理解内容和操作易于理解
健壮性兼容各种辅助技术

实践要点

  • 图片添加 alt 文本
  • 颜色对比度 ≥ 4.5:1
  • 可点击区域 ≥ 44×44px
  • 支持键盘导航
  • 不仅靠颜色传达信息

六、速查表

用户体验

原则一句话
尼尔森十原则可用性设计黄金标准
格式塔原则视觉分组和感知
费茨定律目标要大、距离要近
希克定律选项要少
米勒定律记忆容量 7±2
雅各布定律遵循用户习惯
多尔蒂门槛响应要快(<400ms)
奥卡姆剃刀保持简单

产品策略

原则一句话
MVP最小功能快速验证
80/20 法则聚焦关键 20%
峰终定律做好高潮和结尾
宜家效应让用户参与创造
损失厌恶失去比得到更痛

七、推荐资源

书籍

  • 《设计心理学》- Don Norman
  • 《点石成金》- Steve Krug
  • 《简约至上》- Giles Colborne
  • 《用户体验要素》- Jesse James Garrett

网站