文章

基于golang的web后端分层策略

基于golang的web后端分层策略

1. 代码架构

  1. 传统三层架构(最主流,80%的项目用这个)

    Handler/Controller → Service → Repository/Model

    优点:

    • 简单直白,傻瓜都能理解
    • 职责清晰:HTTP处理、业务逻辑、数据访问
    • 大多数场景够用

    缺点:

    • Service层容易变成”上帝对象”
    • 贫血模型问题(Model只是数据容器)
  2. Clean Architecture / 六边形架构

    Domain ← Use Cases ← Interface Adapters ← Frameworks

    优点:

    • 业务逻辑完全独立于框架
    • 测试友好
    • “理论完美”

    缺点:

    • 过度工程。一个CRUD要写7层接口和实现
    • 抽象泄漏问题依然存在
    • 大多数团队驾驭不了
  3. DDD四层架构(领域驱动设计)

    Interface → Application → Domain → Infrastructure

    优点:

    • 复杂业务建模能力强
    • 领域模型是核心

    缺点:

    • 学习曲线陡峭
    • 简单项目用它是杀鸡用牛刀
    • 容易被滥用成”名词驱动开发”
  4. 简化两层(适合小项目/微服务)

    Handler → Repository

    优点:

    • 极简,代码量少
    • 微服务单一职责时够用

    缺点:

    • 业务逻辑塞在Handler里,复用性差
    • 一旦复杂就得重构

1.1 主流分层策略选择

主流是三层架构: 1. 团队成员都能理解 2. 复杂度与收益匹配 3. Go生态里gin/echo等框架都默认这个模式

什么时候考虑更复杂的分层?

  • 业务逻辑真的复杂到Service层爆炸
  • 有多个入口(HTTP、gRPC、CLI、定时任务)共享业务逻辑
  • 需要严格的领域隔离

1.1.1 三层架构

1.1.1.1 各个层次的边界
该做的事不该做的事
Handler解析参数、校验格式、调用Service、封装响应业务判断、数据库操作、调用多个Service编排流程
Service业务逻辑、权限判断、流程编排、事务控制知道HTTP状态码、解析JSON、拼接URL
Repository/Model数据存取业务规则
1.1.1.2 service用途
  1. service是做完整的业务逻辑,还是只做部分业务逻辑,最终由handler组织,形成完整业务逻辑? 答: 核心原则:写代码时问自己:如果明天要加个gRPC/命令行/定时任务入口,这段逻辑要重写吗?
1.1.1.3 权限验证放哪?

认证(Authentication):你是谁? → 放在中间件/Handler

授权(Authorization):你能干什么? → 放在Service

1.1.1.4 service是否设计成从context获取认证用户信息?

二者都行,但更倾向于调用者信息需要作为参数显示传给service方法,Go社区更偏向显式传参

  • 从ctx获取调用者信息,方便且行为统一,但是由于是从ctx动态获取,有时会有一些隐藏的Bug
  • 调用者信息作为参数,更清晰,但是很多方法都需要重复传参

作为参数,更适合分层隔离:

1
2
3
4
5
  gin.Context (HTTP层)  ←  存 AuthInfo,Handler 专用
       ↓ 取出
     Handler
       ↓ 显式传参
     Service (业务层)  ←  不知道 HTTP 层的存在

Service 层只接收 context.Context(标准库的),它:

  • 不知道 gin.Context
  • 不知道 AuthInfo 从哪来(可能是 HTTP session,可能是 gRPC,可能是测试代码直接构造)
1.1.1.5 API传参风格

RESTful:路径标识资源,body传数据,对于后端有两种参数,一种是路径参数,一种是请求体参数 RPC风格:全JSON body,更像调函数 GraphQL:单端点 + 查询语言

建议风格: 混合RPC风格:

  • 查询接口:GET + Query参数
  • 操作接口:POST + JSON Body
  • 路径不带资源ID,参数统一放Query或Body 这种风格对于查询的接口能方便浏览器直接打开

1.2 DDD四层架构

1.2.1 领域模型(Domain)

