代碼評審的 18 個軍規,收藏好!

前言

大家好,我是田螺

我們開發完需求,提測前,一般都需要代碼評審。小夥伴們,你們知道代碼評審,一般都有哪些軍規嘛?今天田螺哥給你帶來代碼評審的 18 個軍規。

  1. 添加必要的註釋

其實,寫代碼的時候,沒有必要寫太多的註釋,因爲好的方法名、變量名,就是最好的註釋。以下就是筆者總結的一些註釋規範:

以下就是一些添加註釋的 demo:

/**
 * @author 田螺
 * @date 2023/04/22 5:20 PM
 * @desc 田螺的實現類,撿田螺、賣田螺 (更多幹貨,關注公衆號:撿田螺的小男孩)
 */
public class TianLuoClass {
 
    /**
     * 這是賣田螺的兩法,它將兩個田螺的價格整數相加並返回結果。
     * 
     * @param x 第一個整數
     * @param y 第二個整數
     * @return 兩個整數的和
     */
    public int sellTianLuo(int x, int y) {
        return x + y;
    }
}
  1. 日誌打印規範

日誌是快速定位問題的好幫手,是撕逼和甩鍋的利器!打印好日誌非常重要。如果代碼評審的時候,這些日誌規範沒遵守,就需要修改

對於日誌打印規範,我之前整理出一篇文章,大家可以看一下哈,挺有用的:

工作總結!日誌打印的 15 個建議

  1. 命名規範

Java 代碼的命名應該清晰、簡潔和易於理解。我們代碼評審的時候,要注意是否有命名不規範,不清晰的代碼。下面是一些命名規範的建議:

  1. 參數校驗

我們代碼評審的時候,要注意參數是否都做了校驗,如userId非空檢查、金額範圍檢查、userName長度校驗等等。一般我們在處理業務邏輯的時候,要遵循先檢查、後處理的原則。

如果你的數據庫字段 userName 設置爲varchar(16), 對方傳了一個32位的字符串過來,你不校驗參數,插入數據庫直接異常了。

很多 bug 都是因爲沒做參數校驗造成的,這一軍規,是代碼評審重點關注的哈

  1. 判空處理

if(object!=null){
   String name = object.getName();
}

如果你要遍歷列表,也需要判空

  if (CollectionUtils.isNotEmpty(tianLuolist)) {
        for (TianLuo temp : tianLuolist) {
            //do something
        }
    }

  1. 異常處理規範

良好的異常處理可以確保代碼的可靠性和可維護性。因此,異常處理也是代碼評審的一項重要規範。以下是一些異常處理的建議:

大家有興趣可以看下之前我的這篇文章哈:Java 異常處理的十個建議

  1. 模塊化,可擴展性

代碼評審的時候,關注一下,代碼編寫設計是否滿足模塊話,接口是否具有可擴展性

比如你的需求是醬紫:是用戶添加或者修改員工時,需要刷臉。那你是反手提供一個員工管理的提交刷臉信息接口?還是先思考:提交刷臉是不是通用流程呢?比如轉賬或者一鍵貼現需要接入刷臉的話,你是否需要重新實現一個接口呢?還是當前按業務類型劃分模塊,複用這個接口就好,保留接口的可擴展性。

如果按模塊劃分的話,未來如果其他場景比如一鍵貼現接入刷臉的話,不用再搞一套新的接口,只需要新增枚舉,然後複用刷臉通過流程接口,實現一鍵貼現刷臉的差異化即可。

  1. 併發控制規範

至於分佈式鎖, 大家可以看下我之前的這幾篇文章哈

  1. 單元測試規範

  1. 代碼格式規範

良好的代碼格式,可以使代碼更容易閱讀和理解。下面是一些常見的代碼格式化建議:

  1. 接口兼容性

代碼評審的時候, 要重點關注是否考慮到了接口的兼容性. 因爲很多 bug 都是因爲修改了對外舊接口,但是卻不做兼容導致的。關鍵這個問題多數是比較嚴重的,可能直接導致系統發版失敗的。新手程序員很容易犯這個錯誤哦~

所以,如果你的需求是在原來接口上修改,尤其這個接口是對外提供服務的話,一定要考慮接口兼容。舉個例子吧,比如 dubbo 接口,原本是隻接收 A,B 參數,現在你加了一個參數 C,就可以考慮這樣處理:

//老接口
void oldService(A,B){
  //兼容新接口,傳個null代替C
  newService(A,B,null);
}

//新接口,暫時不能刪掉老接口,需要做兼容。
void newService(A,B,C){
  ...
}
  1. 程序邏輯是否清晰, 主次是否夠分明

