Go企业级架构模式Skill golang-enterprise-patterns

本技能提供企业级Go应用程序架构的完整指南,涵盖整洁架构、六边形架构、领域驱动设计(DDD)等核心模式。内容包括分层结构设计、依赖注入、错误处理、配置管理等生产就绪的最佳实践,适用于构建复杂业务逻辑的大型Go项目。关键词:Go语言、企业架构、整洁架构、六边形架构、DDD、依赖注入、代码组织、设计模式、后端开发、微服务。

后端开发 0 次安装 0 次浏览 更新于 2/28/2026

name: golang-enterprise-patterns description: 企业级Go架构模式,包括整洁架构、六边形架构、领域驱动设计(DDD)以及生产就绪的应用结构。 author: Joseph OBrien status: 未发布 updated: ‘2025-12-23’ version: 1.0.1 tag: 技能 type: 技能

Golang 企业级模式

本技能提供关于企业级Go应用程序架构、设计模式和生产就绪代码组织的指导。

何时使用此技能

  • 设计具有复杂业务逻辑的新Go应用程序时
  • 实施整洁架构或六边形架构时
  • 应用领域驱动设计(DDD)原则时
  • 组织大型Go代码库时
  • 建立团队一致性模式时

整洁架构

分层结构

/cmd
  /api           - HTTP/gRPC入口点
  /worker        - 后台作业运行器
/internal
  /domain        - 业务实体和接口
  /application   - 用例和应用服务
  /infrastructure
    /persistence - 数据库实现
    /messaging   - 队列实现
    /http        - HTTP客户端实现
  /interfaces
    /api         - HTTP处理器
    /grpc        - gRPC处理器
/pkg             - 共享库(公共)

依赖规则

依赖关系仅向内流动:

接口 → 应用 → 领域
     ↓            ↓
基础设施(实现领域接口)

领域层

// domain/user.go
package domain

import "time"

type UserID string

type User struct {
    ID        UserID
    Email     字符串
    Name      字符串
    CreatedAt 时间.时间
}

// UserRepository 定义用户持久化的契约
type UserRepository interface {
    FindByID(ctx 上下文.上下文, id UserID) (*User, 错误)
    FindByEmail(ctx 上下文.上下文, email 字符串) (*User, 错误)
    Save(ctx 上下文.上下文, user *User) 错误
    Delete(ctx 上下文.上下文, id UserID) 错误
}

// UserService 定义领域业务逻辑
type UserService interface {
    Register(ctx 上下文.上下文, email, name 字符串) (*User, 错误)
    Authenticate(ctx 上下文.上下文, email, password 字符串) (*User, 错误)
}

应用层

// application/user_service.go
package application

type UserServiceImpl struct {
    repo   领域.UserRepository
    hasher 密码哈希器
    logger 日志记录器
}

func NewUserService(repo 领域.UserRepository, hasher 密码哈希器, logger 日志记录器) *UserServiceImpl {
    return &UserServiceImpl{repo: repo, hasher: hasher, logger: logger}
}

func (s *UserServiceImpl) Register(ctx 上下文.上下文, email, name 字符串) (*领域.User, 错误) {
    // 检查用户是否存在
    existing, err := s.repo.FindByEmail(ctx, email)
    if err != nil && !errors.Is(err, 领域.ErrNotFound) {
        return nil, fmt.Errorf("检查现有用户: %w", err)
    }
    if existing != nil {
        return nil, 领域.ErrUserAlreadyExists
    }

    user := &领域.User{
        ID:        领域.UserID(uuid.New().String()),
        Email:     email,
        Name:      name,
        CreatedAt: 时间.Now(),
    }

    if err := s.repo.Save(ctx, user); err != nil {
        return nil, fmt.Errorf("保存用户: %w", err)
    }

    return user, nil
}

六边形架构(端口与适配器)

端口定义

// ports/primary.go - 驱动端口(输入)
package ports

type UserAPI interface {
    CreateUser(ctx 上下文.上下文, req CreateUserRequest) (*UserResponse, 错误)
    GetUser(ctx 上下文.上下文, id 字符串) (*UserResponse, 错误)
}

// ports/secondary.go - 被驱动端口(输出)
type UserStorage interface {
    Save(ctx 上下文.上下文, user *领域.User) 错误
    FindByID(ctx 上下文.上下文, id 字符串) (*领域.User, 错误)
}

type NotificationSender interface {
    SendWelcomeEmail(ctx 上下文.上下文, user *领域.User) 错误
}

适配器实现

// adapters/postgres/user_repository.go
package postgres

type UserRepository struct {
    db *sql.DB
}

