Object oriented design in rails
Emphasizing Modular Design
Rails is inherently object-oriented, providing a structured environment where modular design thrives.
This modularity is crucial in maintaining scalable and maintainable codebases, especially in larger applications.
Consider a Rails application with poorly designed modules.
Each change is not only difficult but also risky, potentially affecting unrelated parts of the system.
This setup leads to increased development time and higher costs.
Kinda like a motorcycle:
- as long as you design another engine that still has the same socket dimentions and output shaft location. You are good to go!
But if you weld everything… Then you have to re-cut and weld metal.
And that’s what we are solving here:
- Modular code like motorcycle parts.
Good vs. Bad Design: Understanding the Impact
Bad Design Example: Tightly Coupled Models
Consider a scenario where business logic is not properly encapsulated.
# app/models/order.rb
class Order < ApplicationRecord
# Columns in orders table: user_id (integer, foreign key), status (string), total (decimal)
belongs_to :user
# Business logic heavily tied to User model
def calculate_total
self.total = user.cart.items.sum(&:price)
save!
end
end
In the example above, the Order
model directly accesses the user’s cart, creating a high coupling between Order
and User
.
This design complicates testing and violates the Single Responsibility Principle (SRP), leading to a codebase that’s difficult to maintain and scale.
Improved Design: Encapsulation and SRP
A better approach is encapsulating responsibilities properly.
# app/models/order.rb
class Order < ApplicationRecord
# Columns: user_id (integer, foreign key), status (string), total (decimal)
belongs_to :user
end
# app/services/order_calculator.rb
# Handles order calculations, improving modularity
class OrderCalculator
def initialize(user)
@user = user
end
def calculate_total
@user.cart.items.sum(:price) # NOTE: we drop the "&" leading to an SQL SUM statment.
end
end
Here, OrderCalculator
is a service object that encapsulates the logic to calculate order totals.
This design adheres to SRP, improves modularity, and makes the codebase easier to maintain.
Prioritizing Flexibility in Database Relationships
In Rails, managing database relations effectively is crucial for maintaining flexibility. Improper design choices here can lead to complex migrations and convoluted queries that impact performance negatively.
Example: Over-normalized Schemas
An excessively normalized database can complicate Rails associations and queries, leading to performance issues.
# app/models/user.rb
class User < ApplicationRecord
# Columns: name (string), email (string unique index)
has_many :posts
end
# app/models/post.rb
class Post < ApplicationRecord
# Columns: user_id (integer, foreign key, index), title (string), content (text)
belongs_to :user
has_many :tags
end
class Tag < ApplicationRecord
belongs_to :tag
validates :name, presence: true
end
Better Approach: Balanced Normalization
Striking the right balance in database design ensures that Rails applications remain manageable and performant. Avoid over-normalization where it adds little value.
# app/models/user.rb
class User < ApplicationRecord
# Columns: name (string), email (string unique index)
has_many :posts
end
# app/models/post.rb
class Post < ApplicationRecord
# Columns: user_id (integer, foreign key, index), title (string), content (text)
belongs_to :user
enum tags: [:rails, :testing]
end
The above model setup maintains simplicity and ensures efficient queries.
Conclusion: Design for Change
OOD in Rails is not merely a theoretical exercise; it’s a practical approach to building applications that are easy to maintain, extend, and scale.
Best practices in modular design and thoughtful database modeling are here to significantly reduce future headaches, decrease costs associated with changes, and craft applications that adapt smoothly to new requirements.
If you want to get good at it quick, here is the hack: read this gem
gem "rails"
Roland 🤙
Related posts
Building a Rails Engine