Go与六边形架构:编写不怕修改的代码

面向初学者的在线Python训练器

轻松学习Python,无需理论负担。在浏览器中直接解决带自动检查的实践任务,无需安装任何东西。

开始课程

认识一下:与外部世界隔离的代码

\n\n

您是否曾因为将数据库从PostgreSQL更换为MongoDB而重写业务逻辑?或者半夜惊醒,只因想到需要添加新的HTTP端点,而整个应用就是一个3000行的巨型main.go文件?

\n\n

如果是——欢迎加入我们的行列。如果不是——要么您刚接触Go不久,要么您已经在使用六边形架构(也称为端口与适配器)。

\n\n

本文将探讨如何构建一个不惧变化的Go应用。无论是更换数据库、从REST迁移到gRPC,还是引入新框架,都无需重写系统核心。只有代码。只有Go。没有废话。

\n\n

通俗理解六边形架构

\n\n

把您的应用想象成宇宙飞船。中心是驾驶舱(业务逻辑)。周围是对接端口。通过端口连接不同模块:引擎(数据库)、传感器(HTTP请求)、与地球的通信(消息队列)。

\n\n

如果您决定更换引擎——只需断开旧的,连接新的。驾驶舱甚至不会察觉到更换。这就是六边形架构。

\n\n

核心概念:

\n
    \n
  • 端口——定义外部世界如何与核心交互的接口。例如,包含Save和FindByID方法的UserRepository。
  • \n
  • 适配器——端口的具体实现。一个端口可以有多个适配器:PostgreSQLAdapter、InMemoryAdapter、用于测试的MockAdapter。
  • \n
  • 核心——对外部世界一无所知的业务逻辑。它仅通过端口工作。
  • \n
\n\n

这种方法带来三大超能力:可测试性(无需数据库即可测试核心)、灵活性(可替换任何组件)、清晰的职责边界。

\n\n

为什么Go是六边形架构的理想选择

\n\n

Go不强制使用面向对象编程,但提供了接口——这正是端口与适配器所需的唯一特性。Go的接口是隐式的:只要结构体实现了接口的方法,就自动满足该接口。这意味着您可以在不修改核心任何代码的情况下替换适配器。

\n\n

此外,Go编译为二进制文件,使该架构对微服务特别有用。内置的测试和基准测试功能让您可以立即验证组件的隔离性。

\n\n

项目结构:如何组织文件夹

\n\n

虽然没有统一标准,但以下是生产项目中经过验证的方案:

\n\n
myapp/\n├── cmd/\n│   └── app/\n│       └── main.go          # 入口点,依赖组装\n├── internal/\n│   ├── core/\n│   │   ├── domain/          # 实体,值对象\n│   │   ├── ports/           # 接口(端口)\n│   │   └── services/        # 业务逻辑(用例)\n│   └── adapters/\n│       ├── api/             # HTTP/gRPC适配器\n│       ├── db/              # 仓库实现\n│       └── mq/              # 消息队列\n└── go.mod\n
\n\n

重要提示:internal文件夹禁止外部导入——非常适合保护核心。适配器独立存放,便于替换。

\n\n

编写代码:从接口到实现

\n\n

让我们创建一个简单的用户管理服务。从核心开始。

\n\n

步骤1. 领域与端口

\n\n
// internal/core/domain/user.go\npackage domain\n\nimport "time"\n\ntype User struct {\n    ID        string\n    Email     string\n    Name      string\n    CreatedAt time.Time\n}\n\n// internal/core/ports/repositories.go\npackage ports\n\nimport "myapp/internal/core/domain"\n\ntype UserRepository interface {\n    Save(user domain.User) error\n    FindByID(id string) (domain.User, error)\n    FindByEmail(email string) (domain.User, error)\                

博客

书籍推荐