Practical OOD techniques for rails
Embracing Object-Oriented Design in Agile Rails Development
Rails developers often juggle between rapid development cycles and maintaining clean, manageable code.
Let’s check some effective object-oriented design (OOD) strategies in the context of agile Ruby on Rails projects and why it’s crucial for sustainable development.
Understanding the Need for OOD in Agile
Agile methodologies discourage big up front design (BUFD) due to its inefficiency and inaccuracies in long-term planning.
Instead, agile promotes iterative development that adapts to user feedback and changing requirements.
However, this approach doesn’t eliminate the need for design; it actually emphasizes the necessity for excellent ongoing design to manage these changes effectively.
Here’s why OOD is indispensable in Rails:
Flexibility: Agile demands that the design should accommodate changes without extensive reworks. OOD principles help in creating flexible codebases where modifications are localized and do not require broad swathes of changes.
Refactoring: Continuous refactoring is a hallmark of agile Rails projects. Good design practices make refactoring a routine rather than a Herculean effort, thereby keeping the codebase clean and adaptable.
Code Quality: Well-designed object-oriented code enhances readability and maintainability, critical for teams especially when scaling or transitioning between developers.
Practical OOD Techniques for Rails
Let’s review some practical OOD techniques that can be applied effectively in Rails applications.
Use Polymorphism Wisely
Polymorphism can simplify many scenarios in Rails that might otherwise require complex conditional logic. It makes the application easy to extend and modify.
# app/models/notification.rb
class Notification < ApplicationRecord
belongs_to :notifiable, polymorphic: true
end
Comment: Using polymorphism to relate notifications to any model and retrive it to display the text in the notification.
NOTE:
polymorphic
sounds like a silver bullet. But it represent a performance investment in the future. Use Polymorphism Wisely
Encapsulate Behavior in Modules
Sharing code through modules rather than inheritance keeps classes clean and focused on their primary responsibilities.
# app/models/tracker.rb
class Tracker < ApplicationRecord
belongs_to :trackable, polymorphic: true
end
# app/models/concerns/trackable.rb
module Trackable
extend ActiveSupport::Concern
class_methods do
def has_trackable(name: nil)
name ||= class_name.parameterize(separator: '_')
has_many :"#{name}_events", as: :trackable
generated_association_methods.class_eval <<-CODE, __FILE__, __LINE__ + 1
# frozen_string_literal: true
def record_#{name}_event(action)
public_send(:"#{name}_events").create(action: action)
end
CODE
end
end
end
# app/models/user.rb
class User < ApplicationRecord
include Trackable
has_trackable :user
end
Comment: Module Trackable
encapsulates event tracking logic for reuse in various models like User
.
Prefer Composition Over Inheritance
Composition over inheritance is a well-advised OOD principle, especially in Rails where models can easily become bloated.
# app/services/user_registration.rb
class UserRegistration
def initialize(user)
@user = user
end
def register
@user.save
send_welcome_email
# More registration logic
end
private
def send_welcome_email
UserMailer.welcome(@user).deliver_later
end
end
Comment: UserRegistration
handles the registration process, keeping the User
model lean and focused.
@NOTE: Not to be used in small teams. This approach adds more files to traverse to understand the logic, reducing the developer experience in teams that need to be faster rather than cleaner.
Conclusion
Effective OOD in Rails not only supports the agile mandate of adaptability but also ensures that the codebase remains clean, understandable, and maintainable.
The main issue I see among rails developers is that they never read gems. All the best practices are in the rails code base!
Related posts
Building a Rails Engine