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
endSolution
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
endConclusion
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
