結構師手把手教我優化代碼的經驗總結,寫好代碼做個有良心的碼畜

目錄

架構師格言:

背景:

代碼走讀:

代碼優化總結:

方法抽取:

常量提取:

註釋明確:

每個service中不要包含別的service的mapper需要調用盡量走service:

巧用框架:


架構師格言:

在實現相同功能的情況下,誰寫的代碼少誰就牛逼。

背景:

    最近開發了一個關於用戶設置企業的新功能,本地測試與測試環境測試均能通過,但是發佈到線上以後,當用戶選擇的數據量很大以後,用戶點擊確定按鈕就一直轉圈,最後數據庫報:Caused by: com.mysql.cj.jdbc.exceptions.MySQLTransactionRollbackException: Lock wait timeout exceeded; try restarting transaction 異常。由於數據量比較大業務比較複雜,該問題一共耗時三天才解決,在解決問題的過程中涉及到很多東西,包括sql優化,代碼優化,在解決該問題的過程中得到了架構師的手把手教學,讓我收穫頗深,真正體會了什麼叫代碼之美。

代碼走讀:

 講真,我覺得代碼走讀和你裸着站在人羣中被指指點點那種感受是一樣的,被嫌棄你的胸小,屁股小......,代碼走讀兩小時,我全程黑着臉,感覺我是一個沒有良心的碼畜(寫代碼的畜生)。

代碼優化總結:

方法抽取:

比如這段代碼,我甚至都不需要具體點進去看每個方法幹了啥我就知道addApplication幹了啥,

  @Override

    public void addApplication(ApplicationDto applicationDto) {

        Application application = JsonUtil.object2Object(applicationDto, Application.class);

        validateAppName(applicationDto);

        validateAppRoute(applicationDto);

        validateAppRouteName(applicationDto);

        applicationMapper.insert(application);

    }



但如果我寫成下面這樣,看起來就會很難受。一般我們的方法體都不應該過於長,太長了可讀性非常差,自己讀完後面的,忘記了前面在幹啥。

 

    @Override

    public void addApplication(ApplicationDto applicationDto) {

        Application application = JsonUtil.object2Object(applicationDto, Application.class);

        LambdaQueryWrapper<Application> queryWrapper1 = Wrappers.<Application>query().lambda().eq(Application::getName, applicationDto.getName()).eq(Application::isDel, 0);

        Optional.ofNullable(applicationDto.getId()).ifPresent(id -> queryWrapper1.and(wrapper -> wrapper.ne(Application::getId, applicationDto.getId())));

        Application application1 = getOne(queryWrapper1);

        if (!Objects.isNull(application1)) {

            throw new BasicBusinessException("系統名已存在!");

        }

        LambdaQueryWrapper<Application> queryWrapper2 = Wrappers.<Application>query().lambda().eq(Application::getRoute, applicationDto.getRoute()).eq(Application::isDel, 0);

        Optional.ofNullable(applicationDto.getId()).ifPresent(id -> queryWrapper2.and(wrapper -> wrapper.ne(Application::getId, applicationDto.getId())));

        Application application2 = getOne(queryWrapper2);

        if (!Objects.isNull(application2)) {

            throw new BasicBusinessException("系統路由已存在!");

        }

        LambdaQueryWrapper<Application> queryWrapper3 = Wrappers.<Application>query().lambda().eq(Application::getRouteName, applicationDto.getRouteName()).eq(Application::isDel, 0);

        Optional.ofNullable(applicationDto.getId()).ifPresent(id -> queryWrapper3.and(wrapper -> wrapper.ne(Application::getId, applicationDto.getId())));

        Application application3 = getOne(queryWrapper3);

        if (!Objects.isNull(application3)) {

            throw new BasicBusinessException("系統標識已存在!");

        }

        applicationMapper.insert(application);

    }

常量提取:

將代碼中的常量,以及魔法值的數據提取出來,以便公用和可讀。

  public Long createDefaultTenantRole(String tenanName, Long tenantId) {

        Role tenantDefaultRole = Role.builder()

                .name(tenanName + "管理員")

                .code("ROLE_TENANT_ADMIN_" + UuidUtil.get15UUID())

                .classify(1)

                .tenantId(tenantId)

                .type(0)

                .build();

        roleService.save(tenantDefaultRole);

        return tenantDefaultRole.getId();

    }

將常量提取出來:

private static final String ROLE_TENANT_VISIT = "ROLE_TENANT_VISIT_";

註釋明確:

複雜的方法邏輯請寫好註釋,方便覆盤,也方便他人後期的維護,不然你走後你寫的垃圾代碼將使後來者生不如死。註釋不是越多越好,只寫重要的那麼幾句就行了,太多了還以爲你是在寫小說呢,方法取名的時候儘量不要走非主流路線,帶有實際意義一些,不會的單詞就谷歌翻譯,別寫漢語拼音了,真的太low了。很多很長的單詞沒必要全部寫下來,取前面三四個字母就行了,像這樣:kubernetes=k8s ,JsonToObject= Json2Obj。

 

每個service中不要包含別的service的mapper需要調用盡量走service:

我想大部分人寫serviceImpl都是這樣的:

public class ApplicationServiceImpl implements ApplicationService {



    private final ApplicationMapper applicationMapper;



    private final RoleMenuMapper roleMenuMapper;



    private final TenantSystemMapper tenantSystemMapper;



    private final SystemConfigMapper systemConfigMapper;



    private final UserRoleMapper userRoleMapper;



    private final MenuMapper menuMapper;

}

都是直接包含別人的service的mapper,可能我們剛開始使用Mvc模式的時候就是這樣寫的,然後我以爲這樣寫沒什麼毛病但是架構師建議我不要這樣寫,他建議我這樣寫:

public class ApplicationServiceImpl implements ApplicationService {



    private final ApplicationMapper applicationMapper;



    private final RoleMenuServiceImpl roleMenuService;



    private final TenantSystemServiceImpl tenantSystemService;



    private final SystemConfigServiceImpl systemConfigService;



    private final UserRoleServiceImpl userRoleService;



    private final MenuServiceImpl menuService;

}


  • 這樣寫有什麼好處呢?

  1. service比mapper擁有的功能更強、更全面。
  2. 很多操作都需進行邏輯校驗後才能被操作,而很多這樣的邏輯都是通用的,比如更新一條數據之前先要校驗是否被使用,如果被使用那就不能更新,如果引用別人的service就能夠實現方法複用。
  3. 高併發場景下能夠避免事務太長導致mysql報鎖等待超時異常。

巧用框架:

public class ApplicationServiceImpl extends ServiceImpl<ApplicationMapper, Application> implements ApplicationService {

    private final ApplicationMapper applicationMapper;

就拿mybatisPlus來說,當我們繼承了ServiceImpl以後,我們能夠發現ServiceImpl中有這麼多已實現的方法可以用,那我們在使用的時候就儘量用上。

比如:獲取一條數據:我呢吧可以用getOne()而不是通過applicationMapper再去寫一個。

  • 前後端做好傳參約定:

約定>規範>編碼

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章