S.O.L.I.D Principles Explained In Five Minutes

A guide to understandable, reusable, testable, maintanable and flexible codebase.

Petey
Petey
Nov 17, 2019 · 5 min read
Photo by Clément H on Unsplash

S.O.L.I.D is an acronym used in software engineering that describes a set of principles of object-oriented design. When a system is implementing by using these principles, the codebase is understandable, reusable, testable, maintainable and flexible. The concept originated from Robert C. Martin. It has been adopted and used amongst software engineers ever since.

S.O.L.I.D stands for

  • Single-responsibility principle (SRP)

Single-responsibility principle (SRP)

This principle states that a class should only have a single responsibility. This simply means only changes to one part of the software’s specification should be able to affect the specification of the class.

Consider the PaymentProcessing class code snippet below

public class PaymentProcessing
{
public void Process(object obj)
{
//process logic here
}
}

This class abides by the single-responsibility principle because it only does one thing and that is to process payment. If we were to add a method that does something other than processing payment, then that would violate the single-responsibility principle. The reason being is because that class would now have multiple responsibilities. Let’s say we wanted to also process Discounts in concert in payments. You might be tempted to just add the logic to process discounts in the PaymentProcessing class. But payment processing and applying discounts to payment are two different things. The solution would be to change our payment class to return the processed payment object, then create a separate Discount class, then hand over the processed payment as a parameter to the Discount class. That way the payment class still has one responsibility and now we have a Discount class that only applies discounts to processed payments. A change to the Discount class wouldn’t affect the PaymentProcessing class and vice versa.

Open-closed principle (OCP)

This principle states that a class should be extendable, but closed to modification. That simply means any desired additional behavior should be added to another class that extends your original class instead of modifying it.

Consider the Vehicle class code snippet below

public class Vehicle
{
public string Make { get; set; }
public string Model { get; set; }
public string Trim { get; set; }
public string Year { get; set; }
public string Color { get; set; }
//vehicle related logic goes here
}

After implementing all the required functionalities, you find out a month later that there’s a Luxury type of vehicle that shares the same functionalities as your Vehicle class except for some added premium options. Modifying the vehicle class is not the right way to solve that issue. That would violate the open-closed principle. The way to solve the issue is to extend the Vehicle class and add the additional functionalities in your new class.

public class LuxuryVehicle : Vehicle
{
public List<string> AdditionalOptions { get; set; }
//luxury vehicle related logic goes here
}

By extending the Vehicle class, we inherit all the functionalities and we’re free to add whatever luxury-related logic in our new class without any fear of breaking existing functionality.

Liskov substitution principle (LSP)

This principle states that a derived class must be substitutable for its base class.

Using the example code from earlier, we must be able to swap our LuxuryVehice class for our Vehicle class with no issue. Supposed we add a new property to our base class named MSRP and add a new method call getHalfPrice(). All this method does is dividing the MSRP value by 2. The base class precondition is that the property value will always be greater than zero.

A few weeks after bragging about how awesome your Vehicle class is, you receive new requirements that allow the MSRP in your LuxuryVehicle class to be zero with added premium options. The new requirements violate the Liskov substitution principle. A way to solve that would be to create an interface for each of the vehicle classes with the appropriate method signatures. The vehicle class would have the getHalfPrice() method, then the LuxuryVehicle could have the getZeroMSRPPriceWithAddedOption().

Interface segregation principle (ISP)

This principle states that client-specific interfaces are better than one general-purpose interface.

Let’s say we had an interface called Staff, which would have methods such as teach, clean, processPayment, advise, etc… If we were to create a Professor class, we’d have to implement all these methods even though some of them are not related to being a professor. This interface violates the Interface segregation principle.

The solution would be to create client-specific interfaces such as Professor, Administrator, GuidanceCounselor, Janitor, etc... Each interface would have the appropriate method.

  • Professor -> teach()

Because of this fined grained approach, now clients can choose which one suits their specific needs. They wouldn’t have to implement method they don’t need.

Dependency inversion Principle (DIP)

This principle states that the high-level module must not depend on the low-level module, but they should depend on abstractions.

Consider the MessageBoard code snippet below

public class MessageBoard
{
private WhatUpMessage message;
public MessageBoard(WhatsUpMessage message)
{
this.message = message;
}
}

The high-level module MessageBoard now depends on the low-level WhatsUpMessage. If we needed to print the underlying message in the high-level module, we would now find ourselves at the mercy of the low-level module. We would have to write WhatsUpMessage specific logic to print that message. If later, FacebookMessage needed to be supported, we would have to modify the high-level module( tightly-coupled code). That violates the Dependency inversion principle.

A way to fix that would be to extract that dependency. Create an interface and add whatever your high-level module needs. Any class that needed to use your high-level module would have to implement that interface.

Your interface would look something like this

public interface IMessage
{
public void PrintMessage();
}

Your MessageBoard now would look like this

public class MessageBoard
{
private IMessage message;
public MessageBoard(IMessage message)
{
this.message = message;
}
public void PrintMessage()
{
this.message.PrintMessage();
}
}

The low-level module would look like this

public class WhatUpMessage : IMessage
{
public void PrintMessage()
{
//print whatsup message
}
}
public class FacebookMessage : IMessage
{
public void PrintMessage()
{
//print facebook message
}
}

That abstraction removes the dependency of the low-level module in your high-level module. The high-level module is now completely independent of any low-level module.

Using the S.O.L.I.D principles when writing code will make you a better developer and make your life a lot easier. You might even become the new popular person on the block if you’re the only one doing it. Thank you for making it to the end. Until next time, Happy coding.

If you like this article, you might like my other related articles

The Startup

Get smarter at building your thing. Join The Startup’s +725K followers.

Petey

Written by

Petey

Husband, father, engineer, musician, and writer by luck. I write mostly about whatever comes to mind. Follow me on this crazy writing journey if you dare.

The Startup

Get smarter at building your thing. Follow to join The Startup’s +8 million monthly readers & +725K followers.

Petey

Written by

Petey

Husband, father, engineer, musician, and writer by luck. I write mostly about whatever comes to mind. Follow me on this crazy writing journey if you dare.

The Startup

Get smarter at building your thing. Follow to join The Startup’s +8 million monthly readers & +725K followers.

Medium is an open platform where 170 million readers come to find insightful and dynamic thinking. Here, expert and undiscovered voices alike dive into the heart of any topic and bring new ideas to the surface. Learn more

Follow the writers, publications, and topics that matter to you, and you’ll see them on your homepage and in your inbox. Explore

If you have a story to tell, knowledge to share, or a perspective to offer — welcome home. It’s easy and free to post your thinking on any topic. Write on Medium

Get the Medium app

A button that says 'Download on the App Store', and if clicked it will lead you to the iOS App store
A button that says 'Get it on, Google Play', and if clicked it will lead you to the Google Play store