mcpField
C
clean-architecture

clean-architecture

github.com/wondelai开发2.5k7.3k 次安装7 周前更新
代码仓库

关于 clean-architecture

面向软件架构设计、评审和依赖管理的框架,主张代码依赖向业务规则内侧指向。内容涵盖分层边界、组件原则与 SOLID,帮助隔离业务逻辑和外部细节。

主要功能

  1. 01依赖规则与同心分层
  2. 02实体与用例建模
  3. 03接口适配器与框架边界
  4. 04组件内聚与耦合原则
  5. 05SOLID 原则
  6. 06架构诊断与评分

适用场景

  1. 01规划新系统的模块边界
  2. 02检查业务逻辑对框架或数据库的依赖
  3. 03定位组件依赖循环
  4. 04评审类与模块的 SOLID 问题

安装

复制下面的命令,在终端中运行。

$npx skills add https://github.com/wondelai/skills --skill clean-architecture

安装后在 Claude Code 中输入/clean-architecture确认已加载。

包含的文件

除 SKILL.md 外,安装时一起下载的参考资料和脚本。

references/
adapters-frameworks.md
boundaries.md
component-principles.md
dependency-rule.md
entities-use-cases.md
solid-principles.md

详细介绍

整洁架构框架

一种有纪律的软件结构组织方法,确保业务规则独立于框架、数据库和交付机制。在设计系统架构、审查模块边界或提供依赖管理建议时,应用这些原则。

核心原则

**源代码依赖必须指向内层,也就是更高层的策略。**内层中的任何内容都不能了解外层中的任何内容。仅这一条规则,就能构建出可测试且独立于框架、UI、数据库和任何外部机构的系统。业务规则才是关键;数据库、Web 框架和交付机制都只是细节——当细节依赖策略时,你就可以推迟决策、替换实现,并隔离测试业务逻辑。

评分

**目标:10/10。**架构满足“快速诊断”表中七行中的每一行即可得 1 分(0-7 分),然后映射到 0-10 分区间:满足 6-7 行 = 9-10(依赖规则成立,业务逻辑独立于框架和数据库);满足 4-5 行 = 6-8(核心可测试,但有些细节渗入内层);满足 2-3 行 = 3-5(框架或持久化方式决定结构);满足 0-1 行 = 0-2(没有边界——业务规则存在于控制器和 ORM 模型中)。报告分数、未通过的诊断项,以及修复每一项所需的具体依赖反转。

1. 依赖规则与同心圆

**核心概念:**将架构组织为同心圆——最内层是实体(企业业务规则),然后是用例(应用业务规则),再到接口适配器,最外层是框架和驱动程序。源代码依赖始终指向内层。

**有效原因:**当高层策略不依赖底层细节时,你可以替换数据库、Web 框架或 API 风格,而无需改动业务逻辑——系统因此能够抵御技术栈中最易变化的部分。

关键要点:

  • 内层不能提及外层的名称——不得使用外部的类、函数、变量或数据格式
  • 跨越边界的数据必须采用最便于内层使用的形式,不能由外层决定
  • 依赖反转(在内层定义接口,在外层实现)是确保规则得以遵守的机制
  • 圆的数量并不固定——通常为四个;规则始终不变
  • 框架只是细节,而非架构——它们属于最外层

代码应用:

场景模式示例
层级方向内层定义接口;外层实现用例中定义 UserRepository 接口;适配器中实现 PostgresUserRepository
数据跨层DTO 跨越边界,而非 ORM 实体用例返回 UserResponse DTO,而非 ActiveRecord 模型
依赖方向导入箭头始终指向内层控制器导入用例;用例绝不导入控制器

当内层的导入指向外层,且你需要查看四层代码演练、数据跨层规则以及修复问题的四步依赖反转流程时,请参阅 references/dependency-rule.md。

2. 实体与用例

核心概念: 实体封装企业级业务规则——即使没有软件,这些规则也依然存在。用例包含应用专属规则,用于编排数据与实体之间的流转。

有效原因: 将业务要做什么(实体)与应用如何编排(用例)分离,可让你在多个应用中复用实体,并在不改变核心业务规则的情况下调整应用行为。

要点:

  • 实体不是数据库行,而是封装关键业务规则的对象或纯函数
  • 用例接收请求模型并返回响应模型——绝不接收框架对象
  • 每个用例都对应一项独立的应用操作(CreateOrder、ApproveExpense)
  • 交互器模式:用例类实现输入边界接口,并调用输出边界接口
  • 用例变更不应影响实体;实体变更则可能影响用例

代码应用:

