Agent skill · software engineering · affaan-m

hexagonal-architecture

设计、实现并重构端口与适配器系统,具有清晰的领域边界、依赖反转以及跨 TypeScript、Java、Kotlin 和 Go 服务的可测试用例编排。

Why this skill is useful

Provides specific patterns for implementing hexagonal architecture in TypeScript, including domain models and use case orchestration that the AI may not generate on its own.

What it needs

About 2k tokens when loaded. Last updated 2026-08-06. 238,342 stars on the source repository.

What this skill does

六边形架构 六边形架构(端口与适配器)使业务逻辑独立于框架、传输层和持久化细节。核心应用依赖于抽象端口,而适配器在边缘实现这些端口。 适用场景 构建需要长期可维护性和可测试性的新功能。 重构分层或框架密集型代码,其中领域逻辑与I/O关注点混杂。 为同一用例支持多种接口(HTTP、CLI、队列工作器、定时任务)。 替换基础设施(数据库、外部API、消息总线)而无需重写业务规则。 当需求涉及边界、领域驱动设计、重构紧耦合服务,或将应用逻辑与特定库解耦时,使用此技能。 核心概念 领域模型:业务规则和实体/值对象。无框架导入。 用例(应用层):编排领域行为和工作流步骤。 入站端口:描述应用能力的契约(命令/查询/用例接口)。 出站端口:应用所需依赖的契约(仓库、网关、事件发布器、时钟、UUID等)。 适配器:端口的基础设施和交付实现(HTTP控制器、数据库仓库、队列消费者、SDK封装器)。 组合根:将具体适配器绑定到用例的单一连接位置。 出站端口接口通常位于应用层(仅当抽象真正属于领域层时才位于领域层),而基础设施适配器实现它们。 依赖方向始终向内: 适配器 -> 应用/领域 应用 -> 端口接口(入站/出站契约) 领域 -> 仅领域抽象(无框架或基础设施依赖) 领域 -> 无外部依赖 工作原理 步骤1:建模用例边界 定义具有清晰输入和输出DTO的单个用例。将传输细节(Express req、GraphQL context、任务负载包装器)保持在此边界之外。 步骤2:首先定义出站端口 将每个副作用识别为端口: 持久化(UserRepositoryPort) 外部调用(BillingGatewayPort) 横切关注点(LoggerPort、ClockPort) 端口应建模能力,而非技术。 步骤3:使用纯编排实现用例 用例类/函数通过构造函数/参数接收端口。它验证应用层不变量,协调领域规则,并返回纯数据结构。 步骤4:在边缘构建适配器 入站适配器将协议输入转换为用例输入。 出站适配器将应用契约映射到具体API/ORM/查询构建器。 映射保持在适配器中,而非用例内部。 步骤5:在组合根中连接所有组件 实例化适配器,然后将其注入用例。保持此连接集中化,以避免隐藏的服务定位器行为。 步骤6:按边界测试 使用伪造端口对用例进行单元测试。 使用真实基础设施依赖对适配器进行集成测试。 通过入站适配器对面向用户的流程进行端到端测试。 架构图 建议的模块布局 使用以功能为先的组织方式,并带有显式边界: TypeScript 示例 端口定义 用例 出站适配器 组合根 多语言映射 在不同生态系统中使用相同的边界规则;仅语法和连接方式发生变化。 TypeScript/JavaScript 端口:application/ports/ 作为接口/类型。 用例:带有构造函数/参数注入的类/函数。 适配器:adapters/inbound/、adapters/outbound/。 组合:显式工厂/容器模块(无隐藏全局变量)。 Java 包:domain、application.port.in、application.port.out、application.usecase、adapter.in、adapter.out。 端口:application.port. 中的接口。 用例:普通类(Spring @Service 是可选的,非必需)。 组合:Spring配置或手动连接类;将连接逻辑保持在领域/用例类之外。 Kotlin 模块/包镜像Java的拆分(domain、application.port、application.usecase、adapter)。 端口:Kotlin接口。 用例:带有构造函数注入的类(Koin/Dagger/Spring/手动)。 组合:模块定义或专用组合函数;避免服务定位器模式。 Go 包:internal/<feature>/domain、application、ports、adapters/inbound、adapters/outbound。 端口:由消费应用包拥有的小型接口。 用例:带有接口字段和显式 New... 构造函数的结构体。 组合:在 cmd/<app>/main.go 中连接(或专用连接包),保持构造函数显式。 应避免的反模式 领域实体导入ORM模型、Web框架类型或SDK客户端。 用例直接从 req、res 或队列元数据读取。 从用例直接返回数据库行,未经领域/应用映射。 让适配器直接相互调用,而非通过用例端口流转。 将依赖连接分散到多个文件中,使用隐藏的全局单例。 迁移手册 1. 选择一个垂直切片(单个端点/任务),该切片频繁变更且带来痛苦。 2. 提取具有显式输入/输出类型的用例边界。 3. …

How to use it

Reference it in AdaL, Claude Code, Cursor or any coding agent — nothing to install:

@skills affaan-m/hexagonal-architecture--f3da16

View the source on GitHub

Browse the @skills marketplace