6.4 代码组织与分层约定
代码组织与分层约定
一眼看懂的目录
dwz-server/
├── main.go # 入口,嵌入 static/templates,调用 cmd.Start()
├── cmd/run.go # 装配 Assembly + Server,启动服务
├── config/
│ ├── assembly.go # DI 装配顺序
│ ├── server.go # 服务启动顺序
│ └── autoload/ # 路由、依赖提供者
│ └── router.go # 所有路由集中注册
├── app/
│ ├── controller/ # HTTP 请求处理
│ ├── service/ # 业务逻辑
│ ├── dao/ # GORM 数据访问
│ ├── model/ # GORM 实体
│ ├── dto/ # 请求/响应 DTO
│ ├── middleware/ # 认证、CORS、操作日志、安装校验
│ └── constants/ # 业务常量
├── internal/
│ ├── helper/ # 全局 Helper(DI 容器)
│ ├── interfaces/ # 接口定义(依赖倒置)
│ └── pkg/ # 缓存、数据库、http_server 实现
├── pkg/helper/ # 通用工具函数
├── templates/ # 嵌入式 HTML 模板
├── static/ # 嵌入式后台静态资源
└── docs/ # 仓库内 Markdown 文档分层职责
| 层 | 职责 | 不应该做的事 |
|---|---|---|
| Controller | 解析/校验请求参数、调用 Service、组装响应 | 直接访问数据库;写业务规则 |
| Service | 业务逻辑、事务边界、跨 DAO 组合 | 解析 HTTP 参数;直接写 SQL |
| DAO | GORM 查询封装、数据持久化 | 业务判断;调用其他 Service |
| Model | GORM 实体与其方法(如 IsExpired()) |
持有业务状态;调用 DAO |
| DTO | 请求/响应结构,独立于 Model | 持有业务逻辑 |
| Middleware | 横切关注点:认证、日志、CORS | 具体业务处理 |
依赖方向
Controller → Service → DAO → Model
↓ ↓ ↓
DTO Helper GORM/DB不要反向依赖。如果发现 DAO 需要调用 Service,通常意味着业务逻辑放错了层。
Helper 与依赖注入
全局依赖(logger、config、cache、database)通过 internal/helper/helper.go 暴露,任何层都可以调用:
import "cnb.cool/mliev/dwz/dwz-server/internal/helper"
func SomeBusinessFunc() {
logger := helper.GetLogger()
db := helper.GetDatabase()
cfg := helper.GetConfig()
// ...
}Controller 层通过 deps *impl.HttpDeps 接收额外的 HTTP 依赖:
func (c MyController) Handler(ctx *gin.Context, deps *impl.HttpDeps) {
svc := deps.GetShortLinkService()
// ...
}命名约定
- 包名:小写单数,
controller/service/dao(遵循 Go 惯例) - 文件名:功能名下划线,
short_link_controller.go - 结构体:大驼峰,
ShortLinkController - 方法:大驼峰;DTO 字段 JSON tag 使用下划线命名
- 错误:返回
error,不要panic