如何保持代码优雅,可读和可维护
#编程 #python #cleancode #guide

在软件开发的世界中,简单性和优雅是代码的高度价值质量,因为它更容易理解,维护和扩展。编写优雅的代码需要周到的设计和对细节的关注。在本文中,我们将探讨实现这一目标的一些关键原则和实践。

请注意,在继续之前,我确实知道,较大的组织有自己的内部指南编写干净的代码。如果您是为这些组织工作的人之一,那么您应该知道,本文不是这些准则的替代者,而是关于如何编写清洁代码基础的一般想法。

这是我们将在本文中讨论的所有要点的列表。

  1. 保持功能和方法较小,专注于

  2. 使用描述性名称

  3. 避免嵌套如果语句

  4. 避免在语句中固定条件

  5. 写入可读和自我记录的代码

  6. 消除代码重复(Kinda)

  7. 正确构建项目目录

  8. 写单元测试

保持功能和方法较小且重点:编写简单而优雅的代码的基本原理之一是使功能和方法保持较小而专注。旨在实现执行单个任务并具有明确目的的功能。将复杂的逻辑分解为较小,更易于管理的部分,可以增强代码可读性。以下是获取用户输入并运行排序算法的示例:

def sort_array(arr):
    if arr:
        if len(arr) > 1:
            algorithm = input("Enter the sorting algorithm (bubble, insertion, quick): ")
            match algorithm:
                case "bubble":
                    # bubble sort logic
                case "insertion":
                    # insertion sort logic
                case "quick":
                    # quick sort logic
                case _:
                    print("Invalid sorting algorithm.")
        else:
            print("The array has only one element.")
    else:
        print("The array is empty.")

尽管上述确实有效,但它做的事情太多了,例如数组验证,获取用户输入,在每个交换机案例中写出每个分类逻辑,并使用每个开关情况使用字符串值。所有这些事情使功能变得复杂且难以调试。相反,我们应该将这个较大功能分解为每个功能都有其责任的较小功能:

class SortEnum(Enum):
    BUBBLE = "bubble"
    INSERTION = "insertion"
    QUICK = "quick"

def bubble_sort(arr):
    # Bubble sort implementation
    pass

def insertion_sort(arr):
    # Insertion sort implementation
    pass

def quick_sort(arr):
    # Quicksort implementation
    pass

def validate_array(arr):
    if not arr:
        print("The array is empty.")
        return False
    if len(arr) <= 1:
        print("The array has only one element.")
        return False
    return True

def get_sorting_algorithm():
    algorithm = input("Enter the sorting algorithm (bubble, insertion, quick): ")
    return algorithm

def sort_array(arr):
    if validate_array(arr):
        algorithm = get_sorting_algorithm()
        match algorithm:
            case SortEnum.BUBBLE:
                bubble_sort(arr)
            case SortEnum.INSERTION:
                insertion_sort(arr)
            case SortEnum.QUICK:
                quick_sort(arr)
            case _:
                print("Invalid sorting algorithm.")

尽管将函数分为多个函数,但会增加代码行的数量。但是,现在扩展功能并调试将来可能出现的任何问题要容易得多。注意,在真实的代码基础上,枚举类和某些功能应在不同的文件中。

使用描述性名称:为变量,功能和类选择清晰和描述性名称对于编写优雅代码至关重要。名称应准确反映变量和功能的目的和功能。避免使用可能会使其他开发人员混淆的隐秘缩写或首字母缩写。意图揭示名称使代码自我解释并减少评论的需求。有关可变命名的深入讨论和指南,请阅读我的文章The art of naming variables

避免嵌套如果语句:嵌套如果语句可以快速导致代码复杂性,从而更难理解逻辑流并增加在开发或将来修改过程中引入错误的机会。随着嵌套的数量(如果语句增加),代码变得更加令人费解,并且很难跟踪哪个条件对应于哪个代码块;对于传达压痕的Python等语言尤其如此。这可能会导致一种称为“箭头抗模式”的现象,其中代码分支为箭头形状,使遵循程序的逻辑挑战。例如,假设您正在开发一个处理客户订单的软件应用程序。您想在处理订单之前验证该订单。这是if语句深处嵌套的示例:

