工作三年后, 我作为Java后端开发的一些心得

工作三年后, 我作为Java后端开发的一些心得

关于开发

敢于和善于使用package

  • 对于Java后端开发来讲, 在长时间的web开发中. 大家已经熟悉了MVC架构, 也被这套结构所束缚. 导致创建出来的包也一直都是controller, manager, service, dao. 也将各种各样的类文件都放入其中. 这并不是一种好的做法.
  • 其实我们可以大胆的创建相关的package, 只要让结构更合理, 可读性更高.
  • 比如可以把对接前端的类写到request, response包; 把一些处理器提取出来放到handler中, 把一些定时任务放到schedule包; 把参数构造相关的放到generator; 把校验相关的放到validator下等等.

合理的提取业务逻辑, 让方法只做和它相关的事情.

  • 不知道大家是否看到过下面这种代码. 例如在一个单据的创建方法中, 做一系列的事情, 比如一坨校验参数逻辑, 一堆取价逻辑, 一堆扣减库存逻辑, 再加上创建单据本身的逻辑. 写下来一个方法上百行不止.

  public class OrderManager {

    @Autowired 
    private OrderService orderService;

    public String createOrder(Request request){
      // 1. 检查单据创建参数是否合法
      if(Objects.isNull(request)) {
        throw ....;
      }
      if(CollectionUtils.isEmpty(request.getGoodsList())){
        throw ...;
      }
      ... 

      // 获取商品的价格
      List<Goods> goodsList = request.getGoods();
      goodsList.forEach(goods -> {
        // 查询商品价格

        // 校验价格
        
        // 对价格进行填充
        
      });
       
      // 构造单据逻辑
      
      // 创建单据

      return orderCode;
    }
  } 
  • 这个方法里做的事, 没有多余的事情, 但是没有合理的进行业务逻辑的提取. 导致代码看起来非常的杂乱.我们可以对一些业务逻辑做提取封装. 来的到更好的可读性和解耦. 这只是一个简单的例子, 在复杂的业务逻辑里更需要合理提取, 否则屎山就出现了.

  public class OrderManager {

    @Autowired 
    private OrderService orderService;

    @Autowired
    private OrderValidator orderValidator;

    @Autowired
    private OrderGenerator orderGenerator;
    
    @Autowired
    private PriceService priceService;

    @Autowired
    private InventoryService inventoryService;

    public String createOrder(Request request){
      // 1. 检查单据创建参数是否合法
      this.orderValidator(request);

      // 获取商品的价格
      this.priceService(request.getGoods());
       
      // 构造单据逻辑
      Order order = this.orderGenerator.generator(request);
      
      // 创建单据
      this.orderService.create(order);
      return order.getOrderCode();
    }
  } 

合理的方法命名和方法定义

  • 方法名的定义很令人苦恼, 常常思前想后想不到好名字. 我曾经因为方法命名不好, 被疯狂的comments

  • 方法命名的好坏受个人主观影响, 所以只说几个共同点:

    1. 言简意赅 准确表达方法内容
    2. 方法名与方法内容匹配
    3. 尽量别生僻单词...
  • 对于方法的参数, 参数过多的时候, 对方法进行拆解或者抽象出对象去传参:

  // 错误的案例
  public int setParam(int xxx, String xxx, String xxx, String xxx, String xxx, int xxx, String xxx, String xxx){
    ... 
  }

  // 合理的写法
  public int setParam(XxxRequest request) {

  }

控制方法的圈复杂度, 让代码更有层次感

  • 我一直觉得, 好的代码读起来应该像故事一样, 有前因, 有后果, 中间娓娓道来. 简单举个例子, 我们可能会遇到在方法中去for循环处理数据的情况. 比如在一个方法中, 套了三层循环.

  List<String> orderCodeList = request.getOrderCodes();

  // 第一层循环
  for(String orderCode : orderCodeList){

    // 查询单号对应的单据明细
    List<OrderItem> items = this.orderItemService.getByCode(orderCode);
    // 第二层循环
    for(OrderItem item : items) {
      // 执行操作1
      // 执行操作2
      // 执行操作3
      
      // 第三层循环
      for()
    }
  }
  • 可以把每一层for循环都提取出来, 成为单独的一个方法, 来降低圈复杂度, 提高可读性

  List<String> orderCodeList = request.getOrderCodes();

  // 第一层循环
  for(String orderCode : orderCodeList){
    this.processSingleOrder(orderCode);
  }

  public void processSingleOrder(String orderCode){
    // 查询单号对应的单据明细
    List<OrderItem> items = this.orderItemService.getByCode(orderCode);
    this.processItemsData(items);
  }

  public void processItemsData(){
    for(OrderItem item : items) {
      // 执行操作1
      // 执行操作2
      // 执行操作3
    }
  }