上下文模式示例
实体设计关键业务规则,不依赖任何框架Order.calculateTotal() 应用税务规则;不涉及 HTTP
请求/响应简单的数据结构跨越边界CreateOrderRequest { items, customerId }——不使用 ORM 模型
单一职责每项操作对应一个用例将 PlaceOrder、CancelOrder、RefundOrder 分别实现为独立类
交互器实现输入端口并调用输出端口PlaceOrderInteractor implements PlaceOrderInput

设计交互器,或判断某项内容应属于实体还是用例时,请参阅 references/entities-use-cases.md——其中全面讲解了企业级与应用级业务规则,并提供了请求/响应模型示例。

3. 接口适配器与框架

核心概念: 接口适配器负责在适用于用例/实体的形式与外部系统所需的形式之间转换数据。框架和驱动程序位于最外层——它们是连接外部世界的胶水代码。

有效原因: 将 Web 框架、ORM 或消息队列限制在外层,替换其中任何一项都只需局部修改。数据库是细节;Web 是细节;细节应作为业务规则的插件,而非应用的骨架。

要点:

  • 控制器将 HTTP 转换为用例输入;表示器将用例输出转换为视图模型
  • 网关实现由用例定义的仓储接口——内层定义契约,外层负责履行
  • 业务规则无需知道数据存储在 SQL、NoSQL 还是平面文件中,也无需知道数据通过 HTTP 传递
  • 对框架保持警惕——框架会诱使你与其紧密耦合;应与它保持距离

代码应用:

上下文模式示例
控制器传递机制 → 用例输入OrderController.create(req) 构建 CreateOrderRequest,并调用交互器
表示器用例输出 → 视图模型OrderPresenter.present(response) 将内容格式化为 JSON/HTML
网关根据数据库实现仓储接口SqlOrderRepository implements OrderRepository
框架边界框架调用内层,绝不反向调用Express 路由处理程序调用控制器;控制器绝不导入 Express

接线控制器、表示器或网关,或论证数据库/Web 是细节时,请参阅 references/adapters-frameworks.md——其中介绍了插件架构,以及如何将框架限制在边缘。

4. 组件原则

核心概念: 组件是部署的基本单位。三个内聚原则决定组件包含什么,三个耦合原则决定组件之间的关系。

为何有效: 组件划分不当会产生连锁反应,一个更改就可能迫使你重新部署无关代码;这些原则能让更改局部化,让发布彼此独立。

关键要点:

  • REP(复用/发布等同原则):组件中的类必须能够作为一个整体进行版本管理和发布
  • CCP(共同闭包原则):因相同原因、在相同时间更改的类应归在一起——这是组件层面的 SRP
  • CRP(共同复用原则):不要强迫用户依赖他们不会使用的类
  • ADP(无环依赖原则):组件图中不能有环——通过 DIP 或新建组件来打破循环
  • SDP(稳定依赖原则):沿着稳定性递增的方向依赖
  • SAP(稳定抽象原则):稳定的组件应当是抽象的,不稳定的组件应当是具体的

代码应用:

场景模式示例
组件分组将同时更改的类归为一组(CCP)将所有与订单相关的用例放在一个组件中
打破循环应用 DIP 反转依赖边将接口提取到新组件中以打破循环
稳定性度量不稳定性 I = Ce / (Ca + Ce)入向依赖多、没有出向依赖 → I 接近 0(稳定)

在将类分组为可部署组件或打破依赖循环时,请参阅 references/component-principles.md——其中通过不稳定性指标逐一讲解了 REP、CCP、CRP、ADP、SDP 和 SAP。

5. SOLID 原则

核心概念: 五项类和模块级原则——单一职责、开闭、里氏替换、接口隔离和依赖反转——是实现依赖规则的中层构建块。

为何有效: 每项原则都针对一种特定的依赖错误方式,避免代码库陷入僵化、脆弱和难以迁移的困境,沦为令人头疼的遗留系统。

关键要点:

  • SRP:模块只有一个更改理由——它服务于一个角色(而不是“只做一件事”)
  • OCP:通过添加新代码来扩展行为,而不是修改现有代码——策略模式和插件模式
  • LSP:子类型必须能通过基类接口使用,且客户端无需知情——意外抛出异常或忽略方法都会违反此原则
  • ISP:客户端不应依赖它们不会使用的方法——臃肿的接口会造成不必要的耦合
  • DIP:高层模块和底层模块都依赖由高层模块定义的抽象

代码应用:

