首页
开发技巧正文内容

4个小贴士极大提高源代码的可读性

2024年07月03日
阅读时长 3 分钟
阅读量 4
4个小贴士极大提高源代码的可读性

高质量软件的秘密食谱并不在编程课程中教授

一篇优秀的文章以一种让目标受众能够轻松理解和消化困难概念的方式呈现想法。编码与写文章并无二致。计算机程序代码不仅仅是一组指令和逻辑,供机器执行。软件工程师也是目标受众。

想象一下,一个天才软件工程师实现了一个高效而复杂的算法,遗憾的是,如果没有人能理解这段逻辑,那这段代码就是垃圾。尽管AI自动化的使用很普遍,但它还不足以完全接管整个软件开发和维护。换句话说,如今软件程序代码主要由人类维护。

因此,以一种良好组织和可读性强的格式编码是一项必不可少的技能,无论您是作为独立开发人员还是在开发团队中工作。人类可读性是决定代码质量的关键因素之一。

事实上,编写可读性强的代码的好处是巨大的。代码越容易阅读,人们就能越快地理解系统逻辑。因此,花费更少的时间和精力来构建或修改系统功能。最终,缩短上市时间,降低软件维护成本。

下面的示例代码是以一种老式风格编写的:

Employee employee = new Employee();
employee.setId(1);
employee.setName("Denis Rogers");
employee.setDepartment("FINANCE");
employee.setSalary(1500);

如果我们将上面的代码翻译成简单的英语句子,会是这样。这种表达方式笨拙而重复。如果要添加更多信息到员工记录中,阅读起来会更耗时:

创建一个新员工。 员工编号为1。 员工姓名为Denis Rogers。 员工所在部门为FINANCE。 员工的薪水为15000。

让我们看看相同设置的现代编码风格:

Employee employee = Employee.builder()
                            .id(1)
                            .name("Denis Rogers")
                            .department("FINANCE")
                            .salary(1500)
                            .build();

上面的编码风格流畅地呈现了新员工的每个属性。这种呈现格式类似于下面的英语简述。显然,这种编码风格消除了冗余代码,并更有效地呈现信息。

新员工的信息:

  • 编号:1
  • 姓名:Denis Rogers
  • 部门:FINANCE
  • 薪水:1500

为了帮助您将编码技能提升到更高水平,我将在本文中分享4个关于如何生成高质量且易读的代码的绝妙贴士。

贴士 #1 - 从高层流程开始

将所有内容都扔进一张幻灯片中会给您的受众提供大量信息。许多人认为这是一种有效的方式来传达您的想法并提供完整的上下文。这是许多演讲者犯的一个常见错误,他们将整个段落塞进一张幻灯片中,并假设读者/观众能够完全消化信息。事实是,由于信息过载,很少有人能够接收到您的信息。

设身处地为您的读者着想。如果一个人对特定领域没有任何知识,一次性理解一切是很困难的。

编程也是如此。假设理解系统逻辑的人没有任何背景知识。首先,引入整体图片是帮助您的读者理解高层流程的重要信息。

让我们做一个快速测试。如果给你3秒,你能告诉我下面示例代码中的系统逻辑吗?

public boolean openAccount(AccountOpeningRequest request) {

  if (StringUtils.isNotBlank(request.getCustomerName())
        && StringUtils.isNotBlank(request.getCustomerIdentityType())
        && StringUtils.isNotBlank(request.getCustomerIdentityNumber())
        && StringUtils.isNotBlank(request.getNationality())
        && StringUtils.isNotBlank(request.getCustomerAddress())) {

      if (request.getCustomerIdentityType().equalsIgnoreCase("DRIVER_LICENSE")
              && request.getCustomerIdentityNumber().length() != 9) {
          return false;
      }

      if (request.getNationality().equalsIgnoreCase("Arabia Terra")
          && request.getCustomerAddress().equalsIgnoreCase("Mars")) {
          return false;
      }

  } else {
      return false;
  }

  if (request.getAccountNumber().startsWith("099")) {
      if (!request.getNationality().equalsIgnoreCase("WONDERLAND")) {
          return false;
      }

      if (!request.getAccountType().equalsIgnoreCase("PENSION")) {
          return false;
      }

      amlService.checkForBlacklistedCustomer(request.getCustomerIdentity());
  }

  Customer customer = customerDao.retrieveCustomerByIdentity(
          request.getCustomerIdentityType(), request.getCustomerIdentityNumber());
  accountDao.insertAccount(new Account(request.getAccountNumber(), request.getAccountType(),
          customer.getId(), Instant.now()));

  if (request.getAccountNumber().startsWith("022")) {
        investmentService.registerInvestmentAccount(request);
 }

    return true;
}

放松,这不是编码测试练习。事实上,要理解整个系统逻辑需要时间,因为我们需要逐行阅读并弄清楚整个过程。

"总结"是一种常用于写作和编码的关键技术。