不知道的知识可以去问问Google, 不要自己编

  • 不知道标题是否贴切, 但是大家看了例子就会明白我的意思.

  • 其中最为典型的例子我认为 是对Obejct和集合的判空 和 创建集合

  // 对于判断, 很多人喜欢这样写
  if( list == null || list.size == 0) 
  或者 
  if(order == null)

  // 对于创建集合, 去创建空集合, 再添加
  List<String> list = new ArrList();
  list.add("xxx");
  list.add("bbb");
  • 其实只要我们Google以下, Java下如何对集合判空, 就能看到apache.commons 或者google.common等很多类库已经包含这些内容, 并且实现的更严谨, 更优美. 要请善于使用搜索引擎去填补自己不了解的知识.

  CollectionUtils.isEmpty(list);

  List<String> list = Lists.newArrayList("xxx", "bbb");

不要for循环请求数据库和外部系统接口

  • 慢请求的分析, 可能不需要要先去看有没有复杂的关联查询, 或者是不是数据库查询有没有命中索引, 而是先去看是不是有大哥在for循环去请求数据库和dubbo接口. 循环了1w次. 我曾经遇到过多次请求超时都是因为有人在代码里for循环去select , update.
  • 对于这种问题的解决, 将循环调用改成单次的批量接口就可以解决问题. 对于mysql的化in操作就可以解决, 对于外部系统对接的, 双方提供批量接口就可以了.

没有意义的注释不要写

  • 我很反感在类上要先写上 @Author @Date @Description 一大串内容表明这是你的杰作, 这不是JDK 也不是什么开源项目!!! 除了你和你的同事没人去看.

  • 再或者像下面这样在方法上直白翻译了一堆废话, 注释不是这么用的...

  /**
   * 查询用户名称
   *
   * @Param name:用户名
   * @Return 用户
   */
  public User getByName(String name);

不要忽视UnitTest

  • 写过单元测试的会发现, 编写完善的单元测试会占用大量的时间, 一般都会超过需求的开发时间, 但是我还是认为单元测试是必须且重要的. 因为作为研发人员, 才是最了解代码中哪里容易出问题的. 更容易写出发现问题的测试用例. 并且代码迭代或者修改后, 也能更快速的发现问题, 将问题停留在研发阶段去解决, 提高整体的进度.

善于使用AI编程工具

  • 在我使用了Github copilot和ChatGPT半年后, 我发现我的摸鱼时间变多了... 因为AI编程工具帮我完成了一定量的工作. 例如最常用的代码补全, 代码自动生成, 自动生成单元测试等等
  • 在当今, 熟练掌握AI编程工具, 是提高自己工作效率的极佳的方法. 在未来, AI也一定会代替掉一部分程序员的工作.
  • [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-ONbgJ6nV-1690847312973)(C:\Users\quyanliang\AppData\Roaming\Typora\typora-user-images\1690847111862.png)]

利用IDE的工具来完成代码和优化代码

  • IDEA自带功能扫描代码无用引用, 重复代码等坏味道 : Code → Inspect Code

    SonarLint

    MyBatis Plus

    Lombok

    Alibaba Java Coding Guidelines

    CheckStyle-IDEA

    ...

拥抱新技术

  • 可能随着工作的时间变长, 大家对新鲜技术的兴趣并不像之前感兴趣. 或者认为目前的技术足够, 远不会过时, 即使过时了, 也会有公司使用.
  • 技术是不断迭代更新的, 使用技术的人也要随之更新. 当大家都去开始了解和使用云服务, 容器化, 使用JDK 17的新特性, 开始用云原生框架去替换现有技术时, 咱总不能一直玩转jdk 1.8吧.
  • 了解一些新技术并不是什么值得炫耀的, 不知道也不一定影响你工作和赚钱, 但是当互联网红利已经逐渐褪去, 内卷在越来越重的今天, 机会也变得弥足珍贵. 更好的知识储备, 也能让你能获得下一份工作, 在人才市场获得更多青睐.
  • 我也一直认为, 开发对很多人来说不光是工作, 也有着一份热爱.

关于处理工作和人际关系

开发并不只是开发

  • 这个标题就是字面意思, 指的并不是光顾忌自己的开发任务. 同时也要关注公司的运营和公司业务或者说自己负责的项目的业务.
  • 我见过一些程序员只是单纯的根据产品的文档写需求, 你需求怎么写, 我功能就怎么写. 但是研发在看待需求时, 应该持有自己的见解, 观点和建议. 这也就是需求评审的目的.
  • 不要觉得需求是产品提的, 和研发没有任何关系. 但是你需要考虑到, 当需求存在问题, 后续的需求优化, bug修复, 甚至数据处理, 可都是要由研发来做的. 简单来说, 错在产品, 但引发问题由你处理.
  • 而公司的运营, 关系到了你在公司的生存和发展, 所以关注着公司的运营情况, 也大概你知道你明年的涨薪是否有希望, 年终奖是否能按时发放, 以及你是否应该考虑换一个公司去继续搬砖.

