8.3 KiB
8.3 KiB
Internal 包 - CLAUDE.md
此文件为 Claude Code 在 internal 包中工作时提供指导。internal 包包含了应用程序的核心业务逻辑,不对外暴露。
🎯 模块概览
internal 包采用分层架构设计,包含以下核心层次:
- API Layer (
api/): HTTP 接口层,处理请求和响应 - Domain Layer (
domain/): 领域模型层,定义业务实体和规则 - Application Layer (
application/): 应用服务层,编排业务逻辑 - Infrastructure Layer (
infrastructure/): 基础设施层,外部依赖 - Shared Layer (
shared/): 共享工具和常量
📁 目录结构
internal/
├── CLAUDE.md # 🔍 当前文件 - Internal 包指南
├── api/ # 🌐 API 接口层
│ ├── CLAUDE.md # API 层开发指南
│ ├── handlers/ # HTTP 处理器
│ ├── middleware/ # 中间件
│ ├── routes/ # 路由配置
│ └── validators/ # 输入验证
├── domain/ # 🏗️ 领域模型层
│ ├── CLAUDE.md # 领域层开发指南
│ ├── entities/ # 业务实体
│ ├── repositories/ # 仓储接口
│ └── services/ # 领域服务接口
├── application/ # 🔧 应用服务层
│ ├── CLAUDE.md # 应用层开发指南
│ ├── dto/ # 数据传输对象
│ └── services/ # 应用服务实现
├── infrastructure/ # 🏭 基础设施层
│ ├── CLAUDE.md # 基础设施指南
│ ├── config/ # 配置管理
│ ├── database/ # 数据库操作
│ ├── cache/ # 缓存服务
│ ├── storage/ # 文件存储
│ └── repositories/ # 仓储实现
└── shared/ # 🔗 共享组件
├── CLAUDE.md # 共享组件指南
├── constants/ # 常量定义
├── errors/ # 错误处理
└── utils/ # 工具函数
🏗️ 分层架构原则
依赖方向
API Layer ──→ Application Layer ──→ Domain Layer
↓ ↓ ↑
Infrastructure Layer ──────────────────┘
层次职责
1. API Layer (api/)
- 职责: 处理 HTTP 请求和响应
- 依赖: Application Layer
- 不允许: 直接调用 Infrastructure Layer 或包含业务逻辑
2. Application Layer (application/)
- 职责: 编排业务逻辑,协调 Domain Services
- 依赖: Domain Layer
- 不允许: 包含具体的基础设施实现
3. Domain Layer (domain/)
- 职责: 定义业务实体、规则和接口
- 依赖: 无(最核心层)
- 不允许: 依赖外部框架或基础设施
4. Infrastructure Layer (infrastructure/)
- 职责: 实现外部依赖,如数据库、缓存、文件存储
- 依赖: Domain Layer (实现接口)
- 不允许: 包含业务逻辑
5. Shared Layer (shared/)
- 职责: 提供跨层共享的工具和常量
- 依赖: 最小化依赖
- 原则: 保持稳定,避免频繁变更
🔧 开发规范
包导入规则
标准导入顺序
import (
// 1. 标准库
"context"
"fmt"
"time"
// 2. 第三方库
"github.com/gin-gonic/gin"
"gorm.io/gorm"
// 3. 项目内部包 - 按依赖层次
"photography-backend/internal/domain/entities"
"photography-backend/internal/application/dto"
"photography-backend/internal/shared/errors"
)
禁止的依赖
- Domain Layer 不能导入 Infrastructure Layer
- Application Layer 不能导入 API Layer
- 下层不能导入上层
接口设计原则
1. 依赖倒置
// ✅ 正确:在 domain/repositories 定义接口
type UserRepository interface {
FindByID(id uint) (*entities.User, error)
Save(user *entities.User) error
}
// ✅ 在 infrastructure/repositories 实现接口
type userRepository struct {
db *gorm.DB
}
func (r *userRepository) FindByID(id uint) (*entities.User, error) {
// 实现细节
}
2. 接口隔离
// ✅ 正确:小而专注的接口
type UserReader interface {
FindByID(id uint) (*entities.User, error)
FindByEmail(email string) (*entities.User, error)
}
type UserWriter interface {
Save(user *entities.User) error
Delete(id uint) error
}
// ❌ 错误:过大的接口
type UserRepository interface {
// 包含太多方法...
}
错误处理规范
1. 错误传播
// Domain Layer: 定义业务错误
var ErrUserNotFound = errors.New("user not found")
// Application Layer: 处理和转换错误
func (s *UserService) GetUser(id uint) (*dto.UserResponse, error) {
user, err := s.repo.FindByID(id)
if err != nil {
if errors.Is(err, domain.ErrUserNotFound) {
return nil, shared.ErrUserNotFound
}
return nil, fmt.Errorf("failed to get user: %w", err)
}
return s.toDTO(user), nil
}
// API Layer: 转换为 HTTP 响应
func (h *UserHandler) GetUser(c *gin.Context) {
user, err := h.service.GetUser(id)
if err != nil {
response.HandleError(c, err)
return
}
response.Success(c, user)
}
🚀 开发工作流
1. 新功能开发流程
Step 1: Domain Layer
# 1. 定义实体
vim internal/domain/entities/new_entity.go
# 2. 定义仓储接口
vim internal/domain/repositories/new_repository.go
# 3. 定义领域服务接口(如需要)
vim internal/domain/services/new_service.go
Step 2: Application Layer
# 1. 定义 DTO
vim internal/application/dto/request/new_request.go
vim internal/application/dto/response/new_response.go
# 2. 实现应用服务
vim internal/application/services/new_service.go
Step 3: Infrastructure Layer
# 1. 实现仓储
vim internal/infrastructure/repositories/new_repository.go
# 2. 实现其他基础设施(如需要)
Step 4: API Layer
# 1. 实现处理器
vim internal/api/handlers/new_handler.go
# 2. 添加路由
vim internal/api/routes/api_v1.go
# 3. 添加验证器(如需要)
vim internal/api/validators/new_validator.go
2. 测试策略
单元测试
- Domain Layer: 测试业务逻辑
- Application Layer: 测试服务编排
- Infrastructure Layer: 测试数据访问
集成测试
- API Layer: 端到端测试
- Repository Layer: 数据库集成测试
测试隔离
// 使用依赖注入便于测试
type UserService struct {
repo domain.UserRepository
}
// 测试时注入 Mock
func TestUserService_GetUser(t *testing.T) {
mockRepo := &MockUserRepository{}
service := NewUserService(mockRepo)
// 测试逻辑
}
📋 代码审查清单
架构合规性
- 是否遵循分层架构原则
- 是否违反依赖方向
- 接口设计是否合理
- 错误处理是否完善
代码质量
- 命名是否清晰明确
- 函数是否单一职责
- 是否有适当的注释
- 是否有相应的测试
性能考虑
- 是否有 N+1 查询问题
- 是否需要添加缓存
- 数据库操作是否高效
🎯 最佳实践
1. 保持层次清晰
- 每层只关注自己的职责
- 避免跨层直接调用
- 使用接口解耦
2. 依赖注入
- 使用构造函数注入
- 避免全局变量
- 便于测试和替换
3. 错误处理
- 使用带类型的错误
- 适当包装错误信息
- 保持错误处理一致性
4. 性能优化
- 合理使用缓存
- 数据库查询优化
- 避免过度设计
🔍 故障排查
常见问题
- 循环依赖: 检查包导入关系
- 接口未实现: 确认所有方法都已实现
- 依赖注入失败: 检查构造函数和依赖配置
- 测试失败: 确认 Mock 对象配置正确
调试技巧
// 使用结构化日志
logger.Debug("Processing request",
logger.String("handler", "UserHandler.GetUser"),
logger.Uint("user_id", userID),
)
这个架构设计确保了代码的可维护性、可测试性和可扩展性。遵循这些指导原则,可以构建出高质量的后端服务。