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.
Related posts
Building a Rails Engine