场景模式示例
SRP 违规类服务于多个角色Employee 负责薪酬(CFO)、报告(COO)和持久化(CTO)
通过策略实现 OCP通过新类添加新行为添加实现 ShippingStrategy 的 ExpressShipping;Order 不变
LSP 违规子类型改变预期行为Square extends Rectangle 破坏了 setWidth()/setHeight() 契约
应用 ISP将臃肿的接口拆分为角色接口使用 Printer、Scanner、Fax,而不是一个 MultiFunctionDevice
DIP 接线高层定义接口;底层实现接口OrderService 依赖 PaymentGateway,而不是 StripeClient

在对特定类应用 SRP/OCP/LSP/ISP/DIP 或诊断违规问题时,请参阅 references/solid-principles.md——其中通过代码示例逐一讲解了各项原则及其预防的问题气味。

6. 边界与边界剖析

核心概念: 边界是重要事物与细节之间的分界线,通过多态实现:依赖向内跨越边界,而控制流可以双向跨越。

为何有效: 每个边界都带来推迟决策或替换实现的可能;边界的战略性布局决定了一个系统在多年维护过程中是令人愉悦还是令人头疼。

关键见解:

  • 完整边界在两侧都使用相互对应的接口;部分边界则采用更简单的策略或外观模式
  • 谦逊对象模式:将边界代码拆分为难以测试的部分(靠近边界)和易于测试的部分(逻辑)
  • 服务并不自动构成架构边界——拥有臃肿共享数据模型的微服务,只是通过网络调用的单体
  • 测试是隔离程度最高的组件:它们依赖内部,且没有任何组件依赖它们
  • 过早设立边界代价高昂,但缺少边界也一样——应在可能发生变化的位置划定边界

代码应用:

上下文模式示例
完整边界与部分边界相互对应的端口,或单独的策略用例定义 PlaceOrderInput/PlaceOrderOutput;更简单的情况采用 ShippingStrategy
谦逊对象将可测试逻辑与基础设施分离PresenterLogic(可测试)生成 ViewModel;View(谦逊对象)负责渲染
Main 作为插件组合根组装系统main() 连接所有具体实现并启动应用

在决定在哪里划定边界、选择完整边界还是部分边界,或应用谦逊对象模式时,请参阅 references/boundaries.md——其中还介绍了作为边界的服务、测试边界,以及作为终极插件的 Main。

常见错误

错误失败原因修正方法
ORM 渗入业务逻辑实体与数据库架构耦合;数据库变更会导致重写业务规则将领域实体与持久化模型分离;在适配器层进行映射
在控制器中编写业务规则脱离 HTTP 就无法测试;多个端点间出现重复逻辑将逻辑移入用例交互器;控制器只负责转换和委派
框架优先的架构框架决定系统结构;替换框架意味着重写将框架视为插件;按业务能力组织代码
组件间循环依赖变更会不可预测地扩散;无法独立发布应用依赖倒置原则(DIP),或提取共享抽象组件
每个功能只设一个庞大的用例协调器膨胀到数千行拆分为专注于单一操作的用例
“因为简单”而跳过边界耦合会悄然累积,直到代价高得惊人主动在可能发生变化的位置划定边界
把微服务视为天然的优秀架构分布式单体比整洁的单体更糟糕在服务内部和服务之间应用依赖规则;服务是部署边界,而非架构边界

快速诊断

问题如果否操作
能否在不使用数据库、Web 服务器或框架的情况下测试业务规则?规则与基础设施耦合将实体和用例提取到接口后;模拟外层
所有源代码依赖是否都指向内层?违反依赖规则引入边界接口;反转有问题的依赖
能否在不触及业务逻辑的情况下更换数据库?持久化细节泄漏到内层使用仓储模式;在适配器中隔离持久化
用例是否独立于交付机制?用例依赖 HTTP/CLI/队列在用例签名中使用普通 DTO
框架是否仅限于最外层?框架就是你的架构在接口后封装框架调用;将其推到边界
组件图是否无环?存在循环依赖应用 ADP:使用 DIP 或新增组件打破所有循环
Main(组合根)是否负责连接所有依赖?在内层实例化了具体类将构造移至 Main;使用 DI 或工厂

延伸阅读

根据 Robert C. Martin 关于软件架构的权威指南:

关于作者

Robert C. Martin(“Uncle Bob”) 是一位自 1970 年起从事编程的软件工程师,是《敏捷宣言》的创始签署人之一,也是 Clean Code、The Clean Coder、Clean Architecture 和 Clean Agile 的作者。他提出的 SOLID 原则是面向对象设计的基础术语,而他的作品主张,架构关乎管理依赖关系,并让业务规则独立于基础设施细节。

评论

支持 Markdown