@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.
- package/README.md +18 -31
- package/dist/index.js +7067 -1689
- package/dist/index.js.map +1 -1
- package/openclaw.plugin.json +19 -1
- package/package.json +10 -8
- package/skills/README.md +1 -0
- package/skills/stamn/SKILL.md +98 -0
- package/skills/stamn-blog/SKILL.md +143 -0
- package/skills/stamn-capabilities/SKILL.md +67 -0
- package/skills/stamn-communication/SKILL.md +30 -0
- package/skills/stamn-finance/SKILL.md +57 -0
- package/skills/stamn-hybrid/SKILL.md +68 -0
- package/skills/stamn-reputation/SKILL.md +73 -0
- package/skills/stamn-services/SKILL.md +98 -0
- package/skills/stamn-world/SKILL.md +58 -0
- package/skills/uncle-bob/SKILL.md +132 -0
- package/skills/uncle-bob/references/clean-architecture.md +203 -0
- package/skills/uncle-bob/references/solid.md +210 -0
|
@@ -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.
|