def process_order(order):
    if order.is_valid():
        if order.has_sufficient_inventory():
            if order.has_valid_payment():
                order.process()
            else:
                print("Invalid payment")
        else:
            print("Insufficient inventory")
    else:
        print("Invalid order")

在此示例中,随着验证步骤增加或变得更加复杂,逻辑可能很难遵循。一种更好的方法是使用后卫条款或提前退出策略避免过度筑巢。这是使用Guard Crauses的改进版本:

def process_order(order):
    if not order.is_valid():
        print("Invalid order")
        return

    if not order.has_sufficient_inventory():
        print("Insufficient inventory")
        return

    if not order.has_valid_payment():
        print("Invalid payment")
        return

    order.process()

避免在语句中链接条件:当条件与逻辑运算符(例如and)(或/或)链接时,代码可能很难变得难以理解。以下示例需要进行3次检查,然后用户可以编辑:

# check user can edit
if user.role == RoleEnum.ADMIN and 
   job.status == JobStatusEnum.OPEN and 
   job.type == JobTypeEnum.CONTRACT:
        pass

以上是代码库中通常看到的内容,尽管有评论告诉读者此检查的目的是什么,但我们可以为条件分配一个变量:

can_edit = user.role == RoleEnum.ADMIN and 
   job.status == JobStatusEnum.OPEN and 
   job.type == JobTypeEnum.CONTRACT

if can_edit:
    pass

这使得代码更容易一眼理解。

编写可读且自我记录的代码:努力编写自称且易于理解的代码,而无需大量依赖评论。精心设计的代码应像叙述一样读取,使其他开发人员清晰地逻辑和流程。使用一致的格式,凹痕和间距来增强可读性。清晰和表达的代码减少了读者的认知负担,并改善了代码理解。在这么说时,请在需要时使用评论,例如需要域知识的类或功能。

消除代码重复(Kinda):代码重复不仅增加了错误的机会,而且使代码更难读取和维护。通过代码重复使用和抽象消除重复是编写简单而优雅的代码的关键实践。确定重复的模式或功能,并将其提取到可重复使用的功能,模块或类中。我在这里指的是“不要重复自己”(干燥)原理。但是,确实需要了解如何正确使用干燥,而不是在任何地方使用它。因此,“避免仓促抽象”(啊哈)编程原则正在越来越受欢迎。开发商仍然是可以不干燥代码库中的所有东西,而是在适当的情况下使用干燥。 this文章总结了此原则。

正确构建项目目录:一个精心设计的项目目录提供了几个好处。首先,它通过创建不同组件,模块或功能的逻辑分离来提高代码可维护性,从而更容易找到和修改特定文件。其次,一个清晰的文件夹可以更好地了解项目的体系结构,并降低了代码重复的风险。团队成员可以迅速找到所需的东西,并掌握该项目的整体布局。最后,结构化文件夹层次结构简化了版本控制管理,因为它允许开发人员系统地跟踪更改。有关文件夹结构的更深入讨论和示例,请阅读我的文章Express.js: The dangers of unopinionated frameworks and best practices for building web applicationsHere is how you write scalable and maintainable React components for projects of any size

写单元测试:单元测试是软件开发生命周期中非常重要的一部分。写作测试不仅验证了代码的正确性,而且还充当活业文档,并在重构或修改代码期间提供信心。通过与代码一起编写测试,您可以尽早发现错误,提高代码质量,并确保代码随着时间的流逝而保持简单且可维护。重要的是,我们不仅要测试“快乐”路径,而且更重要的是“坏”场景。我们作为开发人员通常在测试方面非常宽大,因此我们需要测试用户可能面临的所有情况。但是说这句话是在编写适当数量的测试之间存在平衡,您不想过度使用它,因为这将导致开发时间增加和维护测试。

总而言之,编写简单而优雅的代码是值得追求软件开发的目标。通过遵循这些实践,开发人员可以创建干净,可读和可维护的代码。简单而优雅的代码可提高生产率,更好的协作和改善的软件质量。拥抱这些原则,并在代码库中为简单和优雅而努力获得长期收益。