您当前的位置:首页 > 电脑百科 > 程序开发 > 程序员

优秀的后端应该有哪些开发习惯?

时间:2022-04-13 09:13:50  来源:掘金  作者:暮色妖娆

前言

毕业快三年了,前后也待过几家公司,碰到各种各样的同事。见识过各种各样的代码,优秀的、垃圾的、不堪入目的、看了想跑路的等等,所以这篇文章记录一下一个优秀的后端 JAVA 开发应该有哪些好的开发习惯。

拆分合理的目录结构

受传统的 MVC 模式影响,传统做法大多是几个固定的文件夹 controller、service、mApper、entity,然后无限制添加,到最后你就会发现一个 service 文件夹下面有几十上百个 Service 类,根本没法分清业务模块。正确的做法是在写 service 上层新建一个 modules 文件夹,在 moudles 文件夹下根据不同业务建立不同的包,在这些包下面写具体的 service、controller、entity、enums 包或者继续拆分。

优秀的后端应该有哪些开发习惯?

 


优秀的后端应该有哪些开发习惯?

 

等以后开发版本迭代,如果某个包可以继续拆领域就继续往下拆,可以很清楚的一览项目业务模块。后续拆微服务也简单。

封装方法形参

当你的方法形参过多时请封装一个对象出来...... 下面是一个反面教材,谁特么教你这样写代码的!

public void updateCustomerDeviceAndInstallInfo(long customerId, String channelKey,
                   String AndroidId, String imei, String gAId,
                   String gcmPushToken, String instanceId) {}
复制代码

写个对象出来

public class CustomerDeviceRequest {
    private Long customerId;
    //省略属性......
}
复制代码

为什么要这么写?比如你这方法是用来查询的,万一以后加个查询条件是不是要修改方法?每次加每次都要改方法参数列表。封装个对象,以后无论加多少查询条件都只需要在对象里面加字段就行。而且关键是看起来代码也很舒服啊!

封装业务逻辑

如果你看过“屎山”你就会有深刻的感触,这特么一个方法能写几千行代码,还无任何规则可言......往往负责的人会说,这个业务太复杂,没有办法改善,实际上这都是懒的借口。不管业务再复杂,我们都能够用合理的设计、封装去提升代码可读性。下面贴两段高级开发(假装自己是高级开发)写的代码

@Transactional
public ChildOrder submit(Long orderId, OrderSubmitRequest.Shop shop) {
    ChildOrder childOrder = this.generateOrder(shop);
    childOrder.setOrderId(orderId);
    //订单来源 APP/微信小程序
    childOrder.setSource(userService.getOrderSource());
    // 校验优惠券
    orderAdjustmentService.validate(shop.getOrderAdjustments());
    // 订单商品
    orderProductService.add(childOrder, shop);
    // 订单附件
    orderAnnexService.add(childOrder.getId(), shop.getOrderAnnexes());
    // 处理订单地址信息
    processAddress(childOrder, shop);
    // 最后插入订单
    childOrderMapper.insert(childOrder);
    this.updateSkuInventory(shop, childOrder);
    // 发送订单创建事件
    applicationEventPublisher.publishEvent(new ChildOrderCreatedEvent(this, shop, childOrder));
    return childOrder;
}
复制代码
@Transactional
public void clearBills(Long customerId) {
    // 获取清算需要的账单、deposit等信息
    ClearContext context = getClearContext(customerId);
    // 校验金额合法
    checkAmount(context);
    // 判断是否可用优惠券,返回可抵扣金额
    CouponDeductibleResponse deductibleResponse = couponDeducted(context);
    // 清算所有账单
    DepositClearResponse response = clearBills(context);
    // 更新 l_pay_deposit
    lPayDepositService.clear(context.getDeposit(), response);
    // 发送还款对账消息
    repaymentService.sendVerifyBillMessage(customerId, context.getDeposit(), EventName.DEPOSIT_SUCCEED_FLOW_REMINDER);
    // 更新账户余额
    accountService.clear(context, response);
    // 处理清算的优惠券,被用掉或者解绑
    couponService.clear(deductibleResponse);
    // 保存券抵扣记录
    clearCouponDeductService.add(context, deductibleResponse);
}
复制代码

