SOLID principles guide the creation of mid-level software structures that:
Can tolerate change
Are easy to understand
Are reusable in many software systems
The SOLID principles contains the following 5 principles, which forms the acronym
Single Responsibility Principle
Open-Closed Principle
Liskov Substitution Principle
Interface Segregation Principle
Dependency Inversion Principle
Chapter 7 - SRP: The Single Reponsibility Principle
Commonly misunderstood that SRP is the same as saying a function should do one, and only one thing
SRP states that "a module should have one, and only one, reason to change"
Systems change to satisfy users / stakeholders
These users / stakeholders, or an actor (group of people) are the "reason to change" which is what the principle refers to
SRP can be rephrased to "a module should be responsible to one, and only one, actor"
A module can refer to a source file or a cohesive set of functions and data structures
The word cohesive implies SRP, binding code reponsible to a single actor
Symptom 1: Accidental Duplication
Ex. Employee class
Each method serves a different stakeholder
calculatePay(): Accounting department (CFO)
reportHours(): Human Resources (COO)
save(): Database administrators (CTO)
Issues
Coupling responsibilities: Different departments’ requirements are mixed in one class, leading to unintended dependencies
Shared code risks: Common code used by multiple methods can cause issues when changes are made, affecting all methods and potentially breaking multiple functionalities
Different responsibilities should be separated into different classes or modules to avoid accidental duplication and unintended side effects
Symptom 2: Merges
Issues
Conflict: Different developers making changes simultaneously can lead to merge conflicts
Large classes with many methods: Merges are common in source files with many methods, especially if those methods serve different stakeholders
Risks
Tools can't deal with every conflict, manually resolving them comes with risks and a chance to introduce errors or bugs
Widespread impact: Changes to a common module might affect unintended parts of the system
Different responsibilities should be separated into distinct classes or modules to minimize merge conflicts and reduce risks associated with changes
Solutions
Separate data from functions, dividing functionality into separate classes operating on a shared data structure
Avoids duplication and reduces coupling
Downside is managing multiple classes, which can complicate instantiation and tracking
Use the Facade Pattern, implement a Facade class which instantiates and delegates tasks to the various functional classes
Simplifies the interface by providing a single entry point and provides encapsulation of the underlying classes
Retain important business methods closer to the data, turn the original class into a Facade class
Keeps important methods accessible and maintains a similar interface while separating concerns
Conclusion
SRP applies to functions and classes, ensuring they have only one reason to change
At the component level, it becomes the Common Closure Principle
Groups related classes that change together, promoting modularity and reducing interdependencies
At the architectural level, it becomes the Axis of Change
Creates architectural boundaries to manage changes at a higher level, ensuring system stability and flexibility