代碼評審的時候,要關注程序邏輯是否清晰。比如,你的一個註冊接口,有參數校驗、判斷用戶是否已經註冊、插入用戶記錄、發送註冊成功通知等功能。如果你把所有所有功能代碼塞到一個方法裏面,程序邏輯就不清晰,主次不夠分明,反例如下:

 public Response registerUser(String userName, String password, String email) {

        if (userName == null || StringUtils.isEmpty(userName)) {
          log.info("用戶名不能爲空!");
            throw new BizException();
        }

        if (password == null || password.length() < 6) {
            log.info("密碼長度不能少於6位!");
            throw new BizException();
        }

        if (email == null || StringUtils.isEmpty(email) || !email.contains("@")) {
            log.info("郵箱格式不正確!");
            throw new BizException();
        }

        Response response = new Response();
        UserInfo userInfo = userService.queryUserInfoByUsername();
        if (Objects.nonNull(userInfo)) {
            response.setCode(0);
            response.setMsg("註冊成功");
            return response;
        }


        UserInfo addUserInfo = new UserInfo();
        addUserInfo.setUserName(userName);
        addUserInfo.setPassword(password);
        addUserInfo.setEmail(email);
        userService.addUserInfo(addUserInfo);

        MessageDo messageDo = new MessageDo();
        messageDo.setUserName(userName);
        messageDo.setEmail(email);
        messageDo.setContent("註冊成功");
        messageService.sendMsg(messageDo);

        response.setCode(0);
        response.setMsg("註冊成功");
        return response;
    }

其實,以上這塊代碼,主次不夠分明的點: 參數校驗就佔registerUser方法很大一部分。正例可以劃分主次,抽一下小函數,如下:

    public Response registerUser(String userName, String password, String email) {

        //檢查參數
        checkRegisterParam(userName, password, email);
        //檢查用戶是否已經存在
        if (checkUserInfoExist(userName)) {
            Response response = new Response();
            response.setCode(0);
            response.setMsg("註冊成功");
            return response;
        }

        //插入用戶
        addUser(userName, password, email);
        sendMsgOfRegister(userName, email);

        //構造註冊成功報文
        Response response = new Response();
        response.setCode(0);
        response.setMsg("註冊成功");
        return response;
    }

    private void sendMsgOfRegister(String userName, String email) {
        MessageDo messageDo = new MessageDo();
        messageDo.setUserName(userName);
        messageDo.setEmail(email);
        messageDo.setContent("註冊成功");
        messageService.sendMsg(messageDo);
    }

    private void addUser(String userName, String password, String email) {
        UserInfo addUserInfo = new UserInfo();
        addUserInfo.setUserName(userName);
        addUserInfo.setPassword(password);
        addUserInfo.setEmail(email);
        userService.addUserInfo(addUserInfo);
    }

    private boolean checkUserInfoExist(String userName) {
        UserInfo userInfo = userService.queryUserInfoByUsername();
        if (Objects.nonNull(userInfo)) {
            return true;
        }
        return false;
    }

    private void checkRegisterParam(String userName, String password, String email) {
        if (userName == null || StringUtils.isEmpty(userName)) {
            log.info("用戶名不能爲空!");
            throw new BizException();
        }

        if (password == null || password.length() < 6) {
            log.info("密碼長度不能少於6位!");
            throw new BizException();
        }

        if (email == null || StringUtils.isEmpty(email) || !email.contains("@")) {
            log.info("郵箱格式不正確!");
            throw new BizException();
        } 
    }
  1. 安全規範

代碼評審,也非常有必要評審代碼是否存在安全性問題。比如:

其實我以前寫過一篇文章,保證數據安全的 10 種方案,大家可以看看哈:保證接口數據安全的 10 種方案

  1. 事務控制規範

  1. 冪等處理規範

什麼是冪等?

計算機科學中,冪等表示一次和多次請求某一個資源應該具有同樣的副作用,或者說,多次請求所產生的影響與一次請求執行的影響效果相同。

代碼評審的時候,要關注接口是否考慮冪等。比如開戶接口,多次請求過來的時候,需要先查一下該客戶是否已經開過戶,如果已經開戶成功,直接返回開戶成功的報文。如果還沒開戶,就先開戶,再返回開戶成功的報文。這就是冪等處理。

一般情況有這幾種冪等處理方案:

冪等要求有個唯一標記,比如數據庫防重表的一個業務唯一鍵。同時強調多次請求和一次請求所產生影響是一樣的。

大家如果對接口冪等有興趣的話,可以看下我之前的這篇文章:聊聊冪等設計

  1. 中間件注意事項 (數據庫,redis)

代碼評審的時候,如果用數據庫、Redis、RocketMq等的中間件時,我們需要關注這些中間件的一些注意事項哈。

比如數據庫

比如Redis:

之前我寫過一篇文章,介紹 Redis 使用注意點的,大家可以看一下哈: 使用 Redis,你必須知道的 21 個注意要點

  1. 注意代碼壞味道問題

理解幾個常見的代碼壞味道,大家代碼評審的時候,需要關注一些哈:

  1. 遠程調用

遠程調用是代碼評審重點關注的一欄,比如:

本文由 Readfog 進行 AMP 轉碼,版權歸原作者所有。
來源https://mp.weixin.qq.com/s/4b7FS7DWvpny9QJig-fsSA