npx skills add https://github.com/wondelai/skills --skill clean-architecture一种结构化的软件构建方法,旨在使业务规则独立于框架、数据库和交付机制。在设计系统架构、审查模块边界或提供依赖管理建议时,应用这些原则。
源代码依赖必须指向内部——指向更高层次的策略。 内层中的任何东西都不能知道外层中的任何东西。这一条规则,如果始终如一地应用,将产生可测试、独立于框架、独立于用户界面、独立于数据库以及独立于任何外部机构的系统。
基础: 软件架构是关于划清界限——边界——将重要的事物与细节分开。业务规则是重要的。数据库、Web框架和交付机制是细节。当细节依赖于策略(而不是相反)时,你可以推迟决策、交换实现,并独立测试业务逻辑。
目标:10/10。 在审查或创建软件架构时,根据对以下原则的遵守程度,给出0-10的评分。10/10表示完全符合所有准则;较低的分数表示需要解决的差距。始终提供当前分数以及达到10/10所需的具体改进措施。
构建能够经受时间考验的系统的六项原则:
核心概念: 架构被组织为同心圆。最内层包含实体(企业业务规则)。下一层包含用例(应用业务规则)。然后是接口适配器。最外层包含框架和驱动程序。源代码依赖始终指向内部。
为何有效: 当高层策略不依赖于低层细节时,你可以将数据库从MySQL更换为MongoDB,交换Web框架,或用GraphQL替换REST API——所有这些都不需要触及业务逻辑。系统对技术栈中最易变的部分变得具有弹性。
关键见解:
代码应用:
| 上下文 | 模式 | 示例 |
|---|---|---|
广告位招租
在这里展示您的产品或服务
触达数万 AI 开发者,精准高效
| 内层定义接口;外层实现它们 |
用例中的 UserRepository 接口;适配器中的 PostgresUserRepository |
| 数据跨越 | DTO或简单结构体跨越边界,而非ORM实体 | 用例返回 UserResponse DTO,而非ActiveRecord模型 |
| 框架隔离 | 将框架调用包装在接口后面 | EmailSender 接口隐藏你使用的是SendGrid还是SES |
| 数据库独立性 | 仓储模式抽象持久化 | 业务逻辑调用 repo.save(user),而非原始SQL |
| 依赖方向 | 图表上的导入箭头始终指向内部 | 控制器导入用例;用例从不导入控制器 |
核心概念: 实体封装了企业范围的业务规则——最通用、最高级别的规则,即使没有软件系统存在,这些规则也会存在。用例包含特定于应用程序的业务规则,编排进出实体的数据流。
为何有效: 通过将业务做什么(实体)与应用程序如何编排它(用例)分开,你可以在多个应用程序中重用实体,并在不改变核心业务规则的情况下更改应用程序行为。
关键见解:
CreateOrder、ApproveExpense)代码应用:
| 上下文 | 模式 | 示例 |
|---|---|---|
| 实体设计 | 封装关键业务规则,无框架依赖 | Order.calculateTotal() 应用税收规则;对HTTP一无所知 |
| 用例边界 | 定义输入端口和输出端口接口 | CreateOrderInput 接口;CreateOrderOutput 接口 |
| 请求/响应 | 简单的数据结构跨越边界 | CreateOrderRequest { items, customerId } —— 无ORM模型 |
| 单一职责 | 每个应用操作一个用例 | PlaceOrder、CancelOrder、RefundOrder 作为单独的类 |
| 交互器 | 用例类实现输入端口,调用输出端口 | PlaceOrderInteractor implements PlaceOrderInput |
核心概念: 接口适配器将数据在最方便用例和实体的格式与外部机构(数据库、Web、设备)所需的格式之间进行转换。框架和驱动程序是最外层——连接到外部世界的粘合代码。
为何有效: 当Web框架、ORM或消息队列被限制在最外层时,替换它们中的任何一个都变成了局部更改。数据库是细节。Web是细节。框架是细节。细节应该是你业务规则的插件,而不是你应用程序的骨架。
关键见解:
代码应用:
| 上下文 | 模式 | 示例 |
|---|---|---|
| 控制器 | 将交付机制转换为用例输入 | OrderController.create(req) 构建 CreateOrderRequest 并调用交互器 |
| 展示器 | 将用例输出转换为视图模型 | OrderPresenter.present(response) 为JSON/HTML格式化数据 |
| 网关 | 使用特定数据库实现仓储接口 | SqlOrderRepository implements OrderRepository |
| 框架边界 | 框架代码向内调用,绝不被内层调用 | Express路由处理器调用控制器;控制器从不导入Express |
| 插件架构 | 主组件在启动时装配依赖 | main() 实例化具体类并注入它们 |
核心概念: 组件是部署单元。三个内聚原则管理组件内部的内容;三个耦合原则管理组件之间的关系。它们共同决定了系统的可发布性、可维护性和稳定性。
为何有效: 组合不当的组件会产生连锁反应:一次更改迫使重新部署不相关的代码。内聚和耦合原则提供了一种系统化的方式来分组类和管理组件间依赖关系,从而使更改保持局部化。
关键见解:
代码应用:
| 上下文 | 模式 | 示例 |
|---|---|---|
| 组件分组 | 将一起更改的类分组(CCP) | 所有与订单相关的用例放在一个组件中 |
| 打破循环 | 应用DIP来反转依赖边 | 将接口提取到新组件中以打破循环依赖 |
| 稳定性指标 | 测量不稳定性:I = Ce / (Ca + Ce) | 一个有许多传入依赖且无传出依赖的组件,I接近0(稳定) |
| 抽象度平衡 | 稳定的组件应主要包含接口 | 核心领域组件是抽象的;适配器组件是具体的 |
| 发布粒度 | 独立地对组件进行版本控制和发布 | 发布 order-domain v2.1.0 而不触及 payment-adapter |
核心概念: 在类和模块级别管理依赖关系的五项原则:单一职责原则(SRP)、开闭原则(OCP)、里氏替换原则(LSP)、接口隔离原则(ISP)和依赖倒置原则(DIP)。它们是使依赖规则成为可能的中级构建块。
为何有效: SOLID原则保持源代码的灵活性、可理解性和易于更改。它们防止了使代码库变成遗留噩梦的僵化性、脆弱性和不可移动性。每个原则都解决了依赖关系可能出错的特定方式。
关键见解:
代码应用:
| 上下文 | 模式 | 示例 |
|---|---|---|
| SRP 违反 | 类服务于多个参与者 | Employee 处理薪资计算(CFO)、报告(COO)和持久化(CTO) |
| 通过策略实现 OCP | 通过新类实现新行为,而非编辑 | 添加实现 ShippingStrategy 的 ExpressShipping 类,无需更改 Order |
| LSP 违反 | 子类型改变了预期行为 | Square extends Rectangle 破坏了 setWidth()/setHeight() 契约 |
| ISP 应用 | 将臃肿接口拆分为角色接口 | Printer、Scanner、Fax 而非一个 MultiFunctionDevice |
| DIP 装配 | 高层定义接口;低层实现 | OrderService 依赖于 PaymentGateway 接口,而非 StripeClient |
核心概念: 边界是在重要事物与细节事物之间划出的一条线。边界通过多态性实现:源代码依赖跨越边界指向内部,而控制流可能向任一方向跨越。谦卑对象模式使边界处的代码可测试。
为何有效: 你划定的每一个边界都给你提供了推迟决策或交换实现的选择。边界将易变的与稳定的分开,将具体的与抽象的分离。早期和战略性的边界放置决定了系统在多年维护中是令人愉悦还是痛苦。
关键见解:
代码应用:
| 上下文 | 模式 | 示例 |
|---|---|---|
| 完整边界 | 两侧都有输入/输出端口接口 | 用例同时定义 PlaceOrderInput 和 PlaceOrderOutput |
| 部分边界 | 没有完整互惠接口的策略或外观模式 | ShippingCalculator 接受一个 ShippingStrategy —— 比完整端口更简单 |
| 谦卑对象 | 将可测试逻辑与难以测试的基础设施分离 | PresenterLogic(可测试)产生 ViewModel;View(谦卑)渲染它 |
| 主组件作为插件 | 组合根装配系统 | main() 装配所有具体实现并启动应用程序 |
| 测试边界 | 测试依赖于源代码;源代码从不依赖于测试 | 测试导入 PlaceOrderInteractor;生产代码从不导入测试代码 |
| 错误 | 为何失败 | 修复方法 |
|---|---|---|
| 让 ORM 泄漏到业务逻辑中 | 实体变得与数据库模式耦合;更改数据库意味着重写业务规则 | 将领域实体与持久化模型分离;在适配器层映射它们 |
| 将业务规则放在控制器中 | 逻辑在没有启动HTTP的情况下变得不可测试;跨端点重复 | 将所有业务逻辑移入用例交互器;控制器仅负责转换和委托 |
| 框架优先架构 | 框架决定文件夹结构和依赖流;交换框架意味着重写 | 将框架视为最外层的插件;按业务能力组织代码 |
| 组件间的循环依赖 | 更改不可预测地传播;无法独立发布 | 应用DIP打破循环或提取共享抽象组件 |
| 每个功能一个巨型用例 | 用例变成臃肿的编排器,有数千行代码 | 拆分为具有单一应用操作的专注用例 |
| 跳过边界“因为它很简单” | 耦合悄然累积;当你需要边界时,代价巨大 | 在可能易变的点上主动划定边界 |
| 将微服务视为自动的良好架构 | 具有共享数据库和紧密耦合的分布式单体比结构良好的单体更糟糕 | 在服务内部和跨服务应用依赖规则;服务是部署边界,而非架构边界 |
| 问题 | 如果答案为“否” | 行动 |
|---|---|---|
| 你能在没有数据库、Web服务器或框架的情况下测试业务规则吗? | 业务规则与基础设施耦合 | 将实体和用例提取到接口后面;模拟外层 |
| 每个导入的源代码依赖都指向内部吗? | 违反了依赖规则 | 在边界处引入接口;反转违规的依赖 |
| 你能在不改变业务逻辑的情况下更换数据库吗? | 持久化泄漏到内部 | 实现仓储模式;将持久化隔离在适配器中 |
| 用例独立于交付机制吗? | 用例了解HTTP、CLI或消息队列 | 从用例签名中移除交付特定类型;使用纯DTO |
| 框架被限制在最外层吗? | 框架是你的架构而非细节 | 将框架调用包装在接口后面;将框架代码推到边缘 |
| 你能识别组件依赖图并确认它没有循环吗? | 存在循环依赖 | 应用ADP:使用DIP或提取新组件来打破每个循环 |
| 主组件(或组合根)装配所有依赖吗? | 具体类在内层实例化 | 将所有构造逻辑移到主组件;使用依赖注入或工厂 |
此技能基于 Robert C. Martin 关于软件架构的权威指南。如需包含详细示例和案例研究的完整方法论:
Robert C. Martin ("Uncle Bob") 是一位软件工程师、作家,也是敏捷宣言的创始签署人之一。他自1970年以来一直从事编程工作,并为世界各地的开发团队提供咨询和培训。Martin 是《代码整洁之道》、《程序员的职业素养》、《整洁架构》和《整洁敏捷》等书的作者。他是 Uncle Bob Consulting LLC 和 cleancoder.com 的创始人。他的 SOLID 原则已成为面向对象设计中的基础词汇,他倡导软件开发中的工匠精神和纪律性影响了几代程序员。Martin 的工作一贯主张软件架构是关于管理依赖关系、划定边界以及保持业务规则独立于交付机制和基础设施细节。
每周安装量
253
代码仓库
GitHub 星标数
260
首次出现
2026年2月23日
安全审计
安装于
codex243
cursor243
opencode243
gemini-cli242
kimi-cli242
github-copilot242
A disciplined approach to structuring software so that business rules remain independent of frameworks, databases, and delivery mechanisms. Apply these principles when designing system architecture, reviewing module boundaries, or advising on dependency management.
Source code dependencies must point inward -- toward higher-level policies. Nothing in an inner circle can know anything about something in an outer circle. This single rule, applied consistently, produces systems that are testable, independent of frameworks, independent of the UI, independent of the database, and independent of any external agency.
The foundation: Software architecture is about drawing lines -- boundaries -- that separate things that matter from things that are details. Business rules are what matter. Databases, web frameworks, and delivery mechanisms are details. When details depend on policies (not the other way around), you can defer decisions, swap implementations, and test business logic in isolation.
Goal: 10/10. When reviewing or creating software architecture, rate it 0-10 based on adherence to the principles below. A 10/10 means full alignment with all guidelines; lower scores indicate gaps to address. Always provide the current score and specific improvements needed to reach 10/10.
Six principles for building systems that survive the passage of time:
Core concept: The architecture is organized as concentric circles. The innermost circle contains Entities (enterprise business rules). The next circle contains Use Cases (application business rules). Then Interface Adapters. The outermost circle contains Frameworks and Drivers. Source code dependencies always point inward.
Why it works: When high-level policies don't depend on low-level details, you can change the database from MySQL to MongoDB, swap a web framework, or replace a REST API with GraphQL -- all without touching business logic. The system becomes resilient to the most volatile parts of the technology stack.
Key insights:
Code applications:
| Context | Pattern | Example |
|---|---|---|
| Layer direction | Inner circles define interfaces; outer circles implement them | UserRepository interface in Use Cases; PostgresUserRepository in Adapters |
| Data crossing | DTOs or simple structs cross boundaries, not ORM entities | Use Case returns UserResponse DTO, not an ActiveRecord model |
| Framework isolation | Wrap framework calls behind interfaces | EmailSender interface hides whether you use SendGrid or SES |
| Database independence | Repository pattern abstracts persistence |
See: references/dependency-rule.md
Core concept: Entities encapsulate enterprise-wide business rules -- the most general, highest-level rules that would exist even if no software system existed. Use Cases contain application-specific business rules that orchestrate the flow of data to and from Entities.
Why it works: By separating what the business does (Entities) from how the application orchestrates it (Use Cases), you can reuse Entities across multiple applications and change application behavior without altering core business rules.
Key insights:
CreateOrder, ApproveExpense)Code applications:
| Context | Pattern | Example |
|---|---|---|
| Entity design | Encapsulate critical business rules with no framework dependencies | Order.calculateTotal() applies tax rules; knows nothing about HTTP |
| Use Case boundary | Define Input Port and Output Port interfaces | CreateOrderInput interface; CreateOrderOutput interface |
| Request/Response | Simple data structures cross the boundary | CreateOrderRequest { items, customerId } -- no ORM models |
| Single responsibility | One Use Case per application operation |
See: references/entities-use-cases.md
Core concept: Interface Adapters convert data between the format most convenient for Use Cases and Entities and the format required by external agencies (database, web, devices). Frameworks and Drivers are the outermost layer -- glue code that connects to the outside world.
Why it works: When the web framework, ORM, or message queue is confined to the outermost circles, replacing any of them becomes a localized change. The database is a detail. The web is a detail. The framework is a detail. Details should be plugins to your business rules, not the skeleton of your application.
Key insights:
Code applications:
| Context | Pattern | Example |
|---|---|---|
| Controller | Translates delivery mechanism to Use Case input | OrderController.create(req) builds CreateOrderRequest and calls Interactor |
| Presenter | Translates Use Case output to view model | OrderPresenter.present(response) formats data for JSON/HTML |
| Gateway | Implements repository interface using a specific DB | SqlOrderRepository implements OrderRepository |
| Framework boundary | Framework code calls inward, never called by inner circles |
See: references/adapters-frameworks.md
Core concept: Components are the units of deployment. Three cohesion principles govern what goes inside a component; three coupling principles govern relationships between components. Together they determine a system's releasability, maintainability, and stability.
Why it works: Poorly composed components create ripple effects: one change forces redeployment of unrelated code. The cohesion and coupling principles provide a systematic way to group classes and manage inter-component dependencies so that changes remain localized.
Key insights:
Code applications:
| Context | Pattern | Example |
|---|---|---|
| Component grouping | Group classes that change together (CCP) | All order-related Use Cases in one component |
| Breaking cycles | Apply DIP to invert a dependency edge | Extract an interface into a new component to break a circular dependency |
| Stability metrics | Measure instability: I = Ce / (Ca + Ce) | A component with many incoming and no outgoing deps has I near 0 (stable) |
| Abstractness balance | Stable components should contain mostly interfaces | Core domain component is abstract; adapter component is concrete |
| Release granularity | Version and release components independently | order-domain v2.1.0 released without touching payment-adapter |
See: references/component-principles.md
Core concept: Five principles for managing dependencies at the class and module level: Single Responsibility (SRP), Open-Closed (OCP), Liskov Substitution (LSP), Interface Segregation (ISP), and Dependency Inversion (DIP). They are the mid-level building blocks that make the Dependency Rule possible.
Why it works: SOLID principles keep source code flexible, understandable, and amenable to change. They prevent the rigidity, fragility, and immobility that turn codebases into legacy nightmares. Each principle addresses a specific way that dependencies can go wrong.
Key insights:
Code applications:
| Context | Pattern | Example |
|---|---|---|
| SRP violation | Class serves multiple actors | Employee handles pay calculation (CFO), reporting (COO), and persistence (CTO) |
| OCP via strategy | New behavior through new classes, not edits | Add ExpressShipping class implementing ShippingStrategy, no changes to Order |
| LSP violation | Subtype changes expected behavior | Square extends Rectangle breaks setWidth()/ contract |
See: references/solid-principles.md
Core concept: A boundary is a line drawn between things that matter and things that are details. Boundaries are implemented through polymorphism: source code dependencies cross the boundary pointing inward, while the flow of control may cross in either direction. The Humble Object pattern makes code at boundaries testable.
Why it works: Every boundary you draw gives you the option to defer a decision or swap an implementation. Boundaries separate the volatile from the stable, the concrete from the abstract. Early and strategic boundary placement determines whether a system is a joy or a pain to maintain over years.
Key insights:
Code applications:
| Context | Pattern | Example |
|---|---|---|
| Full boundary | Input/Output port interfaces on both sides | Use Case defines both PlaceOrderInput and PlaceOrderOutput |
| Partial boundary | Strategy or Facade without full reciprocal interfaces | ShippingCalculator accepts a ShippingStrategy -- simpler than full ports |
| Humble Object | Separate testable logic from hard-to-test infrastructure | PresenterLogic (testable) produces ViewModel; (humble) renders it |
| Mistake | Why It Fails | Fix |
|---|---|---|
| Letting the ORM leak into business logic | Entities become coupled to the database schema; changing the DB means rewriting business rules | Separate domain entities from persistence models; map between them at the adapter layer |
| Putting business rules in controllers | Logic becomes untestable without spinning up HTTP; duplication across endpoints | Move all business logic into Use Case Interactors; controllers only translate and delegate |
| Framework-first architecture | The framework dictates folder structure and dependency flow; swapping frameworks means a rewrite | Treat the framework as a plugin in the outermost circle; structure code by business capability |
| Circular dependencies between components | Changes ripple unpredictably; impossible to release independently | Apply DIP to break cycles or extract a shared abstraction component |
| One giant Use Case per feature | Use Cases become bloated orchestrators with thousands of lines | Split into focused Use Cases with single application operations |
| Skipping boundaries "because it's simple" |
| Question | If No | Action |
|---|---|---|
| Can you test business rules without a database, web server, or framework? | Business rules are coupled to infrastructure | Extract entities and use cases behind interfaces; mock the outer layers |
| Do source code dependencies point inward on every import? | The Dependency Rule is violated | Introduce interfaces at the boundary; invert the offending dependency |
| Can you swap the database without changing business logic? | Persistence is leaking inward | Implement the Repository pattern; isolate persistence in adapters |
| Are Use Cases independent of the delivery mechanism? | Use Cases know about HTTP, CLI, or message queues | Remove delivery-specific types from Use Case signatures; use plain DTOs |
| Is the framework confined to the outermost circle? | The framework is your architecture instead of a detail | Wrap framework calls behind interfaces; push framework code to the edges |
| Can you identify the component dependency graph and confirm it has no cycles? | Circular dependencies exist | Apply ADP: use DIP or extract new components to break every cycle |
| Does Main (or the composition root) wire all dependencies? | Concrete classes are instantiated in inner circles |
This skill is based on Robert C. Martin's definitive guide to software architecture. For the complete methodology with detailed examples and case studies:
Robert C. Martin ("Uncle Bob") is a software engineer, author, and one of the founding signatories of the Agile Manifesto. He has been programming since 1970 and has consulted for and trained development teams worldwide. Martin is the author of Clean Code , The Clean Coder , Clean Architecture , and Clean Agile , among other books. He is the founder of Uncle Bob Consulting LLC and cleancoder.com. His SOLID principles have become foundational vocabulary in object-oriented design, and his advocacy for craftsmanship and discipline in software development has influenced generations of programmers. Martin's work consistently argues that software architecture is about managing dependencies, drawing boundaries, and keeping business rules independent of delivery mechanisms and infrastructure details.
Weekly Installs
253
Repository
GitHub Stars
260
First Seen
Feb 23, 2026
Security Audits
Gen Agent Trust HubPassSocketPassSnykPass
Installed on
codex243
cursor243
opencode243
gemini-cli242
kimi-cli242
github-copilot242
AI代理协作核心原则:提升开发效率的6大Agentic开发原则指南
7,600 周安装
Business logic calls repo.save(user), never raw SQL |
| Dependency direction | Import arrows on a diagram always point inward | Controller imports Use Case; Use Case never imports Controller |
PlaceOrder, CancelOrder, RefundOrder as separate classes |
| Interactor | Use Case class implements Input Port, calls Output Port | PlaceOrderInteractor implements PlaceOrderInput |
| Express route handler calls Controller; Controller never imports Express |
| Plugin architecture | Main component wires dependencies at startup | main() instantiates concrete classes and injects them |
setHeight()| ISP application | Split fat interfaces into role interfaces | Printer, Scanner, Fax instead of one MultiFunctionDevice |
| DIP wiring | High-level defines interface; low-level implements | OrderService depends on PaymentGateway interface, not StripeClient |
View| Main as plugin | Composition root assembles the system | main() wires all concrete implementations and starts the app |
| Test boundary | Tests depend on source; source never depends on tests | Test imports PlaceOrderInteractor; production code never imports test code |
| Coupling accumulates silently; by the time you need a boundary, the cost is enormous |
| Draw boundaries proactively at points of likely volatility |
| Treating microservices as automatic good architecture | A distributed monolith with shared databases and tight coupling is worse than a well-structured monolith | Apply the Dependency Rule within and across services; services are deployment boundaries, not architectural ones |
| Move all construction logic to Main; use dependency injection or factories |