SOLID Principles Aren't Principles
Tags: solidprinciples, softwareengineering, softwaredesign
Published: 2024-04-08 22:08:19

Have you ever found yourself pondering endlessly about whether a piece of code follow this or that SOLID principle? It's as if following those principles is more important than the problem itself.

A hypothesis is that it has to do with the word "principle". If SOLID are truly principles, we must always follow them. But should we?

To address this question, let's first revisit SOLID, then study some definitions of "principle", and finally evaluate if SOLID aligns with any of those definitions.

## Revisiting SOLID

S.O.L.I.D. is a set of design so-called principles coined as an acronym by Robert "Uncle Bob" Martin, with each letter representing a key aspect of software design:

- **S** for the _Single Responsibility Principle_: a particular view of cohesion that organizes code around potential changes.
- **O** for the _Open-Closed Principle_: a way of promoting extensibility through abstractions.
- **L** for the _Liskov Substitution Principle_: a strong view of sub-typing.
- **I** for the _Interface Segregation Principle_: a technique for minimizing the "surface area" of non-cohesive code.
- **D** for the _Dependency Inversion Principle_: an approach that decouples policies and business rules from implementation details.

These ideas are quite useful in Object-Oriented code and likely to be applied to other paradigms. But are they truly principles?

> Fun fact: the concepts above were first published in book format in [Agile Principles, Patterns, and Practices](https://www.amazon.com/Software-Development-Principles-Patterns-Practices/dp/0135974445), released in 2002. But the acronym SOLID itself never appeared in this original edition nor in the 2006 C# edition. The order in the table of contents for both editions would form S.O.L.D.I.!

## Defining Principles

What are principles? Let's consult the [Merriam-Webster dictionary](https://www.merriam-webster.com/dictionary/principle):

1. a comprehensive and fundamental **law**, doctrine, or assumption
1. a **rule** or code of conduct
1. the laws or **facts of nature** underlying the working of an artificial device
1. a primary source, **origin**
1. an underlying faculty or endowment
1. an ingredient (such as a chemical) that exhibits or imparts a characteristic quality
1. a divine principle, GOD (when capitalized)

Are SOLID laws or rules? It doesn't seem to be the case. Maybe they're about natural facts or origin? Unlikely.

## Examining Interface Segregation

Now that we've looked at what principles really mean, let's examine the Interface Segregation Principle (ISP) a bit closer. It states that "_Clients should not be forced to depend on methods that they do not use_."

When we have a non-cohesive piece of code, its clients end up having access to unneeded behavior.

Think of a class with numerous unrelated methods like the following:

```java
public class Employee {
  public BigDecimal calculatePayment() {
    //...
  }
  public BigDecimal calculateTaxes() {
    //...
  }
  public BigDecimal calculateOvertime(List<Hour> hours) {
    //...
  }
  public void saveToDB() {
      //...
  }
  public static Employee retrieveById(Long id) {
    //...
  }
  public String toXML() {
    //...
  }
  public static Employee fromXML(String xml) {
    //...
  }
}
```

The `Employee` class above deals with:

- Payment, taxes and overtime.
- Saving and retrieving objects from a database.
- Converting to/from XML.

Most of the time, code using this class only needs some of its methods. For example:

- Finance-related code might use `calculatePayment`, `calculateTaxes`, and `calculateOvertime`.
- Persistence tasks would use `saveToDB` and `retrieveById`
- Integration with other systems might call `toXML` and `fromXML`.

This situation goes against the ISP. Clients of the problematic class could mix up different usages, spreading lack of cohesion throughout the codebase.

A solution would be to create separate interfaces for each group of clients, eliminating dependency on unused behavior. Hence, we would **segregate behavior to narrowly focused interfaces** such as:

```java
public interface EmployeeFinance {
    BigDecimal calculatePayment();
    BigDecimal calculateTaxes();
    BigDecimal calculateOvertime(List<Hour> hours);
}

public interface EmployeePersistence {
    void saveToDB();
    static Employee retrieveById(Long id);
}

public interface EmployeeXmlSerialization {
    String toXML();
    static Employee fromXML(String xml);
}
```

Our `Employee` class would implement the finer-grained interfaces above:

```java
public class Employee implements EmployeeFinance,
  EmployeePersistence, EmployeeXmlSerialization {
  // rest of the code...
}
```

Now, clients of `Employee` could use it behind a specific mask like `EmployeeFinance` for finance-related code and so on, without even knowing about other behaviors.

### Identifying the root cause

The underlying problem here lies in **lack of cohesion**: a class is doing too much. And this means it's a violation of the Single Responsibility Principle (SRP), as `Employee` has at least three reasons to be changed, related to finance, persistence and system integration. We should refactor this class to be more cohesive, having less reasons to change.

> Actually, this is almost the exact example arguing for SRP in Robert Martin's book [UML for Java Programmers](https://www.amazon.com/UML-Java%C2%BF-Programmers-Robert-Martin/dp/0131428489).

If breaking apart a troublesome class isn't an option, we can apply Interface Segregation.

Therefore, Interface Segregation is not much a principle as it's a technique or a pattern: a solution in the specific context of not being able to refactor non-cohesive code. 

## Exploring the Author's Perspective

So, if the ideas in SOLID aren't truly principles, what do they represent?

Let's turn to their creator, Robert Martin, who, in the 2002 book [Agile PPP](https://www.amazon.com/Software-Development-Principles-Patterns-Practices/dp/0135974445), described them as:

> "These principles are the hard-won product of decades of experience in software engineering.
> They are not the product of a single mind but represent the integration of the thoughts and writings of a large number of software developers and researchers."

Hence, SOLID emerges more as a collection of **pragmatic advice** from seasoned software engineers rather than immutable laws or rules.

In his 2009 blog post [Getting a SOLID start](https://sites.google.com/site/unclebobconsultingllc/getting-a-solid-start), Martin clarified his use of the term "principle":

"The SOLID principles are **not rules**.
They are **not laws**.
They are **not perfect truths**.
They are statements on the order of 'An apple a day keeps the doctor away.'
This is a good principle, it is **good advice**, but it’s not a pure truth, nor is it a rule."

Martin further suggests that SOLID principles serve as **mental frameworks** for addressing common software development challenges:

> "The principles are mental cubby-holes.
> They **give a name to a concept** so that you can talk and reason about that concept. [...]
> These principles are **heuristics**.
> They are **common-sense solutions to common problems**. They are common-sense disciplines that can help you stay out of trouble.
> But like any heuristic, they are **empirical in nature**. They have been observed to work in many cases; but there is no proof that they always work, nor any proof that they should always be followed."

Characterizing SOLID as names for common solutions to recurrent problems resembles the definition of design patterns. It offers guidance within a specific context.

In his 2003 book [UML for Java Programmers](https://www.amazon.com/UML-Java%C2%BF-Programmers-Robert-Martin/dp/0131428489), Martin argues that we shouldn't always apply SOLID and shows the effects of doing so:

> "It is not wise to try to make all systems conform to all principles all the time, every time.
> You’ll spend an eternity trying to imagine all the different environments to apply to the [Open/Closed Principle], or all the different sources of change to apply to the [Single Responsibility Principle].
> You’ll cook up dozens or hundreds of little interfaces for the [Interface Segregation Principle], and create lots of worthless abstractions for the [Dependency Inversion Principle]."

So, are SOLID principles really principles? No. They're more like **guidelines**.

By viewing SOLID as guidelines coming from pragmatic advice, we can avoid needless complexity in our code and make more effective design decisions considering the unique contexts of our projects.