鲜为人知的拒绝CRUD,看这个就够了

136 阅读6分钟

引言 很多同学在工作一段时间后可能会有这样的困境。大家都觉得一直在写业务代码,技术上好像没什么进步。不知不觉就变成了凝乳男孩或女孩,想改变却不知从何下手。有些同学会学习如何做架构,有些同学可能会学习各种新技术,有些同学甚至会求助于产品经理来尝试解决困境。但我认为走出这个困境的方法是从我们每天写的代码开始。即使我们目前每天都在做CRUD,也不能把自己定义为只懂CRUD的工具人。那么我们如何从代码层面改变困境呢?我们可以回头看看之前写的代码,或者目前正在实现的各种需求,问自己以下五个问题。

  1.你使用设计模式来优化代码结构吗?

  2.你利用一些高级特性来简化代码实现吗?

  3.有没有借助框架扩展应用能力的能力?

  4.自己设计的商业模式够抽象吗?

  5.代码可扩展吗?如果需求改变,模块代码是否可以最小化修改?

  通过这样的反问和思考,我们可以不断地审视自己的代码。通过在代码上下功夫,我们负责的模块质量会比别人高,出现bug的概率会更低,稳定性会更高,所以以后会有更多的机会负责更多的业务模块。只有这样,才能真正走出困境,实现突破。因此,本文主要从优化日常工作中经常遇到的重复代码入手,和大家一起探讨如何通过一些技巧来消除平台中的重复代码,以消除系统中的重复代码为出发点,提高系统的稳定性。

  为什么要消除重复代码?

  在程的日常工作中,不仅要随着业务端的发展不断开发新的需求,还要维护原有的平台。无论是开发新的需求还是维护旧的系统,我们都会遇到同样的问题。系统中总是充斥着大量重复的代码。可能是因为建设周期太短无法优化,也可能是历史原因造成的技术欠账。不管是什么原因,系统中大量的重复代码极大地影响了平台整体的可维护性。大神们的谆谆教诲不要重复自己还在耳边。那么平台中的重复代码会带来怎样的稳定性风险呢?

  系统维护成本高

  如果项目中出现大量重复代码,系统中的这部分业务逻辑没有很好的抽象出来,会导致后期代码维护出现很多问题。无论是修改原有逻辑,还是增加新的业务逻辑,都可能需要在不同的文件中进行修改,项目维护成本相当高。再加上后期维护的同学看到同一个逻辑写了很多遍,不明白是代码的恶趣味还是有什么特殊的业务考虑,无形中增加了后期维护人员理解代码逻辑的难度。

  程序出错的可能性很高

  众所周知,代码重复意味着业务逻辑相同或相似。如果这些相同或相似的代码有bug,在修复的过程中需要多处修改,导致大量的在线修改,存在一定的风险。毕竟网上70%-80%的问题都是新变化造成的。另外,如果重复多了,很有可能会错过改动。所以,重复代码其实是隐藏在项目中的老炸弹。可能永远是安全的,也可能你不知道什么时候Bom会给你一个惊喜。因此,我们必须消除重复的代码。

  如何优雅地消除重复代码

  在消除重复代码之前,我们首先需要确定什么是重复代码,或者它们的特征是什么。有的同学可能会说,不容易。重复代码是分散在项目不同部分的相同代码。当然这句话也是对的,但是不够全面。重复代码不仅指不同文件中相同的代码,还包括一些业务流程相似但不完全相同的代码,我们也称之为重复代码。重复代码的几个特征:

  1.代码结构是相同的。

  比如项目中有几个地方读取配置文件的逻辑,代码都是一样的,那么我们就可以把读取不同地方配置文件的逻辑放到一个工具类中,这样以后有读取配置文件的需求时,就可以直接调用工具类中的方法,不需要再写同样的代码。这也是我们日常工作中最常见的使用方式。

  2.代码逻辑结构类似。

  在项目中经常会遇到虽然代码不完全相同,但逻辑结构却非常相似的情况。比如电商平台在进行营销活动时,往往会邀请用户领取红包。但新老用户的红包赠送规则不同,会根据邀请用户数量给予不同的红包优惠。但无论是新老用户,都会经历一个根据用户类型获取红包计算规则,根据规则计算减少的红包,并在支付结束时减去红包金额的业务逻辑。虽然代码表面看起来不一样,但实际上逻辑基本一致,所以也属于重复代码。   统一参数验证

  我们在开发一个项目的时候,会写一些类的实现方法,不可避免的会检查一些参数或者业务规则,所以会在实现方法里面写一些代码来判断参数是否有效或者返回的结果是否有效。 很多人喜欢用注释@Valid来判断参数的有效性,但我觉得不够方便。它只能检查一些参数,而不能判断业务结果的有效性。那么我们如何消除重复的if呢...其他...判断代码为该检查类的代码。因此,我通常定义一个Assert断言来验证参数或业务结果。当然,我也可以使用Spring框架提供的assert抽象类进行判断,但是它抛出的异常是IllegalArgumentException。我习惯于抛出自己定义的全局统一异常信息,让全局异常处理类统一处理。因此,我们首先定义一个业务断言类,它主要断言biz层中的参数和业务结果,从而避免编写if...其他...反复判断代码。


  public static void notEmpty(String param) {

  if(StringUtils.isEmpty(param)) {

  throw new BizException(ErrorCodes.PARAMETER_IS_NULL, "param is empty or null");

  }

  }

  public static void notNull(Object o) {

  if (Objects.isNull(o)) {

  throw new BizException(ErrorCodes.PARAMETER_IS_NULL, "object is null");

  }

  }

  public static void notEmpty(Collection collection) {

  if(CollectionUtils.isEmpty(collection)) {

  throw new BizException(ErrorCodes.PARAMETER_IS_NULL, "collection is empty or null");

  }

  }

  }

我们看下优化后的代码是不是看上去清爽许多。


  Assert.notEmpty(id);

  OrderDTO order = orderBizService.queryOrder(id);

  Assert.notNull(order);

  …

  }

  public List<UserDTO> queryUsersByType(List<String> type) {

  Assert.notEmpty(type);

  …

  }