毕业五年经验分享:优秀后端开发程序员应具备的开发习惯

2024-11-18
来源:网络整理

前言

毕业已经五年多了,一共工作过3家公司。我见过各种各样的同事,见过各种各样的代码。有的优雅、赏心悦目,有的则垃圾如山。因此,我写这篇文章来记录一个优秀的后端开发程序员应该具备哪些良好的开发习惯。

1.评论尽量全面,写出有意义的评论

接口方法、类和复杂的业务逻辑都应该添加有意义的注释。

清晰的注释更有利于后续维护。

2、将项目拆分成合理的目录结构

记得上大学的时候,刚学会搭建各种管理系统,都是用的MVC模式,就是,,,。如果你以后的业务扩展了,如果你不拆分业务结构,你很可能会发现一个包下有上百个服务。 。 。

正确的做法是,如果服务太多,就应该根据不同的业务进行划分,比如订单、登录、积分等。

当然,你也可以根据不同的业务来划分模块,比如构建一个包,然后根据订单、登录等业务来划分。每个企业都有自己的,,,。

我们拆分的目的是让项目结构更清晰、可读性更强、更易于维护。

3、不要循环进行远程调用或数据库操作,优先进行批量操作。

远程操作或者数据库操作会消耗网络和IO资源,所以尽量不要循环调用远程或者循环操作数据库。如果可以一次批量检查回来,尽量不要循环检查多次。 (不过如果是操作数据库的话,不要一次查太多数据,可以分批500次进行)。

正面例子:

remoteBatchQuery(param);

反例:

for(int i=0;i
  remoteSingleQuery(param)
}

4.封装方法参数

如果您的方法有太多参数,请封装一个对象。反例如下:

public void getUserInfo(String name,String age,String sex,String mobile,String idNo){
  // do something ...
}

如果参数较多,处理新旧接口的兼容就会很麻烦。建议写一个对象,如下:

public void getUserInfo(UserInfoParamDTO userInfoParamDTO){
  // do something ...
}

class UserInfoParamDTO{
  private String name;
  private String age; 
  private String sex;
  private String mobile;
  private String idNo;
}

5.封装通用模板

一个优秀的后端开发人员应该具备封装通用模板的编码能力。

我们来看一个业务需求:假设我们有这样一个业务场景:内部系统中的不同商户调用我们的系统接口与外部第三方系统进行交互(http方法)。请遵循与此类似的过程,如下所示:

请求将经过以下过程:

通过HTTP发送请求时,有些商户可能会使用代理,而另一些商户可能会使用直连。假设商户A和商户B当前已连接。许多合作伙伴可能会实施这一点。伪代码如下:


// 商户A处理句柄
CompanyAHandler implements RequestHandler {
   Resp hander(req){
   //查询商户信息
   queryMerchantInfo();
   //加签
   signature();
   //http请求(A商户假设走的是代理)
   httpRequestbyProxy()
   //验签
   verify();
   }
}
// 商户B处理句柄
CompanyBHandler implements RequestHandler {
   Resp hander(Rreq){
   //查询商户信息
   queryMerchantInfo();
   //加签
   signature();
   // http请求(B商户不走代理,直连)
   httpRequestbyDirect();
   // 验签
   verify(); 
   }
}

假设新增一个C商户接入,则需要再实现一套这样的代码。显然,这段代码是重复的。这时候我们就可以封装一个通用模板了!我们可以定义一个抽象类,其中包含请求处理的几个方法。伪代码如下:


abstract class AbstractMerchantService  { 

     //模板方法流程
     Resp handlerTempPlate(req){
           //查询商户信息
           queryMerchantInfo();
           //加签
           signature();
           //http 请求
           httpRequest();
           // 验签
           verifySinature();
     }
      // Http是否走代理(提供给子类实现)
      abstract boolean isRequestByProxy();
}

那么所有连接的商户都会经历这个过程。如果你把这个通用模板提取出来,其他朋友接到开发任务,都会访问你的模板,是不是有点小自豪,哈哈~

封装一个通用模板,难道只是一个模板模式吗?其实不只是,而是我自己对需求和代码的思考和总结,是编程思想的升华。

