From Chaotic If-Else to Elegant, Maintainable Class Structure

From Chaotic If-Else to Elegant, Maintainable Class Structure

In the world of software development, there’s one concept that often differentiates novice developers from seasoned professionals: clean code. Written with clarity, structure, and an emphasis on maintainability, clean code is the backbone of sustainable and scalable systems.

However, transitioning from "dirty" code to clean code doesn't happen overnight. It requires practice, patience, and a mindset focused on quality.

In his seminal book Clean Code, Robert C. Martin emphasizes that well-written code is not just functional, but also understandable and easy to modify.

In this article, we’ll explore two code examples: one that embodies clean code principles and another that doesn’t. Through these examples, we’ll highlight how small decisions can impact the readability, maintainability, and even performance of your projects.


A Typical Dirty Code Example

Let’s begin with an example of bad code. Imagine we’re building a function to calculate tax on a sale, where there are three different types of taxes:

Figure 1: A tax calculation method with unclear naming, hard-coded conditions, and poor scalability.

At first glance, the code seems fine. However, upon a more thorough analysis, a series of issues will be revealed that could cause headaches down the road.

First, the function CalculateTax and the taxType parameter, although simple, don’t provide enough context or clarity about their purpose.

?? What is a "taxType"?

It could refer to multiple kinds of taxes, but from this code alone, we don’t know what these "types" represent. Are they types of taxes based on regions, products, or something else? The naming is vague, and it’s difficult to understand the full context without looking elsewhere in the codebase.

?? What does CalculateTax mean?

This function might seem straightforward, but consider a scenario where your application grows and you start calculating taxes for different business entities, regions, or conditions. A method name like CalculateTax becomes too generic.

This code also violates one of the S.O.L.I.D. principles. Let's remind ourselves of what the Open/Closed Principle teaches:

Software entities (classes, modules, functions) should be OPEN for extension, but CLOSED for modification.

This means that the behavior of a module can be extended without modifying its existing source code. This is achieved by adding new functionality through inheritance, interfaces, or composition, rather than directly altering the existing code.

In the case of the original code, to add a new tax type, the TaxCalculator class itself would have to be modified, which goes against the principle:

Figure 2: Introducing a new tax type by modifying the existing code.

Also, it’s not immediately clear what each condition in the if-else block represents. Each tax type is being evaluated based on a string value ("A", "B", "C"), and the tax rate is applied based on these conditions. But the logic is cluttered and relies on magic strings, which can be error-prone.


A Practical Refactor

To improve the code, the first thing to do is define an interface (ITaxType) that will have only one method (Calculate). This method is where each tax type will define its specific logic for calculating the tax.

Next, we create the concrete classes for each tax type (TaxA, TaxB, and TaxC in the example). Each of these classes will implement the interface and provide its own specific calculation logic:

Figure 3: The ITaxType interface and its implementations

Now that we have our tax types implemented as separate classes, we can refactor the TaxCalculator class to use a data structure called a dictionary for tax types.

Figure 4: Simplifying tax calculation with a dictionary

This way, the code becomes more modular, easier to extend, and more maintainable. Instead of modifying the TaxCalculator class each time a new tax type is added, we simply need to create a new class that implements the ITaxType interface and add it to the dictionary.


Note: A dictionary in C# is a collection that stores key-value pairs. It allows for fast lookups, where the key is used to access the corresponding value. In our case, the key can be the tax type (e.g., "A", "B", "C"), and the value will be the instance of the appropriate class that implements the ITaxType interface.


Performance Consideration

While the primary focus of this refactor is to improve maintainability, scalability, and adherence to clean code principles, there’s an additional performance benefit worth noting. By replacing the if-else chain with a dictionary lookup, the tax calculation logic now benefits from constant time complexity, O(1), for each lookup. In contrast, the if-else structure has a linear time complexity, O(n), meaning that as the number of tax types grows, the performance could degrade.

This refactor not only makes it easier to add new tax types but also results in better performance when the number of tax types increases, especially in scenarios where the program might need to handle many different tax categories.


Conclusion

By leveraging interface-based design, polymorphism, and the Open/Closed Principle, we’ve transformed a rigid and complex codebase into a more flexible, scalable, and maintainable solution. These clean code practices not only improve the efficiency of the development process but also prepare the codebase for future growth and easy extensibility.

Clean code is about making your software easier to read, maintain, and extend, and by applying these principles, you’re setting your project up for long-term success.

#CleanCode #SoftwareDevelopment #CodeQuality #Refactoring #Scalability #Maintainability #Polymorphism #DesignPatterns #ProgrammingTips #TechBestPractices #CSharp #SoftwareEngineering #DeveloperMindset



要查看或添加评论,请登录

Leandro Siqueira的更多文章

  • Transforming Models for Real-World Impact

    Transforming Models for Real-World Impact

    As an AI Specialist and Technical Trainer, I'm excited to share techniques that empower tech learners to build better…

  • Unlocking Development Challenges with the '5 Whys' Framework

    Unlocking Development Challenges with the '5 Whys' Framework

    Every developer, whether working on AI, web applications, or enterprise systems, faces roadblocks. But before…

    2 条评论
  • Cohesion

    Cohesion

    When diving into object-oriented programming (OOP), you’ve likely encountered the term "cohesion" at some point. And…

  • The Open/Closed Principle

    The Open/Closed Principle

    ?? ?????? ????????/???????????? ?????????????????? (??????) ???? ?????? ???? ?????? ????????????????????????…

  • The Single Responsibility Principle

    The Single Responsibility Principle

    ??C?????? ?????????????? ?????? ?????????????????????????????? ?????? ?????????????? ?????? ?????? ?????????????? ????…

  • Keep Calm and Code In Delphi #4

    Keep Calm and Code In Delphi #4

    ??Enumerated Types Enumerated types (or simply "enums") allow you to create ordered sets of predefined values and are…

  • Keep Calm and Code in Delphi - #3

    Keep Calm and Code in Delphi - #3

    ?? Linked Lists Linked Lists are one of the most powerful and flexible data structures, widely used to implement…

    1 条评论

社区洞察

其他会员也浏览了