@stamn/stamn-plugin 0.1.0-alpha.4 → 0.1.0-alpha.41

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,210 @@
1
+ # SOLID Principles — Detailed Guide
2
+
3
+ ## S — Single Responsibility Principle (SRP)
4
+
5
+ > "A module should have one, and only one, reason to change."
6
+
7
+ More precisely: a module should be responsible to one, and only one, actor (stakeholder).
8
+
9
+ ### Violation
10
+
11
+ ```typescript
12
+ class Employee {
13
+ calculatePay() // CFO's team cares about this
14
+ reportHours() // COO's team cares about this
15
+ save() // CTO's team cares about this
16
+ }
17
+ ```
18
+
19
+ Three actors, three reasons to change. A change for payroll could break hour reporting.
20
+
21
+ ### Fix
22
+
23
+ Separate into three classes, each responsible to one actor. Use a facade if you need a single entry point.
24
+
25
+ ```typescript
26
+ class PayCalculator { calculatePay(employee: Employee) {} }
27
+ class HourReporter { reportHours(employee: Employee) {} }
28
+ class EmployeeSaver { save(employee: Employee) {} }
29
+ ```
30
+
31
+ ### Heuristic
32
+
33
+ If you describe a class and use "and" — it probably has multiple responsibilities.
34
+
35
+ ---
36
+
37
+ ## O — Open/Closed Principle (OCP)
38
+
39
+ > "Software entities should be open for extension, closed for modification."
40
+
41
+ Add new behavior by adding new code, not changing existing code.
42
+
43
+ ### Violation
44
+
45
+ ```typescript
46
+ function calculateArea(shape: Shape) {
47
+ if (shape.type === 'circle') return Math.PI * shape.radius ** 2
48
+ if (shape.type === 'rectangle') return shape.width * shape.height
49
+ // Every new shape = modify this function
50
+ }
51
+ ```
52
+
53
+ ### Fix
54
+
55
+ Use polymorphism:
56
+
57
+ ```typescript
58
+ interface Shape { area(): number }
59
+
60
+ class Circle implements Shape {
61
+ constructor(private radius: number) {}
62
+ area() { return Math.PI * this.radius ** 2 }
63
+ }
64
+
65
+ class Rectangle implements Shape {
66
+ constructor(private width: number, private height: number) {}
67
+ area() { return this.width * this.height }
68
+ }
69
+ ```
70
+
71
+ New shapes extend the system without modifying `calculateArea`.
72
+
73
+ ### Heuristic
74
+
75
+ If adding a feature requires modifying a switch/case or if-else chain, consider OCP.
76
+
77
+ ---
78
+
79
+ ## L — Liskov Substitution Principle (LSP)
80
+
81
+ > "Subtypes must be substitutable for their base types."
82
+
83
+ If `S` extends `T`, anywhere you use `T` you should be able to use `S` without surprises.
84
+
85
+ ### Classic Violation: Square/Rectangle
86
+
87
+ ```typescript
88
+ class Rectangle {
89
+ setWidth(w: number) { this.width = w }
90
+ setHeight(h: number) { this.height = h }
91
+ }
92
+
93
+ class Square extends Rectangle {
94
+ setWidth(w: number) { this.width = w; this.height = w }
95
+ setHeight(h: number) { this.width = h; this.height = h }
96
+ }
97
+
98
+ // Breaks expectations:
99
+ function resize(r: Rectangle) {
100
+ r.setWidth(5)
101
+ r.setHeight(10)
102
+ assert(r.area() === 50) // Fails for Square!
103
+ }
104
+ ```
105
+
106
+ ### Fix
107
+
108
+ Don't model Square as a subtype of Rectangle. Use composition or separate types.
109
+
110
+ ### Heuristic
111
+
112
+ If a subclass overrides a method to do something the caller wouldn't expect, it violates LSP.
113
+
114
+ ---
115
+
116
+ ## I — Interface Segregation Principle (ISP)
117
+
118
+ > "Clients should not be forced to depend on methods they don't use."
119
+
120
+ ### Violation
121
+
122
+ ```typescript
123
+ interface Worker {
124
+ work(): void
125
+ eat(): void
126
+ sleep(): void
127
+ }
128
+
129
+ // A Robot worker doesn't eat or sleep
130
+ class Robot implements Worker {
131
+ work() { /* ... */ }
132
+ eat() { throw new Error('Robots do not eat') }
133
+ sleep() { throw new Error('Robots do not sleep') }
134
+ }
135
+ ```
136
+
137
+ ### Fix
138
+
139
+ Split into focused interfaces:
140
+
141
+ ```typescript
142
+ interface Workable { work(): void }
143
+ interface Feedable { eat(): void }
144
+ interface Restable { sleep(): void }
145
+
146
+ class Human implements Workable, Feedable, Restable { /* ... */ }
147
+ class Robot implements Workable { /* ... */ }
148
+ ```
149
+
150
+ ### Heuristic
151
+
152
+ If implementing an interface forces you to write empty methods or throw "not supported", the interface is too fat.
153
+
154
+ ---
155
+
156
+ ## D — Dependency Inversion Principle (DIP)
157
+
158
+ > "Depend on abstractions, not concretions."
159
+
160
+ High-level modules (policy) must not depend on low-level modules (details). Both should depend on abstractions.
161
+
162
+ ### Violation
163
+
164
+ ```typescript
165
+ class OrderService {
166
+ private db = new PostgresDatabase() // Concrete dependency
167
+
168
+ createOrder(order: Order) {
169
+ this.db.insert('orders', order)
170
+ }
171
+ }
172
+ ```
173
+
174
+ ### Fix
175
+
176
+ Depend on an abstraction; inject the implementation:
177
+
178
+ ```typescript
179
+ interface OrderRepository {
180
+ save(order: Order): Promise<void>
181
+ }
182
+
183
+ class OrderService {
184
+ constructor(private repository: OrderRepository) {}
185
+
186
+ createOrder(order: Order) {
187
+ this.repository.save(order)
188
+ }
189
+ }
190
+
191
+ // Inject at composition root:
192
+ const service = new OrderService(new PostgresOrderRepository())
193
+ ```
194
+
195
+ ### Heuristic
196
+
197
+ If a class instantiates its own dependencies with `new`, it's likely violating DIP. Inject dependencies through the constructor.
198
+
199
+ ---
200
+
201
+ ## Applying SOLID Together
202
+
203
+ These principles reinforce each other:
204
+
205
+ - SRP keeps classes focused → easier to apply OCP
206
+ - OCP uses polymorphism → requires LSP-compliant subtypes
207
+ - ISP keeps interfaces thin → makes DIP practical
208
+ - DIP enables testing → which validates LSP
209
+
210
+ Don't apply them dogmatically. They're tools for managing complexity. A simple script doesn't need SOLID. A growing system does.