Mismo

Refactoring in Ruby: Elevating Code Quality through Community and Practice

In the field of Software Engineering, from junior to senior levels, coding transcends mere lines of instructions. Influential figures like Kent Beck and DHH have championed the notion that coding is a collaborative process,  even an art form, due to its inherent creativity and craftsmanship.

However, our aim here is not to ignite a debate on this topic. Ultimately, every coder aspires to produce clean, maintainable, and efficient code. Yet achieving this goal often necessitates guidance.

The book “Refactoring: Ruby Edition” by Jay Fields, Shane Harvie, and Martin Fowler shed light on my journey as a junior developer. In this post, we will delve into some aspects of this book and demonstrate how it serves as a valuable  roadmap.

Fostering Excellence through Community Engagement

Ruby is renowned for its elegance and expressiveness, qualities that owe much to its vibrant community. Unlike some other development communities where individual developers often work in isolation, each employing their own approaches and techniques, Rubyists embrace a collective ethos, aligning themselves with the principles of the “Agile Manifesto.” Perhaps the most prominent exemplar of this collective spirit is the widely acclaimed framework: Rails.

Rails embodies principles such as test-driven development, continuous integration, and iterative cycles. At the heart of these practices lies the art of Refactoring, a discipline that ensures code remains clean, maintainable, and adaptable over time.

The Refactoring Process

By definition, refactoring involves altering the internal structure of software to enhance its comprehensibility and reduce the cost of modification without altering its observable behavior.

However, before delving into specific examples, it’s essential to discuss two key concepts that streamline our approach: identifying “bad smell” code and leveraging test values.

Identifying Code Smells

The initial phase of the refactoring process involves recognizing and addressing “code smells” – indicators of potential issues or areas for improvement within the codebase. These smells, such as “Lazy Class” or “Middle Man,” often signify unnecessary complexity or redundancy, which can diminish readability and maintainability.
A “Lazy Class” may include methods that are overly or underutilized, while a “Middle Man” might serve as an unnecessary intermediary between objects within a class. As you familiarize yourself with these common patterns, you’ll gradually develop the ability to spot these code smells throughout the codebase. This not only enhances your own code quality but also empowers you to provide valuable feedback when reviewing colleagues’ work.

The Values: Enhancing Confidence in Code Changes

The Test-Drive Development (TDD) technique seamlessly complements the process of refactoring, offering a reliable approach to making code modifications with confidence.

The iterative TDD cycle commences with writing a test that outlines the desired behavior. The test initially fails and is marked as “red.” Subsequently, code is implemented to fulfill the test, resulting in a successful outcome, denoted as “green.” Finally, the code can be refactored while ensuring that the tests remain green, thereby maintaining the desired functionality. 

While Test-Driven Development (TDD) is indeed highly beneficial and synergistic with refactoring, it’s essential to acknowledge that it’s not always a strict requirement. However, incorporating testing before embarking on any refactoring endeavors is valuable advice.

Before initiating any refactoring efforts, it’s advisable to add tests that encompass various scenarios. Even a basic black-box test covering the primary functionality can suffice. This approach ensures that the code’s behavior remains consistent throughout the refactoring process, enhancing confidence in the changes made.

Illuminating Examples

We’ll explore four examples of refactoring to provide insight into the types of scenarios covered in the book.

1. Composing Methods

This involves breaking down complex methods into smaller, more manageable ones, making the code easier to understand and maintain.

By extracting variables like ‘base_price’ into separate methods, we simplify the logic flow and can focus more clearly on the if/else conditions.

2. Moving Features Between Objects

This refers to transferring functionality or attributes from one object to another to improve the organization and coherence of the codebase.

For example, transforming the ’telephone_number’  method into its own class, ‘TelephoneNumber’ as illustrated in the code on the left:

3. Simplifying Conditionals Expressions

This involves reducing complex conditional logic, such as nested if statements, to make the code more readable and maintainable.

In the example provided (‘consolidate_conditional_expresion_a.rb’), multiple improvements need to be made. The initial file contains several nested `if…` statements, which can potentially complicate matters in the future. 

To address this, a new method called ’ineligable_for_diability?’ is created to encapsulate all the conditional logic. Furthermore, upon revisiting the ‘disability_amont’ method,  the intention becomes clearer. By explicitly stating that we will return 0 if the individual is  ineligable_for_diability, the method’s purpose and flow are more apparent, enhancing readability and maintainability.  

In this example, you can easily see the smell ready and the improvement on the right.

4. Making Method Calls Simpler

This refers to optimizing method calls by eliminating unnecessary parameters or simplifying the interface, making the code easier to use and understand.

Here, you can see the improvement achieved by avoiding the need to consider the ‘low’ and ‘high’ parameters explicitly. Instead, we directly call ‘withing_range?’, allowing the object or method to handle the ‘low’ and ‘high’ variables internally. This simplifies the interface, making the code more intuitive and easier to use. 

Last Words

I hope these examples have instilled enough confidence in you to begin exploring this book. I can assure you, not to lie, it will be an enjoyable journey. You don’t need advanced English skills to comprehend it, and you can approach it in any order you prefer.

To conclude, I’d like to leave you with two pieces of advice:

  1. The stronger your test suite, the more confidently you can refactor.  High-quality tests act as a safety net, allowing you to make changes with assurance and precision.
  2. Always proceed in small steps, one at a time. Refactoring is a gradual process, so avoid attempting to tackle everything at once.  

I’ll close with a quote from Martin Fowler: “Any fool can write code that a computer can understand. Good programmers write code that humans can understand.

Bibliography:

Fields, J., Harvie, S., Fowler, M., & Beck, K. (2009). Refactoring: Ruby Edition. https://www.amazon.com/Refactoring-Ruby-Addison-Wesley-Professional/dp/0321984137p. 15

Written by:

Julio Augustin Lucero
Sr. Software Engineer
Country: Argentina

Exit mobile version