$npx -y skills add krzysztofsurdy/code-virtuoso --skill solidSOLID principles for object-oriented design with multi-language examples (PHP, Java, Python, TypeScript, C++). Use when the user asks to review SOLID compliance, fix a SOLID violation, evaluate class design, reduce coupling, improve extensibility, or apply Single Responsibility,
| 1 | # SOLID Principles |
| 2 | |
| 3 | Five core principles of object-oriented design that lead to systems which are simpler to maintain, test, and extend. Robert C. Martin (Uncle Bob) formalized these ideas, and Michael Feathers coined the SOLID acronym. |
| 4 | |
| 5 | ## Principle Index |
| 6 | |
| 7 | | Principle | Summary | Reference | |
| 8 | |---|---|---| |
| 9 | | **S** — Single Responsibility | A class should have only one reason to change | [reference](references/srp.md) | |
| 10 | | **O** — Open/Closed | Open for extension, closed for modification | [reference](references/ocp.md) | |
| 11 | | **L** — Liskov Substitution | Subtypes must be substitutable for their base types | [reference](references/lsp.md) | |
| 12 | | **I** — Interface Segregation | Prefer many specific interfaces over one general-purpose interface | [reference](references/isp.md) | |
| 13 | | **D** — Dependency Inversion | Depend on abstractions, not concretions | [reference](references/dip.md) | |
| 14 | |
| 15 | ## Why SOLID Matters |
| 16 | |
| 17 | Without SOLID, codebases gradually develop these problems: |
| 18 | |
| 19 | - **Rigidity** — one change ripples through many unrelated modules |
| 20 | - **Fragility** — modifying one area breaks another seemingly unconnected area |
| 21 | - **Immobility** — components are so intertwined that extracting them for reuse is impractical |
| 22 | - **Viscosity** — doing things correctly is harder than hacking around the design |
| 23 | |
| 24 | SOLID tackles each of these by defining clear boundaries, explicit contracts, and flexible points for extension. |
| 25 | |
| 26 | ## Quick Decision Guide |
| 27 | |
| 28 | | Symptom | Likely Violated Principle | Fix | |
| 29 | |---|---|---| |
| 30 | | Class does too many things | **SRP** | Split into focused classes | |
| 31 | | Adding a feature requires editing existing classes | **OCP** | Introduce polymorphism or strategy | |
| 32 | | Subclass breaks when used in place of parent | **LSP** | Fix inheritance hierarchy or use composition | |
| 33 | | Classes forced to implement unused methods | **ISP** | Break interface into smaller ones | |
| 34 | | High-level module imports low-level details | **DIP** | Introduce an abstraction layer | |
| 35 | |
| 36 | ## Quick Examples |
| 37 | |
| 38 | ### SRP — Before and After |
| 39 | |
| 40 | ```php |
| 41 | // BEFORE: Class handles both user data AND email sending |
| 42 | class UserService { |
| 43 | public function createUser(string $name, string $email): void { /* ... */ } |
| 44 | public function sendWelcomeEmail(string $email): void { /* ... */ } |
| 45 | } |
| 46 | |
| 47 | // AFTER: Each class has one responsibility |
| 48 | class UserService { |
| 49 | public function __construct(private UserNotifier $notifier) {} |
| 50 | public function createUser(string $name, string $email): void { |
| 51 | // persist user... |
| 52 | $this->notifier->welcomeNewUser($email); |
| 53 | } |
| 54 | } |
| 55 | |
| 56 | class UserNotifier { |
| 57 | public function welcomeNewUser(string $email): void { /* ... */ } |
| 58 | } |
| 59 | ``` |
| 60 | |
| 61 | ### OCP — Extend Without Modifying |
| 62 | |
| 63 | ```php |
| 64 | interface DiscountPolicy { |
| 65 | public function calculate(float $total): float; |
| 66 | } |
| 67 | |
| 68 | class PercentageDiscount implements DiscountPolicy { |
| 69 | public function __construct(private float $rate) {} |
| 70 | public function calculate(float $total): float { |
| 71 | return $total * $this->rate; |
| 72 | } |
| 73 | } |
| 74 | |
| 75 | // Adding a new discount type requires NO changes to existing code |
| 76 | class FlatDiscount implements DiscountPolicy { |
| 77 | public function __construct(private float $amount) {} |
| 78 | public function calculate(float $total): float { |
| 79 | return min($this->amount, $total); |
| 80 | } |
| 81 | } |
| 82 | ``` |
| 83 | |
| 84 | ### DIP — Depend on Abstractions |
| 85 | |
| 86 | ```php |
| 87 | // High-level policy depends on abstraction, not on database details |
| 88 | interface OrderRepository { |
| 89 | public function save(Order $order): void; |
| 90 | } |
| 91 | |
| 92 | class PlaceOrderHandler { |
| 93 | public function __construct(private OrderRepository $repository) {} |
| 94 | public function handle(PlaceOrderCommand $cmd): void { |
| 95 | $order = Order::create($cmd->items); |
| 96 | $this->repository->save($order); |
| 97 | } |
| 98 | } |
| 99 | ``` |
| 100 | |
| 101 | ## Relationships Between Principles |
| 102 | |
| 103 | The five principles complement and reinforce one another: |
| 104 | |
| 105 | - **SRP + ISP**: Both narrow the surface area of a class or interface to a single, focused concern |
| 106 | - **OCP + DIP**: Abstractions are the mechanism that enables extension without modification |
| 107 | - **LSP + OCP**: Correct substitutability is essential for polymorphic extension to work |
| 108 | - **ISP + DIP**: Well-segregated interfaces make it easier to depend on precisely the right abstraction |
| 109 | |
| 110 | ## Common Misconceptions |
| 111 | |
| 112 | - **"One method per class"** — SRP means one *reason to change*, not one method. A class can contain many methods as long as they all serve the same responsibility. |
| 113 | - **"Never modify existing code"** — OCP does not prohibit bug fixes. It me |