基于golang的web后端分层策略
1. 代码架构
传统三层架构(最主流,80%的项目用这个)
Handler/Controller → Service → Repository/Model
优点:
- 简单直白,傻瓜都能理解
- 职责清晰:HTTP处理、业务逻辑、数据访问
- 大多数场景够用
缺点:
- Service层容易变成”上帝对象”
- 贫血模型问题(Model只是数据容器)
Clean Architecture / 六边形架构
Domain ← Use Cases ← Interface Adapters ← Frameworks
优点:
- 业务逻辑完全独立于框架
- 测试友好
- “理论完美”
缺点:
- 过度工程。一个CRUD要写7层接口和实现
- 抽象泄漏问题依然存在
- 大多数团队驾驭不了
DDD四层架构(领域驱动设计)
Interface → Application → Domain → Infrastructure
优点:
- 复杂业务建模能力强
- 领域模型是核心
缺点:
- 学习曲线陡峭
- 简单项目用它是杀鸡用牛刀
- 容易被滥用成”名词驱动开发”
简化两层(适合小项目/微服务)
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用途
- 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 = 没有生命周期,创建后不能再增删改查的对象
实际影响
- 表结构设计 不区分时的困惑:”地址要不要单独建张表?要不要给它加ID?” 案例:用户的地址管理,应该建表 用户订单的地址,那是值对象,无法修改,也不应该修改,注意这里的修改是指值对象本身无法被修改,但实际上,有业务需求时,可以直接对整个值对象进行替换(实现下单后改地址)
- 要不要跟踪历史 Entity:通常需要跟踪
- 一个订单从创建到关闭经历了什么?
2. 一些初学者的困惑
MVC、MVVM和之前提到的三层架构是一个维度的事物吗? 不是,MVC/MVVM是给”有UI交互的地方”用的。 MVC、MVVM更多用于界面怎么渲染、数据怎么绑定、交互怎么响应 前后端分离后,MVC这些概念基本归到前端/客户端领域了
理清一些概念(DDD、三层架构、MVC)
| 层级 | 软件 | 建筑 | 军事 |
|---|---|---|---|
| 方法论 | DDD | 建筑哲学 | 战略思想 |
| 架构模式 | 三层架构 | 结构设计 | 战役部署 |
| 设计模式 | MVC | 房间布局 | 战术动作 |
- 为什么DDD是指导思想,那在代码架构那还有DDD四层架构呢
DDD实际上包含两部分:
1
2
3
4
5
6
7
DDD
├── 思想层面(方法论)
│ ├── 战略设计:怎么划分领域、限界上下文
│ └── 战术设计:实体、值对象、聚合怎么建模
│
└── 落地层面(分层策略)
└── DDD推荐的四层架构
- 这里提到的”架构”和”架构师” 里的”架构”, 概念上有什么不同?
这里讨论的只是”架构”的一小部分。
架构的层次:
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) | 领域逻辑 |