DEV Community

Germán Alberto Gimenez Silva
Germán Alberto Gimenez Silva

Posted on • Originally published at rubystacknews.com on

🧠 SOLID vs OOP in Ruby: Are We Just Repackaging the Same Ideas?

SOLID vs OOP in Ruby: Are We Just Repackaging the Same Ideas?
SOLID vs OOP in Ruby: Are We Just Repackaging the Same Ideas?

June 24, 2025

In a recent round of technical interviews, I was asked about the SOLID principles. Like many Ruby developers, I’ve spent years applying object-oriented concepts in practice — even before SOLID was something people talked about regularly.

As I dug deeper into the acronym, something became clear:

Many of the “new” principles in SOLID are just classic object-oriented programming concepts — rephrased, renamed, and organized under a new label.

So in this article, I’d like to explore how SOLID overlaps with traditional OOP theory , using Ruby examples , and why that matters.


📦 Classic OOP Concepts in Ruby

Article content

Ruby is a truly object-oriented language. It’s expressive, flexible, and built on OOP principles. Here are the core ones:

1. Encapsulation

Hide internal details behind a public interface.


class BankAccount
  def initialize(balance)
    @balance = balance
  end

  def deposit(amount)
    @balance += amount
  end

  private

  def log_transaction
    # internal logging
  end
end

Enter fullscreen mode Exit fullscreen mode

2. Inheritance

Use shared behavior across subclasses.


class Animal
  def speak
    "..."
  end
end

class Dog < Animal
  def speak
    "Woof"
  end
end

Enter fullscreen mode Exit fullscreen mode

3. Polymorphism

Different classes respond to the same method call.


def make_sound(animal)
  animal.speak
end

make_sound(Dog.new) # => "Woof"
make_sound(Cat.new) # => "Meow"

Enter fullscreen mode Exit fullscreen mode

Article content


🔠 Enter SOLID Principles

Let’s walk through each SOLID principle and map it directly to the OOP concept it depends on — with Ruby examples.


🔹 S — Single Responsibility Principle (SRP)

A class should have one and only one reason to change.

📌 This is an extension of encapsulation — focus each class on one thing.


# ![❌](https://s0.wp.com/wp-content/mu-plugins/wpcom-smileys/twemoji/2/72x72/274c.png) Violates SRP
class Report
  def generate
    # generate logic
  end

  def send_email
    # mail logic
  end
end

# ![✅](https://s0.wp.com/wp-content/mu-plugins/wpcom-smileys/twemoji/2/72x72/2705.png) Follows SRP
class ReportGenerator
  def generate
    # logic
  end
end

class ReportMailer
  def send_email
    # logic
  end
end

Enter fullscreen mode Exit fullscreen mode

🔹 O — Open/Closed Principle (OCP)

Software entities should be open for extension, but closed for modification.

📌 Built on polymorphism and inheritance.


# Without OCP: adding a new format requires editing this method
class Invoice
  def export(format)
    if format == :pdf
      # ...
    elsif format == :csv
      # ...
    end
  end
end

# With OCP: extend via polymorphism
class InvoiceExporter
  def initialize(strategy)
    @strategy = strategy
  end

  def export(invoice)
    @strategy.export(invoice)
  end
end

class PdfExporter
  def export(invoice)
    # PDF logic
  end
end

class CsvExporter
  def export(invoice)
    # CSV logic
  end
end

Enter fullscreen mode Exit fullscreen mode

🔹 L — Liskov Substitution Principle (LSP)

Subtypes must be substitutable for their base types.

📌 This is about safe inheritance. Ruby makes it easy to break this with monkey-patching, so caution is key.


class Bird
  def fly
    "I'm flying"
  end
end

class Penguin < Bird
  def fly
    raise "I can't fly"
  end
end

# ![❌](https://s0.wp.com/wp-content/mu-plugins/wpcom-smileys/twemoji/2/72x72/274c.png) Violates LSP — a Penguin is not a substitutable Bird

# ![✅](https://s0.wp.com/wp-content/mu-plugins/wpcom-smileys/twemoji/2/72x72/2705.png) Use composition instead
class Bird
end

class FlyingBird < Bird
  def fly
    "I'm flying"
  end
end

class Penguin < Bird
  # No fly method — safe
end

Enter fullscreen mode Exit fullscreen mode

🔹 I — Interface Segregation Principle (ISP)

Clients should not be forced to depend on methods they do not use.

📌 Ruby doesn’t have interfaces, but small modules help.


# ![❌](https://s0.wp.com/wp-content/mu-plugins/wpcom-smileys/twemoji/2/72x72/274c.png) One big interface
module Worker
  def work; end
  def eat; end
  def sleep; end
end

# ![✅](https://s0.wp.com/wp-content/mu-plugins/wpcom-smileys/twemoji/2/72x72/2705.png) Split interfaces
module Workable
  def work; end
end

module Eatable
  def eat; end
end

Enter fullscreen mode Exit fullscreen mode

🔹 D — Dependency Inversion Principle (DIP)

Depend on abstractions, not concretions.

📌 In Ruby, this often means injecting dependencies , instead of hard-coding them.


# ![❌](https://s0.wp.com/wp-content/mu-plugins/wpcom-smileys/twemoji/2/72x72/274c.png) Violates DIP
class Notifier
  def initialize
    @mailer = GmailMailer.new
  end
end

# ![✅](https://s0.wp.com/wp-content/mu-plugins/wpcom-smileys/twemoji/2/72x72/2705.png) Follows DIP
class Notifier
  def initialize(mailer)
    @mailer = mailer
  end
end

Notifier.new(SendGridMailer.new)

Enter fullscreen mode Exit fullscreen mode

🎯 Final Thoughts: Just Another Name?

To me, SOLID doesn’t introduce brand-new ideas — it just repackages and refines OOP best practices. That’s not a bad thing. But in a world full of acronyms, patterns, and buzzwords, it’s easy to get lost.

Sometimes, going back to the roots of OOP is enough.

If you know how to model objects well, use composition, write clear responsibilities, and test your code — you’re already doing most of what SOLID asks.


💬 What’s Your Take?

  • Do you use SOLID when writing Ruby?
  • Do you think these principles add value, or just complexity?

Let’s chat in the comments — I’d love to hear your experience with this balance of theory and practice.

Article content

Top comments (0)