代码的味道

要用一种精致的态度去写代码,才能写出优美而牢固的代码。


本文主要从日常代码中摘录一些不良的写法。这些不良的写法会扰乱清晰的主流程,淹没重要的业务逻辑,使得代码语义难以理解和修改。


代码坏味

单词编写错误

“单测拼写错误,这得多粗心 ?” 错误的单词,看一遍,别扭一次。请体谅我的强迫症。


String finasName = fans.getFansNickname();

if (StringUtil.isNotBlank(finasName)) {
    customer = finasName;
}


“炫技式”的单行代码

“炫技式”的单行代码就是把多个动作全部糅合到一行语句里。这种代码写起来很“爽”,但读者却未必“爽”。

详情可阅:“一个较重的代码坏味:“炫技式”的单行代码”

大段的if-else

常常可以看到这样的代码:

if (isRetail) {
   // buildLocalDeliveryInfoCodeForRetail  55 lines
}
else {
   //buildLocalDeliveryInfoCodeForNormal  73 lines
}

坏处是什么:主流程很容易被分支代码冲散,变成毫无重点的代码堆砌;如果有多个条件分支,渐渐就会演变成多重 if-else 语句;方法越来越长,膨胀很快。第一个人没做好,后面的人效仿起来,很容易就变成了一堆谁也不愿意碰的烂代码。

对于这种情形,简单的方案是,把多个条件分支的语句,分别抽到多个子函数,凸显主流程;更进一步,采用策略模式,将多个子函数变成多个互不影响的组件,这样,每个类都很短小,各司其职,需要修改时也只要改局部即可。

多重嵌套if-else语句

我拆解过一个多重 if-else 语句,限于公司代码规定,这里不便透露。

多重嵌套 if-else 语句,通过一个小技巧就可以进行“降重”:对于每个分支,编写子函数,然后调用它。在每个子函数里,可以通过 if-return 卫述句,快速返回,更容易理解。

如果有多重条件呢 ?比如:

if (orderDetail.getIsVirtual()
        || orderDetail.getIsVT()){
        if (isStockOverSale(orderDetail.getExtra())) {
            return "oversale, wait confirm";
        } else if (isStockDoing(orderDetail.getExtra())) {
            return "wait for stock confirm";
        }
    }

坏处是什么? 如果我又要新增不同维度的条件,这里很容易就会变成三重乃至更多重 if-else 语句, 你懂的。

解决方法:可以将变量分离出来,将多重条件打平:


boolean isVirtual = orderDetail.getIsVirtual();
boolean isVirtualTicket = orderDetail.getIsVT();
boolean isVirtualOrder = isVirtual || isVirtualTicket;
boolean isStockOverSale = isStockOverSale(orderDetail.getExtra());
boolean isStockDoing = isStockDeductDoing(orderDetail.getExtra()); 

if (isVirtualOrder && isStockOverSale) {
    return "oversale, wait confirm";
}
if (isVirtualOrder && isStockDeductDoing) {
    return "wait for stock confirm";
}

不够优美

这段代码并没有问题,但是不够优美。


public Boolean kdtIdsLimit(LimitStageEnum limitStageEnum, Set<Long> kdtIds) {

  for (Long kdtId : kdtIds) {

      Map<String, String> features = Maps.newHashMap();
      features.put("stage", limitStageEnum.getValue());
      features.put("kdt_id", kdtId.toString());
      TrafficLimitDecision decision = programmingTrafficLimitAdapter.apply(features);

      if (decision.shouldLimit()) {
          return true;
      }

  }

  return false;
}


优美的写法是什么 ? 该分离的关注点分离出来,努力寻求最简洁的方式表达。

这段代码含有两个语义:1. 对一个 shopId 判断是否限流; 2. 如果有一个限流,则所有都要限流。一个是单店铺的限流判断的实现,一个是多个店铺的限流匹配规则。应该分离开。


public Boolean shopIdsLimit(LimitStageEnum limitStageEnum, Set<Long> shopIds) {
    return shopIds.stream().anyMatch(this::shouldLimit);
}

private boolean shouldLimit(Long shopId) {
    Map<String, String> features = Maps.newHashMap();
    features.put("stage", limitStageEnum.getValue());
    features.put("shop_id", shopId.toString());
    TrafficLimitDecision decision = programmingTrafficLimitAdapter.apply(features);
    return decision.shouldLimit();
}


小结

代码是逻辑与表达的艺术。

代码编写,就像一门手工艺。要打造出优秀的作品,良好的习惯和细节是关键。改掉不良的代码习惯,坚持清爽整洁之道,才能让代码更优美而牢固。


什么是好的代码习惯 ? 两个小原则:

  1. 拆解。凡有比较复杂的逻辑或关注点,分离细小可复用的关注点, 分离出来作为变量或函数。

  2. 简洁。始终追求简洁易懂的表达。


posted @ 2019-09-20 22:16  琴水玉  阅读(490)  评论(0编辑  收藏  举报