这段两代码里面其实业务很复杂,内部估计保守干了五万件事情,但是不同水平的人写出来就完全不同,不得不赞一下这个注释,这个业务的拆分和方法的封装。一个大业务里面有多个小业务,不同的业务调用不同的 service 方法即可,后续接手的人即使没有流程图等相关文档也能快速理解这里的业务,而很多初级开发写出来的业务方法就是上一行代码是 A 业务的,下一行代码是 B业务的,在下面一行代码又是 A 业务的,业务调用之间还嵌套这一堆单元逻辑,显得非常混乱,代码还多。

判断集合类型不为空的正确方式

很多人喜欢写这样的代码去判断集合

if (list == null || list.size() == 0) {
  return null;
}
复制代码

当然你硬要这么写也没什么问题......但是不觉得难受么,现在框架中随便一个 jar 包都有集合工具类,比如
org.springframework.util.CollectionUtils、com.baomidou.MyBatisplus.core.toolkit.CollectionUtils 。 以后请这么写

if (CollectionUtils.isEmpty(list) || CollectionUtils.isNotEmpty(list)) {
  return null;
}
复制代码

集合类型返回值不要 return null

当你的业务方法返回值是集合类型时,请不要返回 null,正确的操作是返回一个空集合。你看 mybatis 的列表查询,如果没查询到元素返回的就是一个空集合,而不是 null。否则调用方得去做 NULL 判断,多数场景下对于对象也是如此。

映射数据库的属性尽量不要用基本类型

我们都知道 int/long 等基本数据类型作为成员变量默认值是 0。现在流行使用 mybatisplus 、mybatis 等 ORM 框架,在进行插入或者更新的时候很容易会带着默认值插入更新到数据库。我特么真想砍了之前的开发,重构的项目里面实体类里面全都是基本数据类型。当场裂开......

封装判断条件

