Refactoring is the process of restructuring existing computer code without changing its external behavior. It aims to improve the nonfunctional attributes of the software, making it easier to understand, more maintainable, and more efficient. In this section, we will cover the key concepts, techniques, and best practices for refactoring Ruby code.
Key Concepts
- Code Smells: Indicators that there might be a problem in the code.
- Refactoring Techniques: Specific methods used to improve the code.
- Automated Tests: Ensuring that refactoring does not break existing functionality.
Code Smells
Code smells are patterns in the code that may indicate deeper problems. Here are some common code smells:
- Duplicated Code: Same code structure repeated in multiple places.
- Long Method: Methods that are too long and do too much.
- Large Class: Classes that have too many responsibilities.
- Feature Envy: A method that seems more interested in a class other than the one it is in.
- Data Clumps: Groups of data that are often passed together.
Refactoring Techniques
- Extract Method
Problem: A method is too long or does too many things.
Solution: Break the method into smaller, more focused methods.
# Before Refactoring def print_owing outstanding = 0.0 puts "*" puts "* Customer Owes ***" puts "*" @orders.each do |order| outstanding += order.amount end puts "name: #{@name}" puts "amount: #{outstanding}" end # After Refactoring def print_owing print_banner outstanding = calculate_outstanding print_details(outstanding) end def print_banner puts "*" puts "* Customer Owes ***" puts "*" end def calculate_outstanding @orders.reduce(0.0) { |sum, order| sum + order.amount } end def print_details(outstanding) puts "name: #{@name}" puts "amount: #{outstanding}" end
- Inline Method
Problem: A method is not doing enough to justify its existence.
Solution: Replace the method call with the method's content.
# Before Refactoring def get_rating more_than_five_late_deliveries ? 2 : 1 end def more_than_five_late_deliveries @number_of_late_deliveries > 5 end # After Refactoring def get_rating @number_of_late_deliveries > 5 ? 2 : 1 end
- Rename Method
Problem: A method name does not clearly describe what the method does.
Solution: Rename the method to something more descriptive.
# Before Refactoring def get_annual_income # method implementation end # After Refactoring def calculate_annual_income # method implementation end
- Replace Temp with Query
Problem: A temporary variable is holding the result of an expression.
Solution: Replace the variable with a method call.
# Before Refactoring base_price = quantity * item_price if base_price > 1000 # do something end # After Refactoring if base_price > 1000 # do something end def base_price quantity * item_price end
Automated Tests
Before refactoring, it is crucial to have a comprehensive suite of automated tests. These tests ensure that the refactoring process does not introduce new bugs. Here are some steps to follow:
- Write Tests: Ensure you have tests that cover the existing functionality.
- Run Tests: Run all tests to ensure they pass before refactoring.
- Refactor: Apply the refactoring techniques.
- Run Tests Again: Run all tests again to ensure no functionality is broken.
Practical Exercise
Exercise: Refactor the Following Code
Refactor the following code to improve its readability and maintainability.
class Order def initialize(customer) @customer = customer end def print_order puts "Order for #{@customer.name}" puts "Items:" @customer.orders.each do |order| puts "#{order.item_name}: #{order.price}" end total = @customer.orders.reduce(0) { |sum, order| sum + order.price } puts "Total: #{total}" end end
Solution
class Order def initialize(customer) @customer = customer end def print_order print_header print_items print_total end private def print_header puts "Order for #{@customer.name}" puts "Items:" end def print_items @customer.orders.each do |order| puts "#{order.item_name}: #{order.price}" end end def print_total total = calculate_total puts "Total: #{total}" end def calculate_total @customer.orders.reduce(0) { |sum, order| sum + order.price } end end
Conclusion
Refactoring is an essential skill for maintaining and improving the quality of your code. By identifying code smells and applying appropriate refactoring techniques, you can make your code more readable, maintainable, and efficient. Always ensure you have a robust suite of automated tests to safeguard against introducing new bugs during the refactoring process.
Ruby Programming Course
Module 1: Introduction to Ruby
Module 2: Basic Ruby Concepts
Module 3: Working with Collections
Module 4: Object-Oriented Programming in Ruby
- Classes and Objects
- Instance Variables and Methods
- Class Variables and Methods
- Inheritance
- Modules and Mixins
Module 5: Advanced Ruby Concepts
Module 6: Ruby on Rails Introduction
- What is Ruby on Rails?
- Setting Up Rails Environment
- Creating a Simple Rails Application
- MVC Architecture
- Routing
Module 7: Testing in Ruby
- Introduction to Testing
- Unit Testing with Minitest
- Behavior-Driven Development with RSpec
- Mocking and Stubbing