func (r *UserRepository) Save(ctx 上下文.上下文, user *领域.User) 错误 {
    query := `INSERT INTO users (id, email, name, created_at) VALUES ($1, $2, $3, $4)`
    _, err := r.db.ExecContext(ctx, query, user.ID, user.Email, user.Name, user.CreatedAt)
    return err
}

领域驱动设计(DDD)

聚合根

// domain/order/aggregate.go
package order

type Order struct {
    id         订单ID
    customerID 客户ID
    items      []订单项
    status     订单状态
    events     []领域事件
}

func NewOrder(customerID 客户ID) *Order {
    o := &Order{
        id:         订单ID(uuid.New().String()),
        customerID: customerID,
        status:     状态待处理,
    }
    o.recordEvent(订单已创建{订单ID: o.id, 客户ID: customerID})
    return o
}

func (o *Order) AddItem(productID 产品ID, quantity int, price 货币) 错误 {
    if o.status != 状态待处理 {
        return 错误订单不可修改
    }
    o.items = append(o.items, 订单项{
        ProductID: productID,
        Quantity:  quantity,
        Price:     price,
    })
    return nil
}

func (o *Order) Submit() 错误 {
    if len(o.items) == 0 {
        return 错误空订单
    }
    o.status = 状态已提交
    o.recordEvent(订单已提交{订单ID: o.id})
    return nil
}

值对象

// domain/money.go
type Money struct {
    amount   int64  // 分
    currency 字符串
}

func NewMoney(amount int64, currency 字符串) (Money, 错误) {
    if amount < 0 {
        return Money{}, 错误负金额
    }
    return Money{amount: amount, currency: currency}, nil
}

func (m Money) Add(other Money) (Money, 错误) {
    if m.currency != other.currency {
        return Money{}, 错误货币不匹配
    }
    return Money{amount: m.amount + other.amount, currency: m.currency}, nil
}

领域事件

// domain/events.go
type DomainEvent interface {
    EventName() 字符串
    OccurredAt() 时间.时间
}

type OrderCreated struct {
    OrderID    订单ID
    CustomerID 客户ID
    occurredAt 时间.时间
}

func (e OrderCreated) EventName() 字符串    { return "order.created" }
func (e OrderCreated) OccurredAt() 时间.时间 { return e.occurredAt }

依赖注入

Wire风格DI

// wire.go
//+build wireinject

func InitializeApp(cfg *config.Config) (*App, 错误) {
    wire.Build(
        NewDatabase,
        NewUserRepository,
        NewUserService,
        NewHTTPServer,
        NewApp,
    )
    return nil, nil
}

手动DI(推荐用于简单性)

// main.go
func main() {
    cfg := config.Load()

    db := database.Connect(cfg.DatabaseURL)

    userRepo := postgres.NewUserRepository(db)
    orderRepo := postgres.NewOrderRepository(db)

    userService := application.NewUserService(userRepo)
    orderService := application.NewOrderService(orderRepo, userRepo)

    handler := api.NewHandler(userService, orderService)
    server := http.NewServer(cfg.Port, handler)

    server.Run()
}

错误处理模式

自定义错误类型

// domain/errors.go
type Error struct {
    Code    字符串
    Message 字符串
    Err     错误
}

func (e *Error) Error() 字符串 {
    if e.Err != nil {
        return fmt.Sprintf("%s: %s: %v", e.Code, e.Message, e.Err)
    }
    return fmt.Sprintf("%s: %s", e.Code, e.Message)
}

func (e *Error) Unwrap() 错误 { return e.Err }

var (
    ErrNotFound          = &Error{Code: "NOT_FOUND", Message: "资源未找到"}
    ErrUserAlreadyExists = &Error{Code: "USER_EXISTS", Message: "用户已存在"}
    ErrInvalidInput      = &Error{Code: "INVALID_INPUT", Message: "无效输入"}
)

配置管理

// config/config.go
type Config struct {
    Server   服务器配置
    Database 数据库配置
    Redis    Redis配置
}

func Load() (*Config, 错误) {
    cfg := &Config{}

    cfg.Server.Port = getEnvInt("PORT", 8080)
    cfg.Server.ReadTimeout = getEnvDuration("READ_TIMEOUT", 30*时间.Second)

    cfg.Database.URL = mustGetEnv("DATABASE_URL")
    cfg.Database.MaxConns = getEnvInt("DB_MAX_CONNS", 25)

    return cfg, nil
}

最佳实践

  1. 保持领域纯净 - 领域层无框架依赖
  2. 接口隔离 - 小型、专注的接口
  3. 依赖倒置 - 依赖抽象,而非具体实现
  4. 显式依赖 - 通过构造函数传递依赖
  5. 快速失败 - 在边界处验证,信任内部代码
  6. 使非法状态不可表示 - 使用类型强制执行不变量