软件分层的判断

## 一个软件分层包含哪些必要元素? 🧱

一个逻辑上的“层”本身并不是由固定的代码元素构成的,而是由其承担的职责和遵循的设计原则来定义的。一个健康的软件分层应具备以下必要特征:

  1. 明确的职责 (Defined Responsibility): 每个层必须有一个单一且明确的职责。这是分层的基础。常见的职责划分如下:
    • 表示层 (Presentation Layer): 负责处理用户交互和界面显示(UI)。例如,接收HTTP请求、渲染HTML页面、与浏览器交互。
    • 业务逻辑层 (Business Logic Layer / Application Layer): 实现系统的核心业务规则和流程。这是应用“大脑”所在,它不关心数据如何存储或如何显示。
    • 数据访问层 (Data Access Layer / Persistence Layer): 负责与数据库或其他数据存储系统进行交互,执行数据的增删改查(CRUD)操作。
  2. 高内聚 (High Cohesion): 层内部的所有子模块和组件都应该紧密相关,共同为实现该层的唯一职责服务。例如,数据访问层应只包含与数据存取相关的代码(如数据库连接、SQL语句、对象关系映射ORM等)。
  3. 清晰的接口 (Well-Defined Interface): 每个层必须向其上层提供一个稳定、清晰的接口(API)。上层通过这个接口调用下层的功能,而无需知道其内部复杂的实现细节。这体现了抽象 (Abstraction) 的原则。
  4. 有限的依赖 (Limited Dependencies): 理想情况下,一个层只应该依赖于它正下方的层。这种单向依赖关系可以防止“意大利面条式”的混乱代码。这也被称为低耦合 (Low Coupling)

## 如何判断哪些子模块属于一个层? 🤔

判断一个子模块应归属于哪个层,主要依据其核心职责和功能。你可以通过以下几个原则来进行判断:

  • 职责单一原则 (Single Responsibility Principle): 问问自己:“这个模块的核心功能是什么?”
    • 如果它处理的是用户输入、界面渲染或API请求/响应,它属于表示层
    • 如果它实现的是核心业务规则(例如,计算订单总价、检查用户权限),它属于业务逻辑层
    • 如果它负责将数据写入数据库或从文件中读取数据,它属于数据访问层
  • 依赖方向原则 (Dependency Direction): 检查模块的依赖关系。一个模块不应该“跨级”调用。例如,表示层的模块不应直接调用数据访问层的模块,而必须通过业务逻辑层。如果发现一个模块需要直接操作数据库,但它又在处理HTTP请求,那么这个模块的职责可能没有划分清楚。
  • 抽象层次原则 (Level of Abstraction): 同一层内的模块应该处于相似的抽象层次。例如,处理高级业务概念(如“用户注册”)的模块和处理低级技术细节(如“建立TCP连接”)的模块不应放在同一层。
  • 识别横切关注点 (Cross-Cutting Concerns): 有些功能,如日志记录 (Logging)身份验证 (Authentication)缓存 (Caching),是多个层次都需要的。这些模块通常不属于任何一个特定的垂直分层,而是形成一个共享的“基础设施层”或“公共服务层”,被其他所有层调用。

一个简单的判断流程:

  1. 分析功能:确定子模块的主要作用。
  2. 审视依赖:它需要调用哪些其他模块?它被哪些模块调用?
  3. 匹配职责:将其职责与各层的标准职责进行匹配。
  4. 遵守规则:确保它的归属不会破坏单向依赖的规则。

遵循这些原则,你就能构建出一个结构清晰、易于维护和扩展的健壮软件系统。

发表回复