SOLID Pattern — Single-Responsibility Principle

Kevin Bartsch
3 min readMar 25, 2024

--

Greetings, today let’s dive into another SOLID pattern the Single-Responsibility Principle (SRP) with TypeScript. With this pattern we are able to improve issues like maintainability and scalability.
Level: Beginner

The SRP, championed by the venerable Robert C. Martin, admonishes us to imbue our classes with a singular purpose, ensuring that each class is responsible for just one aspect of functionality within our codebase. But how does this manifest in the TypeScript ecosystem? Let’s look at some code examples to see that it is not that big of a deal.

Consider a hypothetical scenario where we’re crafting a rudimentary ship management system:

// A class representing a ship
class Ship {
private name: string;
private crew: string[];

constructor(name: string, crew: string[]) {
this.name = name;
this.crew = crew;
}

public sail(): void {
console.log(`${this.name} sets sail with a crew of ${this.crew.join(', ')}.`);
// Logic for setting sail
}

public loadCargo(cargo: string[]): void {
console.log(`${this.name} loads cargo: ${cargo.join(', ')}.`);
// Logic for loading cargo
}
}

Here, our Ship class seems okay at first glance, handling both sailing and cargo-loading duties. However, the SRP recommends us to separate concerns more distinctly. Let's follow this:

// A class representing a ship
class Ship {
private name: string;
private crew: string[];

constructor(name: string, crew: string[]) {
this.name = name;
this.crew = crew;
}

public sail(): void {
console.log(`${this.name} sets sail with a crew of ${this.crew.join(', ')}.`);
// Logic for setting sail
}
}

// A separate class for managing cargo operations
class CargoManager {
public loadCargo(ship: Ship, cargo: string[]): void {
console.log(`${ship.name} loads cargo: ${cargo.join(', ')}.`);
// Logic for loading cargo
}
}

By untangling cargo-related operations into a distinct CargoManager class, we honor the SRP, ensuring that each class has a singular responsibility. This fosters code that's easier to comprehend, maintain, and extend—a improvement indeed!

Let’s have a look and delve into the pros and cons of the Single-Responsibility Principle (SRP).

💡Pros:

  1. Clarity and Maintainability: By adhering to the SRP, we create classes that are focused and concise, making our codebase easier to understand and maintain. Each class encapsulates a single responsibility, reducing cognitive load and facilitating future modifications.
  2. Scalability: Separating concerns according to the SRP fosters modularization, enabling us to scale our codebase more efficiently. As our project grows, we can add new functionality without disturbing existing code, promoting code reuse and extensibility.
  3. Testability: With well-defined responsibilities, our classes become more testable. Unit testing becomes simpler, as we can isolate individual components and verify their behavior independently, leading to more robust and reliable code.

🚨Cons:

  1. Increased Complexity: Adhering strictly to the SRP can sometimes lead to an explosion of classes, introducing additional complexity and overhead. Managing a multitude of small classes may become cumbersome, especially in smaller projects or when dealing with simple functionalities.
  2. Indirection and Abstraction: Dividing responsibilities into separate classes may introduce indirection, making it harder to trace the flow of logic through our codebase. This abstraction layer can sometimes obscure the relationships between different components, requiring developers to invest extra effort in understanding the code.
  3. Potential Over-Engineering: In our zeal to uphold the SRP, we must guard against over-engineering. Splitting responsibilities too finely can lead to unnecessary abstraction and code bloat, complicating the codebase without providing significant benefits in terms of clarity or maintainability.

Conclusion: Following the Single Responsibility Principle (SRP) makes our code easier to maintain, but it also means we might need more classes and extra steps, which can add some complexity. In short we must strike a balance between clarity and pragmatism.

Hope you enjoyed this little articel! Feel free to follow and sharing my library of knowledge, that’s been created here.

Photo by Sigmund on Unsplash

--

--

Kevin Bartsch

Passionate Developer, UX/UI Aficionado. Sharing knowledge, igniting connections. Let's build, learn, and create something extraordinary! ✨