须要用一种精致的态度去写代码,才能写出优美而牢固的代码。java
坏味,一般是那些人们闻起来很是不舒服且避之不及的味道。走进垃圾桶,你就能深入感觉到坏味的存在。编程
代码坏味,是指那些阅读和理解起来很是拗口、困难、耗费大量脑力的代码。代码坏味更多反映的是风格和态度问题,而与技术没有太大的关系(也能够理解为匮乏编写可读代码的技术能力)。技术还能够提高,风格和态度坏掉了,整我的的作事就 Low 掉了。这就比如一我的学了不少招式,可是一个马步都蹲不稳。函数
好的代码应该是怎样的 ? 简洁、天然、清晰。 读起来,就像感觉到一阵微香的春风,很天然地就理解了,不会感觉到阻力。工具
本文将给出若干代码坏味,以及如何更好地编写。
ui
单测拼写错误,这得多粗心 ?他写代码的时候都在想些什么 ? 真但愿这样的人赶忙转行,编程行业没法容忍这种态度作事的人。code
String finasName = fans.getFansNickname(); if (StringUtil.isNotBlank(finasName)) { customer = finasName; }
最忍不住冲动的就是链式写法。 以下代码所示:orm
boolean isPayCard = goods.getGoodsRichInfo().getItemModel().isPayCard(); if (response.getData() != null && CollectionUtils.isNotEmpty(response.getData().getCartList())) { // 出参转换 cartList = response.getData().getCartList().stream().map(CartResponseBuilder::buildCartList).collect(Collectors.toList()); }
究其缘由,是这么写很爽。不过爽是有代价的: NPE 潜伏其中,并且报 NPE 时,还不能直观看出是哪个有问题。好比上面的代码,getGoodsRichInfo() 和 getItemModel() 都有多是 null 而引起 NPE 。blog
有两种解决技巧:1. 拆解成多个单行调用并作判空(若是变量有复用更好); 2. 用 Optional 避免 NPE。
get
链式写法的一个变种,就是把全部东西都扔到一行,—— 其冲动本质是同样的。 以下代码所示:it
List<String> orderNos = new ArrayList<>(messages.stream().map(TcOrder::getOrderNo).collect(Collectors.toSet())); orderService.queryOrder(Long.parseLong(orderInfoList.get(0).getShopId()), orderNo)
这样的坏处是什么呢 ?
还有这种:
long discounts = Optional.ofNullable(item).map(Item::getPrice).orElse(0L) - Optional.ofNullable(item).map(OrderItem::getItemPrice) .map(ItemPrice::getUnitPrice).orElse(0L);
明明能够拆解为:
Long originPrice = Optional.ofNullable(item).map(Item::getPrice).orElse(0L); Long unitPrice = Optional.ofNullable(item).map(Item::getItemPrice) .map(ItemPrice::getUnitPrice).orElse(0L); long discounts = originPrice - unitPrice
更极端的例子:
坏味是什么?
解决方法: 把构建 refundStatus 的部分抽离出来,以下所示。这样,这个方法就清晰不少,也很容易进行覆盖性单测,更可靠。
人是很容易效仿的。这样的代码看多了,你也会忍不住来上几行。
经常能够看到这样的代码:
if (isRetail) { // buildLocalDeliveryInfoCodeForRetail 55 lines } else { //buildLocalDeliveryInfoCodeForNormal 73 lines }
坏处是什么:主流程很容易被分支代码冲散,变成毫无重点的代码堆砌;若是有多个条件分支,渐渐就会演变成多重 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"; }
代码坏味不少,难以一一列举,但其本质的特色,就是喜欢将大量逻辑不分层次地堆砌到一块儿。解决这些代码坏味的技巧其实很简单:拆解子函数,调用它。 如何将代码拆解成不一样层次的优雅组合,这是一门技艺。
编程,是逻辑与表达并重的活动。我的认为,重逻辑而不重表达,重技术而不重细节,是国内难以批量生产高质量软件的重因之一。要作出高质量软件,从写好每一行代码入手,而不能期望工程上有什么银弹可让一堆烂代码成就一个好软件。须要用一种精致的态度去写代码,才能写出优美而牢固的代码。
对于我的来讲,不容忍代码坏味,孜孜不倦地追求编写简洁、天然、清晰的代码;对于企业来讲,须要树立标杆,有更多关于代码质量的布道者,培养编写好代码的技术氛围。不然,代码就只是赚钱养家的工具,过几年就要所有扔掉,没有留下什么值得借鉴和复用的东西,陷入低水平重复建设的境地。