public void method(LoanAppEntity loanAppEntity, long operatorId) {
  if (LoanAppEntity.LoanAppStatus.OVERDUE != loanAppEntity.getStatus()
          && LoanAppEntity.LoanAppStatus.CURRENT != loanAppEntity.getStatus()
          && LoanAppEntity.LoanAppStatus.GRACE_PERIOD != loanAppEntity.getStatus()) {
    //...
    return;
  }
复制代码

这段代码的可读性很差,这 if 里面谁知道干啥的?我们用面向对象的思想去给 loanApp 这个对象里面封装个方法不就行了么?

public void method(LoanAppEntity loan, long operatorId) {
  if (!loan.finished()) {
    //...
    return;
  }
复制代码

LoanApp 这个类中封装一个方法,简单来说就是这个逻辑判断细节不该出现在业务方法中。

/**
 * 贷款单是否完成
 */
public boolean finished() {
  return LoanAppEntity.LoanAppStatus.OVERDUE != this.getStatus()
          && LoanAppEntity.LoanAppStatus.CURRENT != this.getStatus()
          && LoanAppEntity.LoanAppStatus.GRACE_PERIOD != this.getStatus();
}
复制代码

控制方法复杂度

推荐一款 IDEA 插件 CodeMetrics ,它能显示出方法的复杂度,它是对方法中的表达式进行计算,布尔表达式,if/else 分支,循环等。

优秀的后端应该有哪些开发习惯?

 

点击可以查看哪些代码增加了方法的复杂度,可以适当进行参考,毕竟我们通常写的是业务代码,在保证正常工作的前提下最重要的是要让别人能够快速看懂。当你的方法复杂度超过 10 就要考虑是否可以优化了。

使用 @ConfigurationProperties 代替 @Value

之前居然还看到有文章推荐使用 @Value 比 @ConfigurationProperties 好用的,吐了,别误人子弟。列举一下 @ConfigurationProperties 的好处。

  • 在项目 application.yml 配置文件中按住 ctrl + 鼠标左键点击配置属性可以快速导航到配置类。写配置时也能自动补全、联想到注释。需要额外引入一个依赖 org.springframework.boot:spring-boot-configuration-processor 。
优秀的后端应该有哪些开发习惯?

 

  • @ConfigurationProperties 支持 NACOS 配置自动刷新,使用 @Value 需要在 BEAN 上面使用 @RefreshScope 注解才能实现自动刷新
  • @ConfigurationProperties 可以结合 Validation 校验,@NotNull、@Length 等注解,如果配置校验没通过程序将启动不起来,及早的发现生产丢失配置等问题。
  • @ConfigurationProperties 可以注入多个属性,@Value 只能一个一个写
  • @ConfigurationProperties 可以支持复杂类型,无论嵌套多少层,都可以正确映射成对象

相比之下我不明白为什么那么多人不愿意接受新的东西,裂开......你可以看下所有的 springboot-starter 里面用的都是 @ConfigurationProperties 来接配置属性。

推荐使用 lombok

当然这是一个有争议的问题,我的习惯是使用它省去 getter、setter、toString 等等。

不要在 AService 调用 BMapper

我们一定要遵循从 AService -> BService -> BMapper,如果每个 Service 都能直接调用其他的 Mapper,那特么还要其他 Service 干嘛?老项目还有从 controller 调用 mapper 的,把控制器当 service 来处理了。。。

尽量少写工具类

为什么说要少写工具类,因为你写的大部分工具类,在你无形中引入的 jar 包里面就有,String 的,Assert 断言的,IO 上传文件,拷贝流的,Bigdecimal 的等等。自己写容易错还要加载多余的类。

不要包裹 OpenFeign 接口返回值

搞不懂为什么那么多人喜欢把接口的返回值用 Response 包装起来......加个 code、message、success 字段,然后每次调用方就变成这样

CouponCommonResult bindResult = couponApi.useCoupon(request.getCustomerId(), order.getLoanId(), coupon.getCode());
if (Objects.isNull(bindResult) || !bindResult.getResult()) {
  throw new AppException(CouponErrorCode.ERR_REC_COUPON_USED_FAILED);
}
复制代码

这样就相当于

  1. 在 coupon-api 抛出异常
  2. 在 coupon-api 拦截异常,修改 Response.code
  3. 在调用方判断 response.code 如果是 FAIELD 再把异常抛出去......

你直接在服务提供方抛异常不就行了么。。。而且这样一包装 HTTP 请求永远都是 200,没法做重试和监控。当然这个问题涉及到接口响应体该如何设计,目前网上大多是三种流派

  • 接口响应状态一律 200
  • 接口响应状态遵从HTTP真实状态
  • 佛系开发,领导怎么说就怎么做

不接受反驳,我推荐使用 HTTP 标准状态。特定场景包括参数校验失败等一律使用 400 给前端弹 toast。下篇文章会阐述一律 200 的坏处。

写有意义的方法注释

这种注释你写出来是怕后面接手的人瞎么......

/**
* 请求电话验证
*
* @param credentialNum
* @param callback
* @param param
* @return PhoneVerifyResult
*/
复制代码

要么就别写,要么就在后面加上描述......写这样的注释被 IDEA 报一堆警告看着蛋疼

和前端交互的 DTO 对象命名

什么 VO、BO、DTO、PO 我倒真是觉得没有那么大必要分那么详细,至少我们在和前端交互的时候类名要起的合适,不要直接用映射数据库的类返回给前端,这会返回很多不必要的信息,如果有敏感信息还要特殊处理。

推荐的做法是接受前端请求的类定义为 XxxRequest,响应的定义为 XxxResponse。以订单为例:接受保存更新订单信息的实体类可以定义为 OrderRequest,订单查询响应定义为 OrderResponse,订单的查询条件请求定义为 OrderQueryRequest。

尽量别让 IDEA 报警

我是很反感看到 IDEA 代码窗口一串警告的,非常难受。因为有警告就代表代码还可以优化,或者说存在问题。 前几天捕捉了一个团队内部的小bug,其实本来和我没有关系,但是同事都在一头雾水的看外面的业务判断为什么走的分支不对,我一眼就扫到了问题。

优秀的后端应该有哪些开发习惯?

 

因为 java 中整数字面量都是 int 类型,到集合中就变成了 Integer,然后 stepId 点上去一看是 long 类型,在集合中就是 Long,那这个 contains 妥妥的返回 false,都不是一个类型。

你看如果注重到警告,鼠标移过去看一眼提示就清楚了,少了一个生产 bug。

尽可能使用新技术组件

我觉得这是一个程序员应该具备的素养......反正我是喜欢用新的技术组件,因为新的技术组件出现必定是解决旧技术组件的不足,而且作为一个技术人员我们应该要与时俱进~~ 当然前提是要做好准备工作,不能无脑升级。举个最简单的例子,Java 17 都出来了,新项目现在还有人用 Date 来处理日期时间...... 都什么年代了你还在用 Date

结语

本篇文章简单介绍我日常开发的习惯,当然仅是作者自己的见解。暂时只想到这几点,以后发现其他的会更新。

如果这篇文章对你有帮助,记得点赞加关注!你的支持就是我继续创作的动力!

 

作者:暮色妖娆丶
链接:
https://juejin.cn/post/7072252275002966030



Tags:后端   点击:()  评论:()
声明:本站部分内容及图片来自互联网,转载是出于传递更多信息之目的,内容观点仅代表作者本人,不构成投资建议。投资者据此操作,风险自担。如有任何标注错误或版权侵犯请与我们联系,我们将及时更正、删除。
▌相关推荐
网站开发中的前端和后端开发有什么区别
前端开发和后端开发都是干什么的?有哪些区别?通俗地讲,前端干的工作是用户可以直接看得见的,而后端开发的工作主要在服务端,用户不太能直接看到。虽然前端开发和后端开发的工作有...【详细内容】
2024-02-21  Search: 后端  点击:(37)  评论:(0)  加入收藏
网站程序开发中的前后端分离技术
随着互联网的快速发展和技术的不断创新,传统的网站开发模式已经难以满足日益增长的业务需求。为了提高开发效率、增强系统的可维护性和可扩展性,前后端分离技术逐渐成为了网站...【详细内容】
2024-01-31  Search: 后端  点击:(27)  评论:(0)  加入收藏
一段微信小程序前端与后端连接的代码,带注解
微信小程序的前端和后端连接通常涉及到使用微信小程序提供的网络请求API与后端服务器进行通信。以下是一个简单的示例,展示如何使用微信小程序的前端代码向后端发送请求并处...【详细内容】
2024-01-24  Search: 后端  点击:(58)  评论:(0)  加入收藏
Java后端+Java大数据+前端
web前端开发主要涉及创建网页或网站的用户界面,包括布局、样式、动画、交互等。web前端开发需要掌握HTML、CSS、JavaScript等基础语言,以及各种框架和库,如React、Vue、Bootstr...【详细内容】
2023-12-28  Search: 后端  点击:(111)  评论:(0)  加入收藏
前端请求到后端API的中间件流程解析
在前端请求到后端API的典型流程中,经过一系列中间件的处理,确保请求的顺利处理和安全性。以下是中间件的详细解析:1. 前端请求用户在前端发起请求,包括请求的URL、参数、以及其...【详细内容】
2023-12-06  Search: 后端  点击:(125)  评论:(0)  加入收藏
运动规划之搜索算法:前端规划、后端轨迹生成到状态求解
背景:16-18年做过一阵子无人驾驶,那时候痴迷于移动规划;然而当时可学习的资料非常少,网上的论文也不算太多。基本就是Darpa的几十篇无人越野几次比赛的文章,基本没有成系统的文章...【详细内容】
2023-11-30  Search: 后端  点击:(119)  评论:(0)  加入收藏
Java后端开发需要学什么?这篇干货送给你
在现如今的互联网时代,掌握了编程技术,机遇就会变多,Java作为应用广泛的编程语言,在编程届有着很高的名气,如果你想学习Java,就先要了解Java后端开发需要学习什么!Java后端开发需要...【详细内容】
2023-11-24  Search: 后端  点击:(232)  评论:(0)  加入收藏
2024年不容错过的后端与网页开发新动态
在数字创新不断变化的领域中,作为开发者,你可能会感到自己处于一场永无止境的竞赛之中,面临着挑战和机遇的旋风。开发产品的压力、保持竞争力、跟上用户期望的演变,这些都可能让...【详细内容】
2023-11-24  Search: 后端  点击:(223)  评论:(0)  加入收藏
为什么Go是后端开发的未来
近年来,Go 编程语言的流行度迅速增加。Go 最初由 Google 开发,迅速成为后端开发中最受欢迎的语言之一,特别是在分布式系统和微服务的开发中。本文将讨论为什么 Go 是后端开发的...【详细内容】
2023-11-21  Search: 后端  点击:(207)  评论:(0)  加入收藏
Spring Boot + Vue3 前后端分离 实战wiki知识库系统
下栽の地止:https://www.itwangzi.cn/2508.html Spring Boot + Vue3 前后端分离 实战wiki知识库系统在当今的Web应用开发中,前后端分离已经成为了一种主流的开发模式。Spring...【详细内容】
2023-11-18  Search: 后端  点击:(147)  评论:(0)  加入收藏
▌简易百科推荐
全球首个AI程序员Devin造假?业内人士:质疑有理,但程序员已离不开AI
·号称全球首个AI人工智能软件师Devin日前被网络博主质疑造假、炒作。业内人士分析认为,该位博主质疑有理有据,Devin的“惊人效果”确实存在一些商业炒作的嫌疑。号称“...【详细内容】
2024-04-17    澎湃新闻  Tags:AI程序员   点击:(2)  评论:(0)  加入收藏
李彦宏:以后只要会说话,就可以成为一名开发者
中新网4月16日电(中新财经记者 吴涛)“AI正在掀起一场创造力革命,未来开发应用就像拍个短视频一样简单,只要会说话,就可以成为一名开发者,以后人人都是开发者、创造者。”16日,百...【详细内容】
2024-04-17    中国新闻网  Tags:李彦宏   点击:(2)  评论:(0)  加入收藏
雷军:10年编程路,给程序员的几点建议
随着小米SU7的火热发售,雷军凭借“跨界灭霸”称号又一战封神。作为中国互联网历史上极富传奇色彩的连续创业者,他向大家生动地诠释了“人生在于奋斗”的真谛。雷军作为中国第...【详细内容】
2024-04-15    dbaplus社群  Tags:雷军   点击:(5)  评论:(0)  加入收藏
首个AI程序员造假被抓,Devin再次“震撼”硅谷!扒皮视频文字详解附上
白交 衡宇 发自 凹非寺量子位 | 公众号 QbitAI首个AI程序员,演示视频大幅度造假???不久之前震撼硅谷的Devin,再度震撼硅谷——但这次是被打假。事情是这样的:油管程序员...【详细内容】
2024-04-14    量子位  Tags:AI程序员   点击:(1)  评论:(0)  加入收藏
AI程序员上岗 垂类大模型应用迎来井喷期
能自动写代码的“AI员工”、逐渐告别不够好用的智能客服,无需费时费力开发的工业AI控制器……随着人工智能大模型能力开始深入多个行业,IT、工业生产、金融、服务...【详细内容】
2024-04-07    千龙网  Tags:AI程序员   点击:(5)  评论:(0)  加入收藏
首个AI程序员上岗,码农们暂且不必过度焦虑
“AI程序员上岗”或许是噱头,但淘汰焦虑仍然近在咫尺,需要积极面对。全文2418字,阅读约需7分钟 撰稿 / 马尔文(媒体人)编辑 / 何睿 校对 / 张彦君▲随着相关技术的突飞猛进,AI也在...【详细内容】
2024-04-07    新京报  Tags:AI程序员   点击:(6)  评论:(0)  加入收藏
为何大语言模型不会取代码农?
译者 | 布加迪审校 | 重楼生成式人工智能(GenAI)会取代人类程序员吗?恐怕不会。不过,使用GenAI的人类可能会取代程序员。但是如今有这么多的大语言模型(LLM),实际效果不一而足。如...【详细内容】
2024-03-21    51CTO  Tags:大语言模型   点击:(27)  评论:(0)  加入收藏
AI程序员Devin:通过了面试,但不一定适合职场
昨天,AI圈上演了第一场“大男主爽文”:一个少年成名的编程天才,组建起仅有10人的编程界奥林匹克“梦之队”,在全球瞩目的科技风暴正中心创办了一家公司。成立不到两个月,其推出的...【详细内容】
2024-03-18    甲子光年  Tags:AI程序员   点击:(17)  评论:(0)  加入收藏
微软AI程序员登场,10倍AI工程师真来了?996自主生成代码,性能超GPT-4 30%
新智元报道编辑:桃子 润【新智元导读】全球首个AI程序员Devin诞生之后,让码农纷纷恐慌。没想到,微软同时也整出了一个AI程序员——AutoDev,能够自主生成、执行代码等...【详细内容】
2024-03-18    新智元  Tags:AI程序员   点击:(23)  评论:(0)  加入收藏
李彦宏称程序员职业将不复存在,周鸿祎:程序员热十年内不会减弱,AI时代更需要程序员
李彦宏称程序员职业将不复存在,周鸿祎:程序员热十年内不会减弱,AI时代更需要程序员3月10日,360创始人周鸿祎在社交平台上发文称,“大模型将替代程序员?未来不用学编程了么?我认为,程...【详细内容】
2024-03-11    九派新闻  Tags:程序员   点击:(33)  评论:(0)  加入收藏
站内最新
栏目相关
站内热门
站内头条