11 KiB
11 KiB
认证服务重构说明
重构目标
根据DDD(领域驱动设计)原则,重新划分认证服务的应用层和领域层职责,提高代码的解耦性和可维护性。
重构前后对比
重构前的问题
- 职责混乱:应用服务层直接操作仓库,违反了分层架构原则
- 业务逻辑分散:认证相关的业务逻辑分散在应用服务中,难以维护
- 耦合度高:应用服务与具体的数据访问技术耦合
- 可测试性差:业务逻辑与基础设施代码混合,难以进行单元测试
重构后的改进
- 职责清晰:应用层专注业务流程编排,领域层专注业务逻辑
- 高内聚低耦合:按业务功能模块划分领域服务
- 易于测试:业务逻辑独立,可以独立进行单元测试
- 易于扩展:新增业务功能时,只需要在相应的领域服务中添加方法
新的架构设计
1. 应用服务层 (Application Layer)
职责:
- 业务流程编排和协调
- 事务管理
- 数据转换(DTO ↔ 领域对象)
- 调用领域服务
- 不直接操作仓库
主要方法:
type CertificationApplicationService interface {
// 认证状态查询
GetCertificationStatus(ctx context.Context, query *queries.GetCertificationStatusQuery) (*responses.CertificationResponse, error)
GetCertificationDetails(ctx context.Context, query *queries.GetCertificationDetailsQuery) (*responses.CertificationResponse, error)
GetCertificationProgress(ctx context.Context, userID string) (map[string]interface{}, error)
// 企业信息管理
SubmitEnterpriseInfo(ctx context.Context, cmd *commands.SubmitEnterpriseInfoCommand) (*responses.EnterpriseInfoResponse, error)
// 企业认证
EnterpriseVerify(ctx context.Context, userID string) (*responses.CertificationResponse, error)
// 合同管理
ApplyContract(ctx context.Context, userID string) (*responses.CertificationResponse, error)
CompleteContractSign(ctx context.Context, certificationID, contractURL string) error
}
2. 领域服务层 (Domain Layer)
2.1 认证管理服务 (CertificationManagementService)
职责:
- 认证申请的生命周期管理
- 认证申请的创建、查询
- 认证进度信息获取
主要方法:
type CertificationManagementService struct {
certRepo repositories.CertificationRepository
stateMachine *CertificationStateMachine
logger *zap.Logger
}
// 主要方法
- CreateCertification(ctx context.Context, userID string) (*entities.Certification, error)
- GetCertificationByUserID(ctx context.Context, userID string) (*entities.Certification, error)
- GetCertificationByID(ctx context.Context, certificationID string) (*entities.Certification, error)
- GetCertificationProgress(ctx context.Context, certificationID string) (map[string]interface{}, error)
2.2 认证工作流服务 (CertificationWorkflowService)
职责:
- 认证流程的状态转换
- 业务规则验证
- 状态机操作
主要方法:
type CertificationWorkflowService struct {
certRepo repositories.CertificationRepository
stateMachine *CertificationStateMachine
logger *zap.Logger
}
// 主要方法
- SubmitEnterpriseInfo(ctx context.Context, certificationID string) error
- CompleteEnterpriseVerification(ctx context.Context, certificationID string) error
- ApplyContract(ctx context.Context, certificationID string) error
- CompleteContractSign(ctx context.Context, certificationID, contractURL string) error
- CompleteCertification(ctx context.Context, certificationID string) error
2.3 企业信息服务 (EnterpriseService)
职责:
- 企业信息的创建、更新、查询
- 企业信息验证状态管理
- 企业认证流程
主要方法:
type EnterpriseService struct {
userRepo repositories.UserRepository
enterpriseInfoRepo repositories.EnterpriseInfoRepository
logger *zap.Logger
}
// 主要方法
- CreateEnterpriseInfo(ctx context.Context, userID, companyName, unifiedSocialCode, legalPersonName, legalPersonID string) (*entities.EnterpriseInfo, error)
- GetEnterpriseInfo(ctx context.Context, userID string) (*entities.EnterpriseInfo, error)
- UpdateOCRVerification(ctx context.Context, userID string, isVerified bool, rawData string, confidence float64) error
- UpdateFaceVerification(ctx context.Context, userID string, isVerified bool) error
- CheckUnifiedSocialCodeExists(ctx context.Context, unifiedSocialCode, excludeUserID string) (bool, error)
业务流程示例
提交企业信息流程
// 应用服务层 - 业务流程编排
func (s *CertificationApplicationServiceImpl) SubmitEnterpriseInfo(ctx context.Context, cmd *commands.SubmitEnterpriseInfoCommand) (*responses.EnterpriseInfoResponse, error) {
// 1. 验证企业信息(检查统一社会信用代码是否已存在)
exists, err := s.enterpriseService.CheckUnifiedSocialCodeExists(ctx, cmd.UnifiedSocialCode, "")
if err != nil {
return nil, fmt.Errorf("检查企业信息失败: %w", err)
}
if exists {
return nil, fmt.Errorf("统一社会信用代码已存在")
}
// 2. 获取或创建认证申请
certification, err := s.certManagementService.GetCertificationByUserID(ctx, cmd.UserID)
if err != nil {
// 如果认证申请不存在,自动创建
if err.Error() == "认证申请不存在" || err.Error() == "record not found" {
certification, err = s.certManagementService.CreateCertification(ctx, cmd.UserID)
if err != nil {
return nil, fmt.Errorf("创建认证申请失败: %w", err)
}
} else {
return nil, fmt.Errorf("获取认证申请失败: %w", err)
}
}
// 3. 提交企业信息(状态转换)
if err := s.certWorkflowService.SubmitEnterpriseInfo(ctx, certification.ID); err != nil {
return nil, err
}
// 4. 创建企业信息
enterpriseInfo, err := s.enterpriseService.CreateEnterpriseInfo(ctx, cmd.UserID, cmd.CompanyName, cmd.UnifiedSocialCode, cmd.LegalPersonName, cmd.LegalPersonID)
if err != nil {
return nil, err
}
return s.buildEnterpriseInfoResponse(enterpriseInfo), nil
}
企业认证流程
// 应用服务层 - 业务流程编排
func (s *CertificationApplicationServiceImpl) EnterpriseVerify(ctx context.Context, userID string) (*responses.CertificationResponse, error) {
// 1. 获取认证申请
certification, err := s.certManagementService.GetCertificationByUserID(ctx, userID)
if err != nil {
return nil, fmt.Errorf("用户尚未创建认证申请: %w", err)
}
// 2. 完成企业认证(状态转换)
if err := s.certWorkflowService.CompleteEnterpriseVerification(ctx, certification.ID); err != nil {
return nil, err
}
// 3. 更新企业信息验证状态(模拟OCR和人脸识别验证)
if err := s.enterpriseService.UpdateOCRVerification(ctx, userID, true, "OCR验证通过", 0.95); err != nil {
s.logger.Warn("更新OCR验证状态失败", zap.Error(err))
}
if err := s.enterpriseService.UpdateFaceVerification(ctx, userID, true); err != nil {
s.logger.Warn("更新人脸识别验证状态失败", zap.Error(err))
}
// 4. 重新获取更新后的认证申请
updatedCertification, err := s.certManagementService.GetCertificationByID(ctx, certification.ID)
if err != nil {
return nil, err
}
return s.buildCertificationResponse(updatedCertification), nil
}
依赖注入配置
领域服务注册
// 领域服务
fx.Provide(
user_service.NewUserService,
user_service.NewSMSCodeService,
user_service.NewEnterpriseService,
certification_service.NewCertificationManagementService, // 新增
certification_service.NewCertificationWorkflowService, // 新增
certification_service.NewCertificationStateMachine,
finance_service.NewFinanceService,
product_service.NewProductService,
),
应用服务注册
// 应用服务
fx.Annotate(
certification.NewCertificationApplicationService,
fx.As(new(certification.CertificationApplicationService)),
),
重构收益
1. 代码质量提升
- 单一职责原则:每个服务都有明确的职责范围
- 开闭原则:新增功能时不需要修改现有代码
- 依赖倒置原则:高层模块不依赖低层模块,都依赖抽象
2. 可维护性提升
- 业务逻辑集中:相关的业务逻辑集中在对应的领域服务中
- 易于理解:代码结构清晰,新人容易理解
- 易于调试:问题定位更容易,调试更简单
3. 可测试性提升
- 单元测试:每个领域服务可以独立进行单元测试
- 集成测试:应用服务层可以独立进行集成测试
- 模拟测试:可以轻松模拟依赖的服务
4. 可扩展性提升
- 新增功能:只需要在相应的领域服务中添加方法
- 修改功能:修改影响范围小,不会影响其他模块
- 替换实现:可以轻松替换某个服务的实现
最佳实践
1. 应用服务层设计原则
- 业务流程编排:专注于业务流程的编排和协调
- 事务管理:负责事务的边界和一致性
- 数据转换:负责DTO和领域对象之间的转换
- 错误处理:统一处理业务异常和系统异常
2. 领域服务层设计原则
- 业务功能模块化:按业务功能划分服务
- 单一职责:每个服务只负责一个业务领域
- 高内聚:相关的业务逻辑集中在一起
- 低耦合:服务之间通过接口进行交互
3. 命名规范
- 应用服务:
XxxApplicationService - 领域服务:
XxxManagementService、XxxWorkflowService、XxxService - 方法命名:使用动词+名词的形式,如
CreateCertification、SubmitEnterpriseInfo
4. 错误处理
- 业务异常:在领域服务中抛出业务异常
- 系统异常:在应用服务中处理系统异常
- 错误信息:使用中文错误信息,提高用户体验
总结
通过这次重构,我们实现了:
- 清晰的职责划分:应用层专注业务流程编排,领域层专注业务逻辑
- 高内聚低耦合:按业务功能模块划分服务,降低模块间耦合
- 易于测试:业务逻辑独立,可以独立进行单元测试
- 易于维护:代码结构清晰,新人容易理解和维护
- 易于扩展:新增功能时影响范围小,不会影响其他模块
这种架构设计符合DDD原则,为后续的功能扩展和维护奠定了良好的基础。