OOD Principles and Rails: The Law of Demeter
Understanding the Law of Demeter
The Law of Demeter (LoD) or principle of least knowledge advocates for minimal knowledge of a component about other components.
In Rails, it’s tempting to chain method calls due to ActiveRecord associations.
Frequent utilization, such as <%= @invoice.customer.name %>
, increases coupling and potential maintenance woes.
Code Smells: Chain Dependencies
Chaining dependencies, e.g., <%= @invoice.customer.address.city %>
, poses serious risks:
- Increased Dependency: Any change in model structure demands modifications across multiple files, elevating maintenance costs.
- Breaking Encapsulation: It exposes internal details of the object’s relationships, making refactoring and testing challenging.
Refactoring to Improve: Delegation vs Direct Method Calls
Refactoring <%= @invoice.customer.name %>
to <%= @invoice.customer_name %>
helps adhere to LoD, reducing the system’s brittleness. Here’s why direct method calls can be harmful:
# Bad: High coupling and encapsulation breach
<%= @invoice.customer.name %>
Switching to:
# Good: Reduced coupling and encapsulation preserved
class Invoice < ActiveRecord::Base
def customer_name
customer.name
end
end
We shift responsibility, enhancing cohesion within the Invoice
class, simplifying code, and easing refactoring.
Practical Implementation in Rails: Using delegate
Rails offers a succinct solution using delegate
for better maintainability and adherence to LoD.
Here’s what the evolution looks like:
# Before: Manual method definitions
class Invoice < ActiveRecord::Base
def customer_name
customer.name
end
end
Refactor with delegate
:
# After: Elegant delegation
class Invoice < ActiveRecord::Base
delegate :name, :street, :city, :state, :zip_code, to: :customer, prefix: true
end
This refactoring ensures:
- Clear Declarations: The
delegate
keyword clearly states where the forwarded messages are sent, improving readability and traceability. - Simplification: Reduces the clutter of manual getter methods in the model.
- Adherence to LoD: Code remains compliant with LoD by using single-level interaction.
In view templates, usage stays succinct and maintenance-friendly:
<%= @invoice.customer_name %>
<%= @invoice.customer_street %>
Following the Law of Demeter in Ruby on Rails using delegate
not only upholds OOP principles but also ensures cleaner, more reliable code, adjustable with lesser effort to future changes.