6.封装复杂的逻辑判断条件

我们看一下这段代码:

    public void test(UserStatus userStatus){
        if (userStatus != UserStatus.BANNED && userStatus != UserStatus.DELETED && userStatus != UserStatus.FROZEN) {
            //doSomeThing
            return
        }
    }

微信红包小程序开发_红包软件平台开发_小程序红包配置及开发小结

这段代码有什么问题?是的,逻辑判断条件太复杂了,我们可以封装一下。如下:

    public void test(UserStatus userStatus){
        if (isUserActive(userStatus)) {
            //doSomeThing
        }
    }

    private boolean isUserActive(UserStatus userStatus) {
        return userStatus != UserStatus.BANNED && userStatus != UserStatus.DELETED && userStatus != UserStatus.FROZEN;
    }

7. 密切关注优化性能

优秀的后端开发应该保持优化性能的意识。例如,避免创建不必要的对象、异步处理、使用缓冲流、减少 IO 操作等。

比如我们为某个APP的首页设计一个界面,需要查看用户信息、信息、弹窗信息等,假设耗时如下:

检查用户信息、检查信息、检查弹出信息耗时50ms,总共耗时。如果还查其他资料,那就更费时间了。如何优化呢?可以并行发起,耗时可以降到0。如下:

8. 可变参数的配置处理

在日常开发中,我们经常会遇到一些可变参数,比如用户多少天没有登录或注销、操作活动、不同节假日切换红包皮肤、订单多久不付款被删除等等等,对于这些可变参数,不需要直接写到代码中。对于一个优秀的后端,如果你想配置它,你可以把这些可变参数放在数据库的一个配置表中,也可以放在项目的配置文件中或者服务器上。

比如产品经理要红包。圣诞节期间,红包皮肤应该是与圣诞节相关的,春节期间,红包皮肤应该是春节红包皮肤等等。如果控件是硬编码的,可以有类似下面的代码:

if(duringChristmas){
   img = redPacketChristmasSkin;
}else if(duringSpringFestival){
   img =  redSpringFestivalSkin;
}

如果元宵节期间,运营小姐姐突然有想法要把红包皮肤改成和灯笼相关的东西,这个时候我是不是应该修改代码重新发布呢?

从界面设计开始,就可以实现一个红包皮肤配置表。让红包皮肤可配置怎么样?更换红包皮肤只需要修改表格数据即可。当然,也有一些场景适合一些可配置的参数:控制的页面数量、某个红包需要多长时间过期等等,都可以包含在参数配置表中。这也是可扩展性思维的体现。

9、能够总结和使用工具。

很多朋友,判断一个列表是否为空,会这样写:

if (list == null || list.size() == 0) {
  return null;
}

这样写的话逻辑上并没有什么问题。但更推荐使用工具类,比如:

if (CollectionUtils.isEmpty(list)) {
   return null;
}

在日常开发中,我们不仅要会使用工具类,还要学会自己总结工具类。比如去文件处理工具类,日期处理工具类等等,这些都是一些好的后端开发的好习惯。

10.控制方法功能复杂度

你的方法不应该太复杂,逻辑不应该混乱,也不应该太长。一个函数不能超过 80 行。写代码不仅仅是为了运行,也是为了以后更好的维护。

反例如下:

public class Test {
    private String name;
    private Vector orders = new Vector();

    public void printOwing() {
        //print banner
        System.out.println("****************");
        System.out.println("*****customer Owes *****");
        System.out.println("****************");

        //calculate totalAmount
        Enumeration env = orders.elements();
        double totalAmount = 0.0;
        while (env.hasMoreElements()) {
            Order order = (Order) env.nextElement();
            totalAmount += order.getAmout();
        }

        //print details
        System.out.println("name:" + name);
        System.out.println("amount:" + totalAmount);
        ......
    }
}

其实可以用它来提取单个函数的代码段,形成名称清晰的小函数,来解决函数过长的问题,如下所示:

public class Test {
    private String name;
    private Vector orders = new Vector();

    public void printOwing() {

        //print banner
        printBanner();
        //calculate totalAmount
        double totalAmount = getTotalAmount();
        //print details
        printDetail(totalAmount);
    }

