结构师手把手教我优化代码的经验总结,写好代码做个有良心的码畜

目录

架构师格言:

背景:

代码走读:

代码优化总结:

方法抽取:

常量提取:

注释明确:

每个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再去写一个。

  • 前后端做好传参约定:

约定>规范>编码

  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值