代码的味道
要用一种精致的态度去写代码,才能写出优美而牢固的代码。
本文主要从日常代码中摘录一些不良的写法。这些不良的写法会扰乱清晰的主流程,淹没重要的业务逻辑,使得代码语义难以理解和修改。
代码坏味
单词编写错误
“单测拼写错误,这得多粗心 ?” 错误的单词,看一遍,别扭一次。请体谅我的强迫症。
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();
}
小结
代码是逻辑与表达的艺术。
代码编写,就像一门手工艺。要打造出优秀的作品,良好的习惯和细节是关键。改掉不良的代码习惯,坚持清爽整洁之道,才能让代码更优美而牢固。
什么是好的代码习惯 ? 两个小原则:
-
拆解。凡有比较复杂的逻辑或关注点,分离细小可复用的关注点, 分离出来作为变量或函数。
-
简洁。始终追求简洁易懂的表达。