框架设计原则

1、跟当前请求无关操作,不应该使用context

  • client对context的滥用:
// 初始化
service.Init(
    micro.WrapHandler(
      NewWrapperBuilder(service).
      WithStatus().
      WithUser().
      WithPush().
      WithIM()
    ),
)

// 用法
statuSrv := client.StatusFromContext(ctx) // 有可能没初始化,出现nil
sessionRsp, err := statuSrv.GetSession(ctx, &pb.GetSessionReq{Token: token})
// 用法繁琐,而已不能用于 定时任务 和 broker的异步处理

// 合理用法,单例模式,动态初始化
statuSrv := meet.StatusService() // 不需要用ctx
sessionRsp, err := statuSrv.GetSession(ctx, &pb.GetSessionReq{Token: token})
  • log对context不优雅用法:
// 不合理用法
oLog := log.FormContext(ctx)
oLog.Info("log")   // 可能会报错,oLog有可能是nil

// 合理用法
xlog.Info(ctx, "log")  // 优先记录到ctx,其次输出到控制台
  • context合理用途:
    • 标识用户身份的session
    • 请求Header信息,metadata
    • 请求相关的日志,xlog、xio
    • 数据库事务 ——曾经有个版本,用了全局变量引起互相影响的错误,=_=!!

2、尽量用单例模式,简化代码

// 冗余用法
func main() {
  conf := config.NewConfig()
  uploader := provideUploader(conf, "/general/UploadCallback")
}

func provideUploader(conf config) {
  curl := conf.Get("file_url_prefix").String("") + "/" + req.HeifPath
}

// 后来改为:
func provideUploader() {
  curl := xconfig.GetInstance().Get("file_url_prefix").String("") + "/" + req.HeifPath
}

// 再后来改为:
func provideUploader() {
  curl := xconfig.GetString("file_url_prefix") + "/" + req.HeifPath
}

3、可以panic的错误,尽早panic

问题:

  • 底层的error,逐层冒泡,每一层都要加 if err != nil {}的处理
  • 出现错误,逐层返回,到最顶层时,已经获取不到 错误堆栈

    改造方案:

  • 可panic的错误,及时panic
  • 外层增加全局的recover()处理,并获取堆栈,方便定位问题

    改造例子:

// 调用方要处理err
func getOnlineUserIDs2(ctx context.Context, uids []int64) ([]int64, error) {
  ret, err := meet.StatusService().GetChannelOnline(ctx, &pb2.GetChannelOnlineReq{
    UserIDs: uids,
  })

  // 这里返回了err
  if err != nil {
    return nil, err
  }

    return ret, nil
}

// 改造后的方法,不返回error
func getOnlineUserIDs(ctx context.Context, uids []int64) []int64 {
  ret, err := meet.StatusService().GetChannelOnline(ctx, &pb2.GetChannelOnlineReq{
    UserIDs: uids,
  })

  // 如果err不为nil,直接Panic
  global.AssertError(err)

  return ret
}

4、可不用的interface,没必要过早定义

问题:

  • 之前的dao层,定义了interface,造成 每次接口修改,都要修改两处
  • review代码,定位方法多了一层,部分IDE查找实现比较麻烦

解决:

  • 直接删除interface定义

5、自定义包名,命名时尽量不跟 框架/系统 包名一样

问题:

  • 大量重复,IDE提示不友好,例如:client、log 跟大量库包名一样

解决:

  • 加前缀 =》xclient、xlog
Copyright © xinyan all right reserved,powered by Gitbook该文件修订时间: 2020-07-27 21:03:51

results matching ""

    No results matching ""