【总结】CodeReview 自查要注意的点

本贴最后更新于 1408 天前,其中的信息可能已经水流花落

总述

细数过来。进入阿里大家庭一个多月了,一个月以来,参加了不少 CodeReview,虽有开发规约的指引,但在 Review 的过程中,还是会有不少问题暴露出来,本文会总结在 CodeReview 之前,有哪些可以先自查的点,更好的保证代码的健壮性。

代码结构

在 CodeReview 之前,我们先对代码结构做一次剖析,开头,我们先从最本质的面向对象说起,面向对象,有属性,有方法,然后我们对属性做了很多的修饰,比如加 static 声明为静态,加 final 声明为常量,加 private 声明为私有。同样,我们也会对方法做很多修饰,然后会在方法中调用别的方法,因为,在真正讨论 CodeReview 之前,我们得先讨论下代码结构,如下所示,一个文件中,是分为以下几大模块

import xxxx
public class XiaoDao{

	public 类型 属性名

	public 回参 方法名(入参){
		一段处理逻辑
        
        调用其他的方法
        
       	一段逻辑处理
        
        返回
    }
}

要有了上面大致的结构后,我们就可以逐段的去自检。

代码 CR

当提到代码 CR 的时候,那一定是分两大部分, 一部分是代码层面,即 import 是否合理,属性/方法修饰是否合理,工具类使用是否合理。第二部分则是看业务逻辑,即写的代码有没有完成即定的产研需求。本文也会从这两个方面和大家一起探讨如何自检

代码层面的自检

代码层面的自检,主要是上面所列的代码结构是否是符合现有的业务,代码场景,本文将以两份代码做一个对比

import 引包

import 这个区域经常会被我们忽略掉,因为在新引入一个类的时候 ,IDEA 会帮我们自动引入,但是当我们删代码的时候,又不会帮我们自动删 除,所以这时候就有了多余的引用,如下所求:
image.png

如上图所求,对一个数据结构,我们开始想的是用 List 存,后来还是用 Map 存,然后把 List 的声明代码给注释掉了,但是上面的 import 并没有删掉,同样的情况还可能出现在 StringUtils 上面,有团队自己封装的,有引的 Spring 里面的,有引的 Apache 中的,就会在 import 区域,留下很多无用的引用。

代码格式化

格式化这个事,说大不大,说小不小,就是顺手的一个事,但是有个点要特别注意,只格式化自己修改的那一块代码,切记不要全选,不要格式化别人的代码!!
格式化之前:
image.png

格式化之后:
image.png

public/private

这是一个小细节,可能我们写 public 会写的比较顺手,或者在开发的时候,把一个公用方法,做了定制化改造,或者是把一个私有方法做了通用的抽象等等,在跑了代码逻辑没问题之后,可能就忽略这些小细节了,但一个定制化的方法,如果声明成了 public,其他开发的小伙伴在不知情的情况下调用了错误的逻辑,就有可能引发一些缺陷。如下图所求
image.png

日志

日志这个东西是很难打的一个东西,打少了,无法定位问题,打多了呢,又有太多的无用信息。就本文而言,要检查几个必打的地方
入参,调外域接口前的参数,调外域接口返回的参数,进行一大段复杂处理逻辑之后的结果,有异常之后的信息,准备返回给上层的返回值,如下所示:

public class Main {

    private static final Logger logger = LoggerFactory.getLogger(Main.class);

    public static void main(String[] args) {
        logger.info("Main,main param={}", JSON.toJSONString(args));

        // 经过一系列的复杂的运算得到了param值
        String param = "XiaoDao";
        logger.info("Main,main,key param={}", param);

        try {
            String result = fakeInterface(param);
            logger.info("Main,main,fakeInterface param={},result={}", param, result);
        } catch (Exception e) {
            String msg = String.format("Main,main,fakeInterface,error param=%s", param);
            logger.error(msg, e);
        }

        // 如果有返回值的话,还要记录返回值
        logger.info("Main,main result={}", "result");

    }
	
    /**
     * 假装这是外域的接口
     * @param param
     * @return
     */
    private static String fakeInterface(String param) {
        return "fake" + param;
    }

}

循环

可以说,我们在写代码的时候,十行有六行都是在对集合(List,Map)处理,如果一个方法中出现对一个集合多次遍历的话,就要注意了,是不是可以合并在一起,如下所示:

public static void main(String[] args) {
        List<TestModel> modelList = Collections.singletonList(new TestModel());
        // 获取NameList
        List<String> nameList = modelList.stream().map(TestModel::getName).collect(Collectors.toList());

        // 获取AgeList
        List<Integer> ageList = modelList.stream().map(TestModel::getAge).collect(Collectors.toList());

        ////////// 考虑是否可以用下面一个循环代替 //////////

        List<String> names = new ArrayList<>(modelList.size());
        List<Integer> ages = new ArrayList<>(modelList.size());
        for (TestModel model : modelList) {
            names.add(model.getName());
            ages.add(model.getAge());
        }

    }

业务 CR

发现有些小伙伴在进行 CR 的时候,不知道要讲什么,直接讲代码吧,没有一个业务前景,听的小伙伴也比较懵,讲业务吧,又不知道讲哪些合适。这时候,可以参考本文的表述:

在这次的迭代中,我负责的模块是 XXX,其中主要的逻辑是 XXXXXXX,涉及到 XXX 表变更,XXX 配置项变更,XXX 定时任务变更。如涉及到多个配置项和定时任务,可提前列一个表格出来。

然后开始从代码入口处,开始展示代码,就是把上述的代码结构中的每一部分讲解清楚。可参考以下话术:
现在我有 XXXX 信息,要经过 XXXX 的处理,得到 XXXX 结果。
然后要调用 XXXX 方法,得到 XXXX 结果,然后对 XXXX 结果进行 XXXX 的处理,得到 XXXXX
最后完成了 XXXX 业务。
我相信上述这么一段话,在大家开发的时候,一直回响在大家脑海中,CR 只不过是把这些话稍加整理,再表述出来给大家听。参会的小伙伴也可以顺着讲的业务线,了解这一块的业务,在串数据流的时候,也能发现一些处理欠缺可能引起风险的地方。

总结

上述梳理,可以大家平时用以自我 Review 代码,我一直相信,写代码是一件创造艺术品的过程,是一件需要不断打磨的过程,不是说完成了业务功能就可以了,要不断的抽象,整理,沉淀才能写出健壮的代码! 大家一起加油!!

  • Java

    Java 是一种可以撰写跨平台应用软件的面向对象的程序设计语言,是由 Sun Microsystems 公司于 1995 年 5 月推出的。Java 技术具有卓越的通用性、高效性、平台移植性和安全性。

    3186 引用 • 8212 回帖

相关帖子

欢迎来到这里!

我们正在构建一个小众社区,大家在这里相互信任,以平等 • 自由 • 奔放的价值观进行分享交流。最终,希望大家能够找到与自己志同道合的伙伴,共同成长。

注册 关于
请输入回帖内容 ...