Domain = 业务领域

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
              Domain
                 ↓
      ┌──────────┼──────────┐
      ↓          ↓          ↓
  Subdomain  Subdomain  Subdomain
      ↓          ↓          ↓
   Bounded   Bounded    Bounded
   Context   Context    Context
      ↓
      ├── Entity(有ID,有行为)
      ├── Value Object(无ID,不可变)
      ├── Aggregate(实体的组合,事务边界)
      ├── Domain Service(跨实体逻辑)
      ├── Repository(存取接口)
      └── Domain Event(发生了什么)

1.2.2 贫血与充血

贫血/充血是针对Model层的

| 术语 | 指的是 | Model的样子 | |———-|—————————|————-| | 贫血模型 | Model层只有数据,没有行为 | 纯数据结构 | | 充血模型 | Model层包含业务逻辑 | 数据 + 方法 |

1.2.3 实体(Entity)与值对象(Value Object)

区分Entity和Value Object,本质是区分一个对象是否有生命周期

Entity = 有生命周期(创建 → 变化 → 销毁) Value Object = 没有生命周期,创建后不能再增删改查的对象

实际影响

  1. 表结构设计 不区分时的困惑:”地址要不要单独建张表?要不要给它加ID?” 案例:用户的地址管理,应该建表 用户订单的地址,那是值对象,无法修改,也不应该修改,注意这里的修改是指值对象本身无法被修改,但实际上,有业务需求时,可以直接对整个值对象进行替换(实现下单后改地址)
  2. 要不要跟踪历史 Entity:通常需要跟踪
    • 一个订单从创建到关闭经历了什么?

2. 一些初学者的困惑

  1. MVC、MVVM和之前提到的三层架构是一个维度的事物吗? 不是,MVC/MVVM是给”有UI交互的地方”用的。 MVC、MVVM更多用于界面怎么渲染、数据怎么绑定、交互怎么响应 前后端分离后,MVC这些概念基本归到前端/客户端领域了

  2. 理清一些概念(DDD、三层架构、MVC)

层级软件建筑军事
方法论DDD建筑哲学战略思想
架构模式三层架构结构设计战役部署
设计模式MVC房间布局战术动作
  1. 为什么DDD是指导思想,那在代码架构那还有DDD四层架构呢

DDD实际上包含两部分:

1
2
3
4
5
6
7
  DDD
  ├── 思想层面(方法论)
  │   ├── 战略设计:怎么划分领域、限界上下文
  │   └── 战术设计:实体、值对象、聚合怎么建模
  │
  └── 落地层面(分层策略)
      └── DDD推荐的四层架构 
  1. 这里提到的”架构”和”架构师” 里的”架构”, 概念上有什么不同?

这里讨论的只是”架构”的一小部分。

架构的层次:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
  ┌─────────────────────────────────────────────────────────────┐
  │                      企业架构                                │
  │               业务架构、数据架构、技术架构                      │
  ├─────────────────────────────────────────────────────────────┤
  │                      系统架构                                │
  │          服务怎么拆分、怎么通信、怎么部署                       │
  ├─────────────────────────────────────────────────────────────┤
  │                      应用架构                                │
  │              单个应用内部怎么组织代码                          │
  │      ┌─────────────────────────────────────────┐            │
  │      │                                         │            │
  │      │    三层架构、DDD分层、六边形架构            │            │
  │      └─────────────────────────────────────────┘            │
  └─────────────────────────────────────────────────────────────┘

架构师关心什么

| 层面 | 关心的问题 | 举例 | | —- | ———- | —————– | | 业务架构 | 业务流程怎么设计 | 订单流程、支付流程 | | 系统架构 | 服务怎么拆、怎么通信 | 微服务划分、API网关 | | 技术架构 | 用什么技术栈 | MySQL还是PostgreSQL | | 部署架构 | 怎么部署、怎么扩容 | K8s、负载均衡、多机房 | | 数据架构 | 数据怎么存、怎么流转 | 分库分表、数据仓库 | | 安全架构 | 怎么保证安全 | 认证、加密、防攻击 | | 应用架构 | 代码怎么分层组织 | 三层架构、DDD✅ |

术语定义

术语是否标准含义
Transaction Script✅ 是逻辑在Controller/Handler
Service Layer✅ 是独立的服务层
Anemic Model(贫血)✅ 是Model无行为,逻辑在Service
Rich Model(充血)✅ 是Model包含业务逻辑
Application Service✅ 是(DDD)用例编排
Domain Service✅ 是(DDD)领域逻辑
本文由作者按照 CC BY 4.0 进行授权