通过"总结"程序代码,整体流程更加清晰。详细逻辑被移入私有方法。不需要深入详细的系统逻辑,源代码研究变得更容易。如果要增加新的验证逻辑,怎么办?很简单,只需跳转到_validateRequest()_,而不必理会其余系统逻辑。

public boolean openAccount(AccountOpeningRequest request) {

   if (!validateRequest(request)) {
       return false;
   }

   if (!checkRequestForPensionAccountType(request)) {
       return false;
   }

   createNewAccount(request);
   handlingForInvestmentAccount(request);

   return true;
}

贴士 #2 - 用人类语言编码

注释是一种软件工程师将源代码中的系统逻辑解释给他人的文档。例如,下面的注释解释了带有前缀"099"的帐号是养老金帐号。

// 099前缀是养老金帐号
if (request.getAccountNumber().startsWith("099")) {

   if (!request.getNationality().equalsIgnoreCase("WONDERLAND")) {
       return false;
   }

   ...
   ...
}

在过去,程序员需要在源代码中编写注释作为编程任务的一部分,以帮助他人遵循系统流程。带有描述性注释的源代码被认为是高质量的。

如今,少即是多,一个可读性强的源代码少或无注释有趣地被认为是高质量的。

等等!如何在不写注释的情况下记录源代码中的逻辑?

有意义的方法和变量名称

使用人类语言的方法名称是回答这个问题的一个很酷的技巧。下面的示例代码对if语句进行了小调整。如果我们将帐号前缀检查移入名为_isPensionAccount()_的方法,代码逻辑将变得清晰且不言自明。任何想要了解确定养老金帐号逻辑的人都可以查看方法实现。

您的团队会喜欢您的源代码,因为它接近自然语言且易于阅读。

除了将逻辑封装到具有有意义名称的方法中,此技术也可以应用于变量名称。

if (isPensionAccount(request)) {

   if (!request.getNationality().equalsIgnoreCase("WONDERLAND")) {
       return false;
   }

   ...
   ...
}

有意义的比较

在进行值比较时,大多数编程语言都适用于原始数据类型,如整数和双精度。使用 >、=>、<、<= 和 == 这些运算符清楚地指示比较操作。

然而,这些运算符不能用于对象的比较。BigDecimal就是一个典型的例子。我们依赖于_compareTo()_来比较两个值。比较结果产生一个整数值。下面的示例代码解释了它的工作原理:

  • ZERO - 两个值相等

  • ZERO - 值A大于值B

  • < ZERO - 值A小于值B

void compareBigDecimal(BigDecimal valueA, BigDecimal valueB) {
   
    int result = valueA.compareTo(valueB);

   if (result == 0) {
       System.out.println("valueA等于valueB");
   } else if (result > 0) {
       System.out.println("valueA大于valueB");
   } else {
       System.out.println("valueA小于valueB");
   }
}

这实际上是低级编程语言(如C/C++)的继承。有时,人们会因为表达方式不符合人类语言而感到困惑并粗心地混淆结果。

Apache common lang3库提供了一个简单的技巧,使这种比较更易读。该库以流畅的方式提供以下方法调用。方法名称清晰描述,因此不会再有混淆和误解。

Dim isEqual As Boolean = is(valueA).equalTo(valueB)
Dim isGreater As Boolean = is(valueA).greaterThan(valueB)
Dim isGreaterThanOrEqualTo As Boolean = is(valueA).greaterThanOrEqualTo(valueB)
Dim isLess As Boolean = is(valueA).lessThan(valueB)
Dim isLessThanOrEqualTo As Boolean = is(valueA).lessThanOrEqualTo(valueB)

要在系统中包含 Apache common lang3 库,请将以下依赖项添加到 Maven 的 pom.xml 文件中:

<dependency>
 <groupId>org.apache.commons</groupId>
 <artifactId>commons-lang3</artifactId>
</dependency>

小贴士 #3 - 使用构建器模式构建对象

您可能已经了解了在本文开头演示的对象构建中的构建器模式。尽管在许多编程语言中使用构造函数是创建新对象的传统方式,但许多软件工程师发现随着要添加更多属性到构造函数中,代码变得更难理解。

让我们看看下面的示例代码,您能解释下面构造函数中每个属性的含义吗?

Employee employee = new Employee(1, "Denis Rogers", "FINANCE", 
                                 "Senior Officer", 
                                 LocalDate.parse("2020-02-28"), true, 
                                 new BigDecimal("15000"));

也许,您可以识别记录 ID、员工姓名、部门和职称。我猜没有人知道 "2020–02–28"、true 和 15000 是什么意思。

让我们用下面的构建器模式替换构造函数,现在所有属性都得到了清晰解释。没有歧义,避免混淆构造函数参数的机会。

Employee employee = Employee.builder()
                           .id(1)
                           .name("Denis Rogers")
                           .department("FINANCE")
                           .title("Senior Officer")
                           .employmentDate(LocalDate.parse("2020-02-28"))
                           .fullTime(true) 
                           .salary(new BigDecimal("15000"))
                           .build();

