forked from datawhale/whale-town-end
7.4 KiB
7.4 KiB
架构重构文档
重构目标
将现有的混合架构重构为清晰的4层架构,实现更好的关注点分离和代码组织。
架构对比
重构前
src/
├── business/auth/ # 混合了Gateway和Business职责
│ ├── login.controller.ts # HTTP协议处理
│ ├── login.service.ts # 业务逻辑
│ ├── jwt_auth.guard.ts # 认证守卫
│ └── dto/ # 数据传输对象
└── core/login_core/ # 核心层
└── login_core.service.ts # 数据访问和基础设施
重构后
src/
├── gateway/auth/ # 网关层(新增)
│ ├── login.controller.ts # HTTP协议处理
│ ├── register.controller.ts # HTTP协议处理
│ ├── jwt_auth.guard.ts # 认证守卫
│ ├── dto/ # 数据传输对象
│ └── auth.gateway.module.ts # 网关模块
├── business/auth/ # 业务层(精简)
│ ├── login.service.ts # 登录业务逻辑
│ ├── register.service.ts # 注册业务逻辑
│ └── auth.module.ts # 业务模块
└── core/login_core/ # 核心层(不变)
└── login_core.service.ts # 数据访问和基础设施
4层架构说明
1. Transport Layer(传输层)- 可选
位置:src/transport/
职责:
- 底层网络通信和连接管理
- WebSocket服务器、TCP/UDP服务器
- 原生Socket连接池管理
说明:对于HTTP应用,NestJS已经提供了传输层,无需额外实现。对于WebSocket等特殊协议,可以在此层实现。
2. Gateway Layer(网关层)
位置:src/gateway/
职责:
- HTTP协议处理和请求响应
- 数据验证(DTO)
- 路由管理
- 认证守卫
- 错误转换(业务错误 → HTTP状态码)
- API文档
原则:
- ✅ 只做协议转换,不做业务逻辑
- ✅ 使用DTO进行数据验证
- ✅ 统一的错误处理
- ❌ 不直接访问数据库
- ❌ 不包含业务规则
示例:
@Controller('auth')
export class LoginController {
constructor(private readonly loginService: LoginService) {}
@Post('login')
async login(@Body() loginDto: LoginDto, @Res() res: Response): Promise<void> {
// 只做协议转换
const result = await this.loginService.login({
identifier: loginDto.identifier,
password: loginDto.password
});
// 转换为HTTP响应
this.handleResponse(result, res);
}
}
3. Business Layer(业务层)
位置:src/business/
职责:
- 业务逻辑实现
- 业务流程控制
- 服务协调
- 业务规则验证
- 事务管理
原则:
- ✅ 实现所有业务逻辑
- ✅ 协调多个Core层服务
- ✅ 返回统一的业务响应
- ❌ 不处理HTTP协议
- ❌ 不直接访问数据库
示例:
@Injectable()
export class LoginService {
async login(loginRequest: LoginRequest): Promise<ApiResponse<LoginResponse>> {
try {
// 1. 调用核心服务进行认证
const authResult = await this.loginCoreService.login(loginRequest);
// 2. 业务逻辑:验证Zulip账号
await this.validateAndUpdateZulipApiKey(authResult.user);
// 3. 生成JWT令牌
const tokenPair = await this.loginCoreService.generateTokenPair(authResult.user);
// 4. 返回业务响应
return {
success: true,
data: { user: this.formatUserInfo(authResult.user), ...tokenPair },
message: '登录成功'
};
} catch (error) {
return {
success: false,
message: error.message,
error_code: 'LOGIN_FAILED'
};
}
}
}
4. Core Layer(核心层)
位置:src/core/
职责:
- 数据访问(数据库、缓存)
- 基础设施(Redis、消息队列)
- 外部系统集成
- 技术实现细节
原则:
- ✅ 提供技术基础设施
- ✅ 数据持久化和缓存
- ✅ 外部API集成
- ❌ 不包含业务逻辑
- ❌ 不处理HTTP协议
数据流向
客户端请求
↓
Gateway Layer (Controller)
↓ 调用
Business Layer (Service)
↓ 调用
Core Layer (Data Access)
↓
数据库/缓存/外部API
依赖关系
Gateway → Business → Core
- Gateway层依赖Business层
- Business层依赖Core层
- Core层不依赖任何业务层
- 依赖方向单向,不允许反向依赖
重构步骤
第一阶段:登录注册模块(已完成)
- ✅ 创建
src/gateway/auth/目录 - ✅ 移动Controller到Gateway层
- ✅ 移动DTO到Gateway层
- ✅ 移动Guard到Gateway层
- ✅ 创建
AuthGatewayModule - ✅ 更新Business层模块,移除Controller
- ✅ 更新
app.module.ts使用新的Gateway模块 - ✅ 创建架构文档
第二阶段:其他业务模块(待进行)
- 重构
location_broadcast模块 - 重构
user_mgmt模块 - 重构
admin模块 - 重构
zulip模块 - 重构
notice模块
第三阶段:WebSocket模块(待进行)
- 创建
src/transport/websocket/ - 实现原生WebSocket服务器
- 创建
src/gateway/location-broadcast/ - 移动WebSocket Gateway到Gateway层
迁移指南
如何判断代码应该放在哪一层?
Gateway层:
- 包含
@Controller()装饰器 - 包含
@Get(),@Post()等HTTP方法装饰器 - 包含
@Body(),@Param(),@Query()等参数装饰器 - 包含DTO类(
class LoginDto) - 包含Guard类(
class JwtAuthGuard)
Business层:
- 包含
@Injectable()装饰器 - 包含业务逻辑方法
- 协调多个服务
- 返回
ApiResponse<T>格式的响应
Core层:
- 包含数据库访问代码
- 包含Redis操作代码
- 包含外部API调用
- 包含技术实现细节
重构Checklist
对于每个模块:
- 识别Controller文件
- 创建对应的Gateway目录
- 移动Controller到Gateway层
- 移动DTO到Gateway层的
dto/目录 - 移动Guard到Gateway层
- 创建Gateway Module
- 更新Business Module,移除Controller
- 更新imports,修正路径
- 更新app.module.ts
- 运行测试确保功能正常
最佳实践
1. 保持层级职责清晰
每一层只做自己职责范围内的事情,不要越界。
2. 使用统一的响应格式
Business层返回统一的ApiResponse<T>格式:
interface ApiResponse<T = any> {
success: boolean;
data?: T;
message: string;
error_code?: string;
}
3. 错误处理分层
- Gateway层:将业务错误转换为HTTP状态码
- Business层:捕获异常并转换为业务错误
- Core层:抛出技术异常
4. 依赖注入
使用NestJS的依赖注入系统,通过Module配置依赖关系。
5. 文档完善
每个层级都应该有README文档说明职责和使用方法。
注意事项
- 渐进式重构:不要一次性重构所有模块,逐个模块进行
- 保持测试:重构后运行测试确保功能正常
- 向后兼容:重构过程中保持API接口不变
- 代码审查:重构代码需要经过代码审查
- 文档更新:及时更新相关文档