合理的分配和安排自己的工作

  • 拿到需求不要急于开发, 不要急于开发, 不要急于开发.
  • 我见过一些开发, 在拿到需求后会马不停蹄的开始Coding, 然后就出现边写边改, 再写又发现哪里存在问题, 最后发现写不通, 推翻了之前的结构再写.
  • 这个可能并不适合所有人, 但是我认为在开始Coding之前, 是需要构思一下再着手的. 花一些时间分析一下这个需求, 考虑下设计到的各个部分, 构思下自己的开发思路, 设想下其中可能遇到的问题, 当思路清晰后, 再去着手开发, 这样会让你能够流畅的完成开发工作, 并且让你的代码质量更高.

对自己的工作要有Owner意识, 答应的事情要尽力去做到

  • 什么是工作的Owner意识, 简单来说, 就是这个工作分配给你, 你就是第一负责人.
  • 对于分配到自己手里的工作, 首先要有一个正确的评估. 可以简单的分为: 这个工作你能不能做, 能不能按时做完, 要怎么做, 最后能做到什么效果.
  • 如果因为种种原因做不到, 需要提前预报风险, 不要等到最后一刻告诉大家, 你没做到. 任务分配给你, 是因为这是你的工作, 也有一部分信任在, 是相信你可以做好, 别去辜负别人的信任, 信任可能因为一件事就确立起来, 也可能因为一件事情就毁掉.

我不管别人摸鱼, 但不要影响到我的工作

  • 工作难免偷懒, 大家都有想休息放松的时候. 我对这个事情的看法就是, 摸鱼可以, 但是不要影响别人的工作.
  • 在整个项目或者需求的流程里, 产品, 后端开发, 前端开发, 测试人员都只是其中的一环. 对于各个环节的人员来说, 都是这样, 可以适当摸鱼, 但是不要压缩了别人安排好的时间.

自己的问题勇于承认, 但不是我的锅我不背

  • 承认自己的问题并不是一个可耻的事情, 但是不承认被别人扒出来可是非常尴尬的.
  • 如果你不能按时完成开发任务, 可以说明你的原因, 尽快的提出来, 别等到最后到了Deadline你说你做不完.
  • 或者因为你的bug导致了线上事故, 也没必要遮遮掩掩. 快速的定位问题, 解决问题, 在会议上复盘问题, 最好下次发生同样的状况就好, 也没必要因此给自己很大的心理压力和负担. 常在河边走, 哪有不湿鞋.
  • 但是, 对于甩锅这种问题, 没有人不反感. 我不去讨论什么叫甩锅, 我只去讨论怎么避免甩锅这种事情的发生.
    • 在对于需求, 会议, 形成良好的书面文档, 各方进行确认
    • 有问题避免天知地知你知我知, 有问题大家一起沟通, 沟通后形成相关的书面文档
    • 当出现这种问题的时候, 拿出自己的证据来证明自己, 不是老子的锅老子不背

摆正自己和领导的位置

  • 对于领导, 你是他的下属, 不管你们是酒友还是烟友或者是pao友, 你对他最重要的是工作的能力和处理问题的能力. 认真对待分配的任务, 做好自己的分内工作, 让他看到你对他在工作上的价值, 才是建立你们工作关系的基础.

合理的看待别人的反对和批评

  • 可能每一个参加工作的人都被批评过或者吐槽, 被领导也好, 被同事也好. 在面对批评时, 不要急于反驳. 大家作为成年人, 很少会有人毫无原因和根据的前提下去吐槽你的问题.
  • 他提出的问题, 可能就是你切实存在的问题, 他不说, 下一个人也会说, 尽早了解自己的问题并及时改掉不是坏事. 不能不在意, 也不要太在意.

如果你领导或者同事是sb

  • 能忍忍, 不能忍就滚. 你不能强迫别人走, 你忍不了, 你自己走.
相关推荐
奋斗的小花生1 小时前
c++ 多态性
开发语言·c++
魔道不误砍柴功1 小时前
Java 中如何巧妙应用 Function 让方法复用性更强
java·开发语言·python
NiNg_1_2341 小时前
SpringBoot整合SpringSecurity实现密码加密解密、登录认证退出功能
java·spring boot·后端
闲晨1 小时前
C++ 继承:代码传承的魔法棒,开启奇幻编程之旅
java·c语言·开发语言·c++·经验分享
老猿讲编程1 小时前
一个例子来说明Ada语言的实时性支持
开发语言·ada
Chrikk2 小时前
Go-性能调优实战案例
开发语言·后端·golang
幼儿园老大*2 小时前
Go的环境搭建以及GoLand安装教程
开发语言·经验分享·后端·golang·go
canyuemanyue2 小时前
go语言连续监控事件并回调处理
开发语言·后端·golang
杜杜的man2 小时前
【go从零单排】go语言中的指针
开发语言·后端·golang
测开小菜鸟2 小时前
使用python向钉钉群聊发送消息
java·python·钉钉