使用 Lombok 库 可以轻松完成构建器的样板代码,它会在字节码级别自动生成构建器模式。通过在下面的示例中使用 Lombok 的注解 @Builder, @Setter@Getter,它会自动生成 getter 和 setter 方法以及构建器模式。有关 Lombok 库的使用,请参阅 如何神奇地加快 Java 编码速度

@Builder
@Setter
@Getter
public class Employee {
   private int id;
   private String name;
   private String department;
   private String title;
   private LocalDate employmentDate;
   private boolean fullTime;
   private BigDecimal salary;
}

小贴士 #4 - 使用 ? 运算符简化逻辑分支

? 运算符是一个方便的辅助工具,可以简化变量赋值的分支逻辑。如果我们要实现一个新功能,在一个特性标志后面返回一个奖金金额。这是一个使用 if 语句的简单分支逻辑。

BigDecimal bonusAmount = BigDecimal.ZERO;

If (featureFlag) {
     bonusAmount = retrieveBonusAmount();
}

使用 ? 运算符使逻辑更整洁,因为读者能够找出变量 bonusAmount 的数据源,而无需导航 if 语句。对于更简单的情况,变量赋值可以用一行代码完成。

也许,这种小改变只是稍微提高了代码的可读性。这些小的改进累积起来,加快了软件工程师阅读数百甚至数千行代码的速度。

BigDecimal bonusAmount = featureFlag ? BigDecimal.ZERO 
                                     : retrieveBonusAmount();

总结思考

当您编写程序代码时,您不仅仅是在编写机器指令。源代码是一个不断演变和改进的活文档。将来可能会有人阅读和增强您的源代码。

您在源代码中呈现系统逻辑的方式会产生巨大影响。它影响其他人能够多快地吸收重要的系统逻辑。与文章写作类似,如果您以高效的方式呈现信息,您的受众将能够轻松理解您的想法。

由于系统逻辑清晰且易于理解,因此更容易调试,隐藏问题更少。这些是高质量源代码的关键因素。

免责声明:本站所有文章,如无特殊说明或标注,均为本站原创发布。任何个人或组织,在未征得本站同意时,禁止复制、盗用、采集、发布本站内容到任何网站、书籍等各类媒体平台。如若本站内容侵犯了原著者的合法权益,可联系我们进行处理。

相关文章

探索多种软件架构模式及其实用应用
2024年11月22日19:06
本文深入探讨了多种软件架构模式,包括有界上下文、边车模式、发布-订阅模式、应用网关、微服务、命令职责分离(CQRS)等,介绍了它们的优点、使用场景以及具体应用实例。文章强调根据具体项目需求和团队能力选择最合适的架构,以构建高效和可维护的解决方案,同时展示了各架构模式间的综合应用,提供了丰富的案例和技术细节。
15个高级Python快捷键助您更快编程
2024年11月21日07:02
本文分享了 15 个高级的 Python 编程快捷键,包括上下文管理器、行内字典合并、函数参数解包、链式比较、dataclasses、海象运算符、反转列表、备忘录缓存、splitlines、enumerate、字典推导、zip 用于并行迭代、itertools.chain 扁平化列表、functools.partial 部分函数和 os.path 文件路径管理等,帮助开发者提高编程效率和代码简洁性。
揭示网页开发的 11 个迷思:停止相信这些误区
2024年11月19日22:05
网页开发充满误解,这篇博文针对11个常见迷思进行揭秘。包括网站开发后不需更新、需掌握所有技术、AI会取代开发者等。强调持续学习、专业化、用户体验的重要性,澄清误区如多任务处理的必要性和最新技术的必需性。文章提醒开发者注重实用而非追求完美代码,以务实态度面对开发工作。
你知道 CSS 的四种 Focus 样式吗?
2024年11月18日21:41
本文介绍了四种 CSS focus 样式::focus、:focus-visible、:focus-within 以及自定义的 :focus-visible-within,帮助提升网站用户体验。:focus 样式应用于被选中元素;:focus-visible 仅在键盘导航时显示;:focus-within 用于父元素;自定义 :focus-visible-within 结合两者效果。合理运用这些样式能使网站更方便键盘用户导航。
利用 Python 实现自动化图像裁剪:简单高效的工作流程
2024年11月11日20:49
使用 Python 和 OpenCV 自动裁剪图像,轻松实现 16:9 的完美构图。这个指南介绍了如何通过代码进行灰度化、模糊处理和边缘检测,最终识别出最重要的部分进行裁剪。特别适合需要批量处理图像的情况,节省大量时间。
每位资深前端开发人员都应了解的 TypeScript 高级概念
2024年11月11日02:07
资深前端开发者应了解 TypeScript 的高级概念,如联合类型、交叉类型、类型保护、条件类型、映射类型、模板字面量类型和递归类型。这些特性可提升代码的可维护性和可扩展性,确保在开发复杂应用时实现更高的类型安全性和效率。