SOLID design principles with JAVASCRIPT

Upendra Ihalagedara
5 min readFeb 26, 2022

SOLID is a very popular set of design patterns developers use in object-oriented software development. The name SOLID itself stand for five design principles. They are,

· Single responsibility

· Open-close

· Liskov substitution

· Interface segregation

· Dependency inversion.

From here onwards let’s talk about each of them.

Single responsibility

The main idea given by the single responsibility principle is, “A class should have one reason to change”. Which means a class should have a unique functionality or responsibility. So, in that way it will be easy to maintain our code for us as well as for the others. By following the single responsibility principle, it will make the implementation,

· Easier to understand

· Help to prevent errors in changes

· More flexible

· Easier to test

We can apply this principle not only for classes but also for functions, software components, API’s etc.

If we consider the above example we can see that there are two methods for the customer. Although the greet method is about the customer validateCard method is another responsibility to the customer. Therefore, any changes to the validateCard can make changes to the customer. The correct way to do it is to put the validateCard responsibility to a different class.

As the given two examples we can create another class to validateCard. Now any changes to the validate method will not affect the customer.

Open-closed

The main idea of the open-close principle is “classes, modules or any software entity should be open for extension, but it should be closed for modification”. In simpler words other than changing a class, we can simply extend the class in order to do the necessary changes. Otherwise it can make errors in the implementation. With the help of this principle as the benefits we can mention,

· More maintainable

· Longevity of the application

· Minimize risk when adding new behavior

· Less error prone for the existing implementation

In the below example let’s say we need to calculate the discount according to the payments and the discounts. But in any case, like we need to calculate the discount for a vip customer we need to use the vip discount as well.

Therefor in that case we can create another class for vipCustomers and do the necessary implementations as given below. So, inside the new class we created we can get the vipDiscount and override the getDiscount method in the new class.

Liskov substitution

The principle says that every subclass should be able to substitute their parent class. This principle is like an extension of open-closed principle. In a simpler meaning the child class should contain the functionalities of the parent class while not having a different behavior to the functionalities or methods in the parent class. With the use of this principle we can find some advantages like,

· Easy maintainability

· Code reusability

As the disadvantages we can mention that,

· Create unnecessary entanglements

· Low performance

· More error prone

As we can see in the given example we can’t extend the customer class methods to the waiter class. But we can create another class for the Vip customer and extend the methods. That means base class should not be extended if the child class cannot accept its parent class methods.

Interface segregation

The main idea is “client should not be forced to implement methods they do not use”. According to this principle it will be better if can use rather more specific interfaces than using them in the regularly used general purpose interfaces. So that we can use specific interfaces rather than using the larger once. So, in that way,

· We can reduce the complexity

· We can increase the maintainability

Increase the readability

In the above example you can see the interface implementation in typescript. So, we can create an interface newCustomer and implement it in the Vip customer class.

Dependency inversion principle

The main idea is “high level modules which provide complex logic should be easily reusable and unaffected by changes in low level modules which provide utility features”. In other words, it means high level modules should not depend on lower level modules so we should use abstraction and interfaces. So that we will be able to have a more,

· Flexible

· Reusable

Implementation.

In the above scenario we are providing a service inside the constructor. So, we have the problem that high-level modules depend on low level modules. To solve this problem, we can change the CustomerController class to refer only an abstraction of the service class. The example is given in the below.

--

--