    void printBanner(){
        System.out.println("****************");
        System.out.println("*****customer Owes *****");
        System.out.println("****************");
    }

    double getTotalAmount(){
        Enumeration env = orders.elements();
        double totalAmount = 0.0;
        while (env.hasMoreElements()) {
            Order order = (Order) env.nextElement();
            totalAmount += order.getAmout();
        }
        return totalAmount;
    }

    void printDetail(double totalAmount){
        System.out.println("name:" + name);
        System.out.println("amount:" + totalAmount);
    }   
}

11.释放块内资源

大家一定都有过这样的经历。如果系统桌面上打开的文件或系统软件太多,电脑就会感觉卡住。当然,我们的服务器也是如此。如果我们平时操作文件或者数据库连接,如果不关闭IO资源流,那么IO资源就会被它占用,这样其他人就无法使用,就会造成资源的浪费。

当我们操作文件资源后,我们需要释放块中的资源。

FileInputStream fdIn = null;
try {
    fdIn = new FileInputStream(new File("/公众号_捡田螺的小男孩.txt"));
} catch (FileNotFoundException e) {
    log.error(e);
} catch (IOException e) {
    log.error(e);
}finally {
    try {
        if (fdIn != null) {
            fdIn.close();
        }
    } catch (IOException e) {
        log.error(e);
    }
}

12.打印日志

日常开发中,必须要打印日志。比如:你实现了一个转账业务,转账几百万,然后转账失败,然后客户投诉,然后你还没有打印到日志中。想想水深火热,自己却无计可施。 。 。

一般来说,方法的输入输出参数都需要打印日志。当发生异常时,还必须打印日志等,如下:

public void transfer(TransferDTO transferDTO){
    log.info("invoke tranfer begin");
    //打印入参
    log.info("invoke tranfer,paramters:{}",transferDTO);
    try {
      res=  transferService.transfer(transferDTO);
    }catch(Exception e){
     log.error("transfer fail,account:{}",
     transferDTO.getAccount())
     log.error("transfer fail,exception:{}",e);
    }
    log.info("invoke tranfer end");
    }

13.考虑异常情况并妥善处理

优秀的后端开发应该考虑异常并处理好。天罗哥给你10条异常处理建议:

14.考虑系统和接口兼容性

优秀的后端开发会考虑系统和接口的兼容性。

红包软件平台开发_微信红包小程序开发_小程序红包配置及开发小结

如果对旧的外部接口进行修改,但不兼容。这个问题可能很严重,甚至可能直接导致系统无法发布。新手程序员很容易犯这个错误~

因此,如果你的需求是修改原来的接口,特别是这个接口对外提供服务,就必须考虑接口的兼容性。例如,如果接口原本只接收参数A和B,但现在添加了参数C,则可以考虑这样处理:

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

//新接口,暂时不能删掉老接口,需要做兼容。
void newService(A,B,C){
  ...
}

15.采取措施避免运行时错误

优秀的后端开发应该在编码阶段采取措施避免运行时错误,例如数组边界溢出、被零除、空指针等运行时错误。类似的代码比较常见:

String name = list.get(1).getName(); //list可能越界,因为不一定有2个元素哈

因此,应采取措施防止数组边界溢出,例如:

if(CollectionsUtil.isNotEmpty(list)&& list.size()>1){
  String name = list.get(1).getName(); 
}

欢迎扫描二维码加入如源技术交流群。每天晚上20:00,会有Java访谈、Java架构等技术问答分享。您还可以与朋友交流技术。

我们还向您推荐乳源课堂的1元系列课程。欢迎大家加入我们,共同学习~

互联网Java工程师面试惊喜课程

(1元专享)

从零基础入门到项目实践

(1元专享)

亿级流量下的电商详情页系统实战项目

(1元专享)

消息中间件内核源码详解

(1元专享)

12个实用案例助你掌握Java并发编程

(1元专享)

从初学者到精通

(1元专享)

基于Java的手写分布式中间件系统实战

(1元专享)

基于的分库分表实践课程

(1元专享)

分享