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

Free Training By Email:
Building a Rails Engine

We will send udpates but we care about your data.
No spams.

Back to homepage