How to Implement the SOLID Principle in JavaScript?

A beginner’s tutorial on the basics of the SOLID principle and how to implement it in JavaScript programming.

Kobe
JavaScript in Plain English

--

Photo by Arnold Francisca on Unsplash

This article will give you a basic concept of the SOLID principle in the JavaScript language. We will have a different way of following this principle with each language. However, in JavaScript, it’s very difficult to apply this principle in the code.

To make it easy for you, I have shown you the way of implementing the code. I have mixed 2 methods (class and function) in the example to apply the code following the SOLID principle.

This principle helps us build software. Here are the key features of the SOLID principle:

  • The code reusability.
  • Easy to make a code change in the feature.
  • Keeps the code easy to maintain.
  • Easy to write a test for the code.

What does SOLID stand for?

We will go into detail about each character in the word “SOLID”.

S: Single Responsibility

A class (method) should have only single responsibility

Code Example:

From the example, we can see that the (SuperTool) has many responsibilities to handle for a Sword action and Bow action. This class (method) can become complex when we add more and more action to it. We have to read and maintain it when a newcomer must understand the class before they want to make a change (they are worried about the impact of new change).

The goal of this principle is: Separate the class (method) behaviors into a single point action. Break the code (class, function) into as small components as possible.

Instead of building super tools with a lot of (n) tools in 1. Just break the support tool into multiple tools and each tool will have to be responsible for all its actions. It helps the code base be clear that when a new feature changes on the SwordTool class (or BowTool) we don’t end up affecting another tool.

O: Open-Closed

Open for extension, but closed for modification

This principle is related to code maintenance and new code change. To easy to understand the principle example in the system we have an existing class Person ( it has all attributes, methods of a human jump, run, eat…etc). the new feature wants to add a SwordMan or Wizard to our system and they also have all attributes and behavior like a Person class. However, if we change the current behavior of the person class to satisfy the requirement example the person can jump 1m high and the SwordMan can jump 100m high on the earth. we must modify the existing function of the person class. It can have side effects on the system where you are using that class.

Code Example:

The goal of this principle: The new code change should avoid impacting the existence of the class as much as possible. It helps the new feature ( new code change ) avoid causing bugs and impacting the original class. Instead, to modify the Person class we can extend the Person class from SwordMan, and Wizard class, and handle the functionality of that character by itself, and don’t worry about where using the Person class and the new classes used for a new feature without impact anything from the old feature.

Liskov’s Substitution

Objects in a program should be replaceable with instances of their subtypes without altering the correctness of that program. -Wikipedia

This principle sticks to the OOP concept and it told about the way we create an abstraction and define relationships between parent class (supertype) and child class (subtype). If the child class cannot perform the same actions as its parent class it can happen an unknown issue in the future.

Code Example:

#Q1: Is the BlindSwordMan a person? -> Yes

#Q2: Can the Person (Super Class) view the cloud? -> Yes, I can

#Q3: Can the BlindSwordMan (Sub Class) view the cloud? -> No, I can’t

The unknown issue can happen on the system from the first example you can call the `view` action on the BlindSwordMan. So to fix the problem we should define correct the abstract classes and the BlindSwordMan shouldn’t implement the `view` method like a normal person.

The goal of this principle is: Avoid the inconsistency between the parent class and the child class and make sure that the supper class can do it and the child class also can do it as well.

Interface Segregation

“Many client-specific interfaces are better than one general-purpose interface. -Wikipedia”

The principle resolves the issues caused when we try to implement a big interface.

The goal of this principle is: should splitting a set of actions into smaller sets so that a class ONLY runs the set of actions it requires. It help us reduce dependencies less coupled between classes in the system and more reusable between interfaces.

Dependency Inversion

One should “depend upon abstractions, [not] concretions.” -Wikipedia

In a simple way, you can think that a class should not contain dependencies (external services) in itself. It makes the class become stick by that service. Otherwise, external services should work in a single way reduce dependence on each other making the code clean and easy to use by another class.

When a class wants to use another class or another service we can inject it via the constructor or use a wrapper to return a new instance with services injected.

Conclusion

SOLID is not for everything. With each language, you will have a way to specifically deal with the problem. Some principles stick to OOP (classes, interfaces, abstractions) that you can’t apply to GUI programming (functional programming)

It is not a rule, don’t force yourself to adhere to it. However, it helps your mind think of ways to make your code easy to read, and easy to maintain.

More content at PlainEnglish.io. Sign up for our free weekly newsletter. Follow us on Twitter, LinkedIn and Discord.

--

--

I’m working at KMS-Technology company. I love code (▀̿Ĺ̯▀̿ ̿) — Full Stack Software Engineer