SOLID Principles for Programming Success: The Ultimate Guide to Writing Rock-Solid Code

Jason Kam
4 min readJul 3, 2023

--

SOLID Principles for Programming Success: The Ultimate Guide to Writing Rock-Solid Code
SOLID Principles for Programming Success: The Ultimate Guide to Writing Rock-Solid Code

In the world of software development, writing maintainable and scalable code is a paramount goal. One approach that has gained immense popularity is the SOLID principle. SOLID is an acronym for five design principles — Single Responsibility, Open/Closed, Liskov Substitution, Interface Segregation, and Dependency Inversion. In this article, we’ll explore these principles and demonstrate their application using JavaScript examples. Let’s dive in!

Follow Me to Stay Up to Date for More Tips & Tricks! 🔔😜

Suppose we are building an e-commerce platform and need to implement the shopping cart functionality. Let’s see how SOLID principles can guide us in designing and implementing the cart feature.

1. Single Responsibility Principle (SRP)

The Single Responsibility Principle states that a class should have only one reason to change. In other words, a class should have a single responsibility. By adhering to this principle, we can create code that is easier to understand, maintain, and test.

The ShoppingCart class should have a single responsibility, which is managing the items in the cart.

class ShoppingCart {
constructor() {
this.items = [];
}

addItem(item) {
this.items.push(item);
}

removeItem(item) {
const index = this.items.indexOf(item);
if (index !== -1) {
this.items.splice(index, 1);
}
}

getTotalPrice() {
let total = 0;
for (const item of this.items) {
total += item.price;
}
return total;
}
}

The ShoppingCart class takes care of adding and removing items from the cart and calculating the total price. It focuses solely on managing the cart's functionality.

2. Open/Closed Principle (OCP):

The Open/Closed Principle states that software entities (classes, modules, functions) should be open for extension but closed for modification. This principle encourages us to design code that can be easily extended without modifying existing code.

The ShoppingCart class should be open for extension but closed for modification. Let's introduce a discount feature without modifying the existing class.

class ShoppingCart {
// ...

applyDiscount(discount) {
const total = this.getTotalPrice();
const discountedPrice = total - (total * (discount / 100));
return discountedPrice;
}
}

By adding the applyDiscount method, we extend the functionality of the ShoppingCart class without modifying its existing code. This allows us to introduce new features without impacting the existing implementation.

3. Liskov Substitution Principle (LSP)

The Liskov Substitution Principle states that objects of a superclass should be replaceable with objects of its subclasses without affecting the correctness of the program. In simpler terms, it means that derived classes must be substitutable for their base classes.

Let’s create two types of products: PhysicalProduct and DigitalProduct. Both types can be added to the shopping cart.

class Product {
constructor(name, price) {
this.name = name;
this.price = price;
}
}

class PhysicalProduct extends Product {
// ...
}

class DigitalProduct extends Product {
// ...
}

const cart = new ShoppingCart();
const physicalProduct = new PhysicalProduct('Keyboard', 50);
const digitalProduct = new DigitalProduct('eBook', 20);

cart.addItem(physicalProduct);
cart.addItem(digitalProduct);

In this example, both PhysicalProduct and DigitalProduct inherit from the Product class. Since they are subclasses of Product, they can be substituted wherever Product is expected, such as when adding items to the shopping cart.

4. Interface Segregation Principle (ISP)

The Interface Segregation Principle states that clients should not be forced to depend on interfaces they do not use. It promotes the idea of creating smaller, focused interfaces rather than large, monolithic ones.

Let’s consider that we have additional functionality related to shipping. We can segregate the cart’s responsibilities by introducing separate interfaces for shipping-related operations.

class ShoppingCart {
// ...

calculateShipping() {
// Calculate shipping cost
}

generateShippingLabel() {
// Generate shipping label
}
}

class Shipping {
calculateShipping() {
// Calculate shipping cost
}

generateShippingLabel() {
// Generate shipping label
}
}

class ShippingLabelGenerator {
generateShippingLabel() {
// Generate shipping label
}
}

By segregating the interfaces, we ensure that clients (other modules, components) depend only on the methods they require. For instance, the Shipping class and the ShippingLabelGenerator class handles different shipping-related responsibilities.

5. Dependency Inversion Principle (DIP)

The Dependency Inversion Principle states that high-level modules should not depend on low-level modules. Both should depend on abstractions. It promotes loose coupling between modules and facilitates easier testing and maintenance.

Let’s assume we need to persist the cart data. We can introduce a repository interface and inject it into the ShoppingCart class.

class CartRepository {
save(cart) {
// Save the cart data
}
}

class ShoppingCart {
constructor(cartRepository) {
this.cartRepository = cartRepository;
// ...
}

saveCart() {
this.cartRepository.save(this);
}
}

By depending on the CartRepository interface instead of a specific implementation, we decouple the ShoppingCart class from the concrete repository, allowing us to easily switch implementations or mock the repository for testing purposes.

Conclusion

By understanding and applying the SOLID principles, we can create more maintainable, flexible, and scalable JavaScript applications. These principles guide us toward writing code that is easier to understand, test, and extend. Embracing SOLID principles is a vital step toward becoming a more proficient and professional developer.

So go ahead, refactor your code, and start building robust JavaScript applications using the power of SOLID principles!

Thinks

Writing has always been my passion and it gives me pleasure to help and inspire people. If you have any questions, feel free to reach out!

Thank you for reading this far, please give this article a round of applause if you can, or give me a follow, I will thank you from the bottom of my heart

--

--