devnotes.

S — Single Responsibility, O — Open/Closed

SOLID is a set of five design principles, popularized by Robert C. Martin ('Uncle Bob'), for writing maintainable, understandable OOP code. Each letter stands for one principle; this page and the next two cover all five.

S — Single Responsibility Principle (SRP): A class should have only one reason to change — it should have exactly one job or responsibility.

// Violates SRP — this class has THREE responsibilities
class Report {
    function generateData() { ... }
    function formatAsHtml() { ... }
    function saveToFile(path) { ... }
}
// A change to file storage logic, HTML formatting, OR data logic all force changes to this one class

// Follows SRP — each class has exactly one responsibility
class ReportData {
    function generate() { ... }
}
class ReportFormatter {
    function formatAsHtml(data) { ... }
}
class ReportSaver {
    function saveToFile(content, path) { ... }
}

SRP-compliant code is easier to test (each class does one narrow thing), easier to understand, and changes to one concern don't risk breaking unrelated logic bundled into the same class.

O — Open/Closed Principle (OCP): Classes should be open for extension but closed for modification — you should be able to add new behavior without changing existing, tested code.

// Violates OCP — adding a new shape means editing this function every time
function calculateArea(shape) {
    if shape.type == "circle": return 3.14159 * shape.radius ** 2
    if shape.type == "square": return shape.side ** 2
    // adding a triangle means modifying this existing, working function
}

// Follows OCP — new shapes extend the system without touching existing code
interface Shape {
    function area(): number
}
class Circle implements Shape { function area() { return 3.14159 * this.radius ** 2 } }
class Square implements Shape { function area() { return this.side ** 2 } }
// Adding Triangle just means writing a NEW class — zero changes to existing code
class Triangle implements Shape { function area() { return 0.5 * this.base * this.height } }

This is achieved primarily through polymorphism and interfaces (covered earlier): new functionality is added as new classes implementing an existing contract, rather than by editing a central function that already works and is already tested.

SOLID Principles: Single Responsibility & Open/Closed | DevNotes