Why change is hard in tech
Understanding and Managing Dependencies in Rails for Sustainable Design
Meticulously managing dependencies between objects is the safeguard adaptability and maintainability.
As your application scales, your design decisions will either empower or hinder its growth and flexibility.
Dependency Management in Models
The core of Rails, the Model, often bears the brunt of poor design choices, notable among these are excessive dependencies.
Let’s dissect good versus bad practices in dependency management within Rails models, and how to implement more resilient designs.
Poor Dependency Management Example
Here’s a typical example of a poorly designed Rails model where multiple dependencies are inadequately managed:
# app/models/order.rb
# Columns:
# - user_id:integer:index
# - product_id:integer:index
# - status:string
# - quantity:integer
class Order < ApplicationRecord
belongs_to :user
belongs_to :product
def total_price
product.price * quantity # Dependency on product internals
end
end
In the above model, Order
excessively depends on the internal structure of Product
. Such code can lead to significant issues as the system evolves, given that any modification within Product
could require revisiting Order
methods, thereby increasing maintenance costs and potential for introducing bugs.
Improved Dependency Management
The improved approach involves encapsulating responsibilities and reducing direct dependencies:
# app/models/order.rb
# Revised to encapsulate responsibility and reduce direct dependency on Product internals
class Order < ApplicationRecord
belongs_to :user
belongs_to :product
def total_price
product.calculate_price_for(quantity) # Improved encapsulation
end
end
# app/models/product.rb
# Encapsulation of price calculation and stock management
class Product < ApplicationRecord
has_many :orders
def calculate_price_for(quantity)
price * quantity # Encapsulates price calculation
end
end
In this refined version, Product
now encapsulates its operations, making Order
less vulnerable to changes within Product
.
This separation enhances the adaptability of both models.
Implications of Managed Dependencies
Each component has limited knowledge of and reduced reliance on the internal workings of other components. Besides simplifying testing, this design approach leads to a system that is easier to understand and modify.
Reducing object dependencies does not merely mitigate the “ripple effect” of changes; it also prepares your codebase for sustainable evolution, keeping the development process agile and less error-prone as complexities increase.
There is no secret to get good at this: you need to read more code. The best code does not takes hours to understand.
That’s the magic about Object Oriented Design.
Related posts
Building a Rails Engine