优化if···else
我们在工作中经常会写出如下代码
       if (xxx != null) {
           if (xxx != null) {
               if (xxx != null) {
                   
              }
              ....
          }
      }
看起来也没什么问题。但是当if···else层数变多,将会越来越难以阅读,逐步形成‘屎’代码
if (xxx == null) {
	return;
}
// 原来if()逻辑
if 逻辑中的代码过多,可以考虑封装对应的子方法,来解决层数问题
方法相关
每个方法有每个方法的职责,不要在方法中增加额外的逻辑,例如
public void xxx() {
   // 业务逻辑
   xxx.setXxx();
   // 业务逻辑
   xxx.setXxx();
   // 业务逻辑
   xxx.setXxx();
  ...
  }
优化后,注意不要让你的代码过于的臃肿
public void xxx() {
   // 业务逻辑
   // 业务逻辑
   // 业务逻辑
   setXxx(xxx)
}
public void setXxx() {
   xxx.setXxx();
   xxx.setXxx();
   xxx.setXxx();
}
最大最小值
    public static void main(String[] args) {
        int[] nums = {1,2 ,3, 4, 5};
        int min = Integer.MAX_VALUE;
        for (int i = 0; i < nums.length; i++) {
            if (nums[i] < min) {
                min = nums[i];
            }
        }
    }
优化后
    public static void main(String[] args) {
        int[] nums = {1,2 ,3, 4, 5};
        int length = nums.length;
        int min = Integer.MAX_VALUE; // 如果是有序数组,这里还可以直接替换int min = nums[length - 1]; 一般不建议使用Integer.MAX_VALUE
        min = nums[length - 1];
        for (int i = 0; i < length; i++) {
            min = Math.min(min, nums[i]);
        }
    }
Go语言的流式调用解决多层for
我们在业务中经常可能遇到这种代码
func GetResult(param []*dto.ActReq) []Stream {
	var (
		u []Stream
	)
	for _, p := range param {
		// 业务逻辑
		for _, a := range param.aaa {
			// 业务逻辑
			for _, x := range a.xxx {
				// 业务逻辑
				for _, b := range x.bbb {
					// 业务逻辑
					if b == "res" {
						var s Stream
						// 业务逻辑
						s.result = a
						u = append(u, s)
					}
				}
			}
		}
	}
	return u
}
优化后
type StreamList struct {
   StreamList []Stream
}
type Stream struct {
   result interface{}
   flag   string
}
func Builder(param []*dto.ActReq) *StreamList {
   var (
      u   []Stream
      res = &StreamList{}
   )
   for _, p := range param {
      // 业务逻辑
      for _, a := range param.aaa {
         // 业务逻辑
         var s Stream
         // 业务逻辑
         s.result = a
         u = append(u, s)
      }
   }
   return res.SetStream(u)
}
func (s *StreamList) SetStream(streamList []Stream) *StreamList {
   s.StreamList = streamList
   return s
}
func (s *StreamList) GetStream() []Stream {
   return s.StreamList
}
func (s *StreamList) AFilter(pass func(flag string) bool) *StreamList {
   streamList := make([]Stream, 0)
   for _, stream := range streamList {
      // 业务逻辑
      if pass(stream.flag) {
         streamList = append(streamList, stream)
      }
   }
   s.StreamList = streamList
   return s
}
func (s *StreamList) BFilter(pass func(flag string) bool) *StreamList {
   streamList := make([]Stream, 0)
   for _, stream := range streamList {
      // 业务逻辑
      if pass(stream.flag) {
         streamList = append(streamList, stream)
      }
   }
   s.StreamList = streamList
   return s
}
func main() {
   res := Builder(param).AFilter(func(flag string) bool {
      // 处理业务逻辑
      if flag == "xxx" {
         return true
      }
      return false
   }).BFilter(func(flag string) bool {
      // 处理业务逻辑
      if flag == "xxx" {
         return true
      }
      return false
   }).GetStream()
   fmt.Println(res)
}
业务代码中错误规范
-  Dao层 有逻辑可以进行包装处理,打印对应的req, 没有逻辑直接返回err 
-  Service层进行包装处理,打印对应的req,方便定位,业务错误封装到common baseError 
-  Controller层进行统一处理, 业务错误直接返回,内部错误进行包装处理 
-  也可以使用 %w 来找到调用的层级关系 
-  fmt.Errorf("[ShopOrder.UpdateOrderReward] is fail, orderID: %d, err: %w", orderID, err)
设计注意点
-  写测试 
-  路由不要透露内部的信息 防止暴露内部方法 
-  对应的一些配置信息,需要进行再次封装,进行解耦合 
-  方法的注释的规范,方便维护 例如:// 方法名 注释 
-  尽可能确保 err等于nil,其他状态不是nil 
-  引用类型,去查看nil指针,注意引用传递,尽量不要去修改指针中的值 
-  默认值不要为0, 因为有可能0值有意义,导致无法区分,还有就是gorm 更新实体,不会更新默认值。 
-  内存用到在进行初始化,因为go延迟释放内存 
-  预先知道长度 用长度初始化,避免频繁扩容(append) 
-  先把业务的主干进行确定 
-  遵循开闭原则,内部调用小写,可以建立service的协助者 
-  Mq消息做幂等 
-  使用golangci golint进行代码的扫描 
-  黑名单考虑用户多次进入和移除黑明单的场景,自动退出黑名单的场景 
-  能一层循环搞定的一层循环搞定, 代码重复引用,抽取方法 
-  订单的数据表是 退单 方面就是 退单时间+订单状态 
-  Mq 中消费消息加入角色锁,防止用户进行刷单 
-  事先知道长度的 用i 进行循环,因为append 每次都会申请新的空间 
-  使用 redis hash数据结构,在进行Hincy 可以进行原子操作,而不需要进行加锁 
-  Service 和 dao 进行解耦合,遵守开闭原则,细化方法力度 
-  加入分布式锁 在幂等之前,加锁保证锁的力度变小 
-  本地master超前远程的master(别人在远程的master回滚代码,这样需要删除本地的master重新从远程拉去一个新的master) 
-  如果map中key value中value值为nil,可以使用struct{} 这个内存占比 0 
-  测试去除的代码 加todo 防止遗忘,例如协程。 
-  开发功能判断是否需要增加开关操作 
-  对于map的并发读写,增加读写锁,防止并发问题 
-  如果第三方接口耗时较长,需要对其做超时控制 
需求思考与总结
-  外部因素的排除(提前问好第三方有什么限制,是否是针对该接口的 还是针对全局的,对于其他的有什么影响) 
-  思考整体的方案设计,以及方案设计的优点和缺点,是否有其他方案可以 
-  编写测试用例,然后先测试成功 
-  思考逻辑点,先看接口是否正常,在深入看每个逻辑访问 成功 失败 是否对业务有影响,有影响如何进行处理 
-  测试正常的逻辑功能,debug一步一步的测试,不要去跳出,每次都需要仔细看看是否异常 
-  注意go语言如果是指针类型,那么不管内部什么类型都会替换地址,导致后续引用有可能出现问题,要注意 
-  自测仔细去思考所有的可能,然后模拟测试 
-  测试完,自己需要再去验证一遍上线的代码 
后续将持续进行更新~~~
 欢迎各位也分享与补充










