cursor-kit-cli 1.2.0-beta → 1.2.0-beta.2
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/dist/cli.cjs +333 -56
- package/dist/cli.cjs.map +1 -1
- package/dist/cli.js +334 -57
- package/dist/cli.js.map +1 -1
- package/dist/index.cjs +39 -1
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +9 -1
- package/dist/index.d.ts +9 -1
- package/dist/index.js +33 -2
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
- package/templates/commands/docs.md +5 -3
- package/templates/commands/explain.md +5 -3
- package/templates/commands/fix.md +5 -3
- package/templates/commands/implement.md +5 -3
- package/templates/commands/refactor.md +5 -3
- package/templates/commands/review.md +5 -3
- package/templates/commands/test.md +5 -3
- package/templates/manifest.json +11 -8
- package/templates/rules/git.mdc +0 -2
- package/templates/rules/toc.mdc +17 -9
- package/templates/skills/aesthetic/SKILL.md +121 -0
- package/templates/skills/aesthetic/assets/design-guideline-template.md +163 -0
- package/templates/skills/aesthetic/assets/design-story-template.md +135 -0
- package/templates/skills/aesthetic/references/design-principles.md +62 -0
- package/templates/skills/aesthetic/references/design-resources.md +75 -0
- package/templates/skills/aesthetic/references/micro-interactions.md +53 -0
- package/templates/skills/aesthetic/references/storytelling-design.md +50 -0
- package/templates/skills/backend-development/SKILL.mdc +95 -0
- package/templates/skills/backend-development/references/backend-api-design.md +495 -0
- package/templates/skills/backend-development/references/backend-architecture.md +454 -0
- package/templates/skills/backend-development/references/backend-authentication.md +338 -0
- package/templates/skills/backend-development/references/backend-code-quality.md +659 -0
- package/templates/skills/backend-development/references/backend-debugging.md +904 -0
- package/templates/skills/backend-development/references/backend-devops.md +494 -0
- package/templates/skills/backend-development/references/backend-mindset.md +387 -0
- package/templates/skills/backend-development/references/backend-performance.md +397 -0
- package/templates/skills/backend-development/references/backend-security.md +290 -0
- package/templates/skills/backend-development/references/backend-technologies.md +256 -0
- package/templates/skills/backend-development/references/backend-testing.md +429 -0
- package/templates/skills/frontend-design/SKILL.mdc +41 -0
- package/templates/skills/frontend-design/references/animejs.md +396 -0
- package/templates/skills/frontend-development/SKILL.mdc +399 -0
- package/templates/skills/frontend-development/resources/common-patterns.md +331 -0
- package/templates/skills/frontend-development/resources/complete-examples.md +872 -0
- package/templates/skills/frontend-development/resources/component-patterns.md +502 -0
- package/templates/skills/frontend-development/resources/data-fetching.md +767 -0
- package/templates/skills/frontend-development/resources/file-organization.md +502 -0
- package/templates/skills/frontend-development/resources/loading-and-error-states.md +501 -0
- package/templates/skills/frontend-development/resources/performance.md +406 -0
- package/templates/skills/frontend-development/resources/routing-guide.md +364 -0
- package/templates/skills/frontend-development/resources/styling-guide.md +428 -0
- package/templates/skills/frontend-development/resources/typescript-standards.md +418 -0
- package/templates/skills/problem-solving/SKILL.mdc +96 -0
- package/templates/skills/problem-solving/references/attribution.md +69 -0
- package/templates/skills/problem-solving/references/collision-zone-thinking.md +79 -0
- package/templates/skills/problem-solving/references/inversion-exercise.md +91 -0
- package/templates/skills/problem-solving/references/meta-pattern-recognition.md +87 -0
- package/templates/skills/problem-solving/references/scale-game.md +95 -0
- package/templates/skills/problem-solving/references/simplification-cascades.md +80 -0
- package/templates/skills/problem-solving/references/when-stuck.md +72 -0
- package/templates/skills/research/SKILL.mdc +168 -0
- package/templates/skills/sequential-thinking/.env.example +8 -0
- package/templates/skills/sequential-thinking/README.md +183 -0
- package/templates/skills/sequential-thinking/SKILL.mdc +94 -0
- package/templates/skills/sequential-thinking/package.json +31 -0
- package/templates/skills/sequential-thinking/references/advanced-strategies.md +79 -0
- package/templates/skills/sequential-thinking/references/advanced-techniques.md +76 -0
- package/templates/skills/sequential-thinking/references/core-patterns.md +95 -0
- package/templates/skills/sequential-thinking/references/examples-api.md +88 -0
- package/templates/skills/sequential-thinking/references/examples-architecture.md +94 -0
- package/templates/skills/sequential-thinking/references/examples-debug.md +90 -0
- package/templates/skills/sequential-thinking/scripts/format-thought.js +159 -0
- package/templates/skills/sequential-thinking/scripts/process-thought.js +236 -0
- package/templates/skills/sequential-thinking/tests/format-thought.test.js +133 -0
- package/templates/skills/sequential-thinking/tests/process-thought.test.js +215 -0
- package/templates/skills/ui-styling/LICENSE.txt +202 -0
- package/templates/skills/ui-styling/SKILL.mdc +321 -0
- package/templates/skills/ui-styling/references/canvas-design-system.md +320 -0
- package/templates/skills/ui-styling/references/shadcn-accessibility.md +471 -0
- package/templates/skills/ui-styling/references/shadcn-components.md +424 -0
- package/templates/skills/ui-styling/references/shadcn-theming.md +373 -0
- package/templates/skills/ui-styling/references/tailwind-customization.md +483 -0
- package/templates/skills/ui-styling/references/tailwind-responsive.md +382 -0
- package/templates/skills/ui-styling/references/tailwind-utilities.md +455 -0
- package/templates/rules/frontend-design.mdc +0 -48
- package/templates/rules/performance.mdc +0 -54
- package/templates/rules/react.mdc +0 -58
- package/templates/rules/security.mdc +0 -50
- package/templates/rules/testing.mdc +0 -54
- package/templates/rules/typescript.mdc +0 -36
|
@@ -0,0 +1,659 @@
|
|
|
1
|
+
# Backend Code Quality
|
|
2
|
+
|
|
3
|
+
SOLID principles, design patterns, clean code practices, and refactoring strategies (2025).
|
|
4
|
+
|
|
5
|
+
## SOLID Principles
|
|
6
|
+
|
|
7
|
+
### Single Responsibility Principle (SRP)
|
|
8
|
+
|
|
9
|
+
**Concept:** Class/module should have one reason to change
|
|
10
|
+
|
|
11
|
+
**Bad:**
|
|
12
|
+
```typescript
|
|
13
|
+
class User {
|
|
14
|
+
saveToDatabase() { /* ... */ }
|
|
15
|
+
sendWelcomeEmail() { /* ... */ }
|
|
16
|
+
generateReport() { /* ... */ }
|
|
17
|
+
validateInput() { /* ... */ }
|
|
18
|
+
}
|
|
19
|
+
```
|
|
20
|
+
|
|
21
|
+
**Good:**
|
|
22
|
+
```typescript
|
|
23
|
+
class User {
|
|
24
|
+
constructor(public id: string, public email: string, public name: string) {}
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
class UserRepository {
|
|
28
|
+
async save(user: User) { /* ... */ }
|
|
29
|
+
async findById(id: string) { /* ... */ }
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
class EmailService {
|
|
33
|
+
async sendWelcomeEmail(user: User) { /* ... */ }
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
class UserValidator {
|
|
37
|
+
validate(userData: any) { /* ... */ }
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
class ReportGenerator {
|
|
41
|
+
generateUserReport(user: User) { /* ... */ }
|
|
42
|
+
}
|
|
43
|
+
```
|
|
44
|
+
|
|
45
|
+
### Open/Closed Principle (OCP)
|
|
46
|
+
|
|
47
|
+
**Concept:** Open for extension, closed for modification
|
|
48
|
+
|
|
49
|
+
**Bad:**
|
|
50
|
+
```typescript
|
|
51
|
+
class PaymentProcessor {
|
|
52
|
+
process(amount: number, method: string) {
|
|
53
|
+
if (method === 'stripe') {
|
|
54
|
+
// Stripe logic
|
|
55
|
+
} else if (method === 'paypal') {
|
|
56
|
+
// PayPal logic
|
|
57
|
+
}
|
|
58
|
+
// Adding new payment method requires modifying this class
|
|
59
|
+
}
|
|
60
|
+
}
|
|
61
|
+
```
|
|
62
|
+
|
|
63
|
+
**Good (Strategy Pattern):**
|
|
64
|
+
```typescript
|
|
65
|
+
interface PaymentStrategy {
|
|
66
|
+
process(amount: number): Promise<PaymentResult>;
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
class StripePayment implements PaymentStrategy {
|
|
70
|
+
async process(amount: number) {
|
|
71
|
+
// Stripe-specific logic
|
|
72
|
+
return { success: true, transactionId: '...' };
|
|
73
|
+
}
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
class PayPalPayment implements PaymentStrategy {
|
|
77
|
+
async process(amount: number) {
|
|
78
|
+
// PayPal-specific logic
|
|
79
|
+
return { success: true, transactionId: '...' };
|
|
80
|
+
}
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
class PaymentProcessor {
|
|
84
|
+
constructor(private strategy: PaymentStrategy) {}
|
|
85
|
+
|
|
86
|
+
async process(amount: number) {
|
|
87
|
+
return this.strategy.process(amount);
|
|
88
|
+
}
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
// Usage
|
|
92
|
+
const processor = new PaymentProcessor(new StripePayment());
|
|
93
|
+
await processor.process(100);
|
|
94
|
+
```
|
|
95
|
+
|
|
96
|
+
### Liskov Substitution Principle (LSP)
|
|
97
|
+
|
|
98
|
+
**Concept:** Subtypes must be substitutable for base types
|
|
99
|
+
|
|
100
|
+
**Bad:**
|
|
101
|
+
```typescript
|
|
102
|
+
class Bird {
|
|
103
|
+
fly() { /* ... */ }
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
class Penguin extends Bird {
|
|
107
|
+
fly() {
|
|
108
|
+
throw new Error('Penguins cannot fly!');
|
|
109
|
+
}
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
// Violates LSP - Penguin breaks Bird contract
|
|
113
|
+
```
|
|
114
|
+
|
|
115
|
+
**Good:**
|
|
116
|
+
```typescript
|
|
117
|
+
interface Bird {
|
|
118
|
+
move(): void;
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
class FlyingBird implements Bird {
|
|
122
|
+
move() {
|
|
123
|
+
this.fly();
|
|
124
|
+
}
|
|
125
|
+
private fly() { /* ... */ }
|
|
126
|
+
}
|
|
127
|
+
|
|
128
|
+
class Penguin implements Bird {
|
|
129
|
+
move() {
|
|
130
|
+
this.swim();
|
|
131
|
+
}
|
|
132
|
+
private swim() { /* ... */ }
|
|
133
|
+
}
|
|
134
|
+
```
|
|
135
|
+
|
|
136
|
+
### Interface Segregation Principle (ISP)
|
|
137
|
+
|
|
138
|
+
**Concept:** Clients shouldn't depend on interfaces they don't use
|
|
139
|
+
|
|
140
|
+
**Bad:**
|
|
141
|
+
```typescript
|
|
142
|
+
interface Worker {
|
|
143
|
+
work(): void;
|
|
144
|
+
eat(): void;
|
|
145
|
+
sleep(): void;
|
|
146
|
+
}
|
|
147
|
+
|
|
148
|
+
class Robot implements Worker {
|
|
149
|
+
work() { /* ... */ }
|
|
150
|
+
eat() { throw new Error('Robots don't eat'); }
|
|
151
|
+
sleep() { throw new Error('Robots don't sleep'); }
|
|
152
|
+
}
|
|
153
|
+
```
|
|
154
|
+
|
|
155
|
+
**Good:**
|
|
156
|
+
```typescript
|
|
157
|
+
interface Workable {
|
|
158
|
+
work(): void;
|
|
159
|
+
}
|
|
160
|
+
|
|
161
|
+
interface Eatable {
|
|
162
|
+
eat(): void;
|
|
163
|
+
}
|
|
164
|
+
|
|
165
|
+
interface Sleepable {
|
|
166
|
+
sleep(): void;
|
|
167
|
+
}
|
|
168
|
+
|
|
169
|
+
class Human implements Workable, Eatable, Sleepable {
|
|
170
|
+
work() { /* ... */ }
|
|
171
|
+
eat() { /* ... */ }
|
|
172
|
+
sleep() { /* ... */ }
|
|
173
|
+
}
|
|
174
|
+
|
|
175
|
+
class Robot implements Workable {
|
|
176
|
+
work() { /* ... */ }
|
|
177
|
+
}
|
|
178
|
+
```
|
|
179
|
+
|
|
180
|
+
### Dependency Inversion Principle (DIP)
|
|
181
|
+
|
|
182
|
+
**Concept:** Depend on abstractions, not concretions
|
|
183
|
+
|
|
184
|
+
**Bad:**
|
|
185
|
+
```typescript
|
|
186
|
+
class MySQLDatabase {
|
|
187
|
+
query(sql: string) { /* ... */ }
|
|
188
|
+
}
|
|
189
|
+
|
|
190
|
+
class UserService {
|
|
191
|
+
private db = new MySQLDatabase(); // Tight coupling
|
|
192
|
+
|
|
193
|
+
async getUser(id: string) {
|
|
194
|
+
return this.db.query(`SELECT * FROM users WHERE id = ${id}`);
|
|
195
|
+
}
|
|
196
|
+
}
|
|
197
|
+
```
|
|
198
|
+
|
|
199
|
+
**Good (Dependency Injection):**
|
|
200
|
+
```typescript
|
|
201
|
+
interface Database {
|
|
202
|
+
query(sql: string, params: any[]): Promise<any>;
|
|
203
|
+
}
|
|
204
|
+
|
|
205
|
+
class MySQLDatabase implements Database {
|
|
206
|
+
async query(sql: string, params: any[]) { /* ... */ }
|
|
207
|
+
}
|
|
208
|
+
|
|
209
|
+
class PostgreSQLDatabase implements Database {
|
|
210
|
+
async query(sql: string, params: any[]) { /* ... */ }
|
|
211
|
+
}
|
|
212
|
+
|
|
213
|
+
class UserService {
|
|
214
|
+
constructor(private db: Database) {} // Injected dependency
|
|
215
|
+
|
|
216
|
+
async getUser(id: string) {
|
|
217
|
+
return this.db.query('SELECT * FROM users WHERE id = $1', [id]);
|
|
218
|
+
}
|
|
219
|
+
}
|
|
220
|
+
|
|
221
|
+
// Usage
|
|
222
|
+
const db = new PostgreSQLDatabase();
|
|
223
|
+
const userService = new UserService(db);
|
|
224
|
+
```
|
|
225
|
+
|
|
226
|
+
## Design Patterns
|
|
227
|
+
|
|
228
|
+
### Repository Pattern
|
|
229
|
+
|
|
230
|
+
**Concept:** Abstraction layer between business logic and data access
|
|
231
|
+
|
|
232
|
+
```typescript
|
|
233
|
+
// Domain entity
|
|
234
|
+
class User {
|
|
235
|
+
constructor(
|
|
236
|
+
public id: string,
|
|
237
|
+
public email: string,
|
|
238
|
+
public name: string,
|
|
239
|
+
) {}
|
|
240
|
+
}
|
|
241
|
+
|
|
242
|
+
// Repository interface
|
|
243
|
+
interface UserRepository {
|
|
244
|
+
findById(id: string): Promise<User | null>;
|
|
245
|
+
findByEmail(email: string): Promise<User | null>;
|
|
246
|
+
save(user: User): Promise<void>;
|
|
247
|
+
delete(id: string): Promise<void>;
|
|
248
|
+
}
|
|
249
|
+
|
|
250
|
+
// Implementation
|
|
251
|
+
class PostgresUserRepository implements UserRepository {
|
|
252
|
+
constructor(private db: Database) {}
|
|
253
|
+
|
|
254
|
+
async findById(id: string): Promise<User | null> {
|
|
255
|
+
const row = await this.db.query('SELECT * FROM users WHERE id = $1', [id]);
|
|
256
|
+
return row ? new User(row.id, row.email, row.name) : null;
|
|
257
|
+
}
|
|
258
|
+
|
|
259
|
+
async save(user: User): Promise<void> {
|
|
260
|
+
await this.db.query(
|
|
261
|
+
'INSERT INTO users (id, email, name) VALUES ($1, $2, $3)',
|
|
262
|
+
[user.id, user.email, user.name]
|
|
263
|
+
);
|
|
264
|
+
}
|
|
265
|
+
|
|
266
|
+
// Other methods...
|
|
267
|
+
}
|
|
268
|
+
|
|
269
|
+
// Service layer uses repository
|
|
270
|
+
class UserService {
|
|
271
|
+
constructor(private userRepo: UserRepository) {}
|
|
272
|
+
|
|
273
|
+
async getUser(id: string) {
|
|
274
|
+
return this.userRepo.findById(id);
|
|
275
|
+
}
|
|
276
|
+
}
|
|
277
|
+
```
|
|
278
|
+
|
|
279
|
+
### Factory Pattern
|
|
280
|
+
|
|
281
|
+
**Concept:** Create objects without specifying exact class
|
|
282
|
+
|
|
283
|
+
```typescript
|
|
284
|
+
interface Notification {
|
|
285
|
+
send(message: string): Promise<void>;
|
|
286
|
+
}
|
|
287
|
+
|
|
288
|
+
class EmailNotification implements Notification {
|
|
289
|
+
async send(message: string) {
|
|
290
|
+
console.log(`Email sent: ${message}`);
|
|
291
|
+
}
|
|
292
|
+
}
|
|
293
|
+
|
|
294
|
+
class SMSNotification implements Notification {
|
|
295
|
+
async send(message: string) {
|
|
296
|
+
console.log(`SMS sent: ${message}`);
|
|
297
|
+
}
|
|
298
|
+
}
|
|
299
|
+
|
|
300
|
+
class PushNotification implements Notification {
|
|
301
|
+
async send(message: string) {
|
|
302
|
+
console.log(`Push notification sent: ${message}`);
|
|
303
|
+
}
|
|
304
|
+
}
|
|
305
|
+
|
|
306
|
+
class NotificationFactory {
|
|
307
|
+
static create(type: 'email' | 'sms' | 'push'): Notification {
|
|
308
|
+
switch (type) {
|
|
309
|
+
case 'email':
|
|
310
|
+
return new EmailNotification();
|
|
311
|
+
case 'sms':
|
|
312
|
+
return new SMSNotification();
|
|
313
|
+
case 'push':
|
|
314
|
+
return new PushNotification();
|
|
315
|
+
default:
|
|
316
|
+
throw new Error(`Unknown notification type: ${type}`);
|
|
317
|
+
}
|
|
318
|
+
}
|
|
319
|
+
}
|
|
320
|
+
|
|
321
|
+
// Usage
|
|
322
|
+
const notification = NotificationFactory.create('email');
|
|
323
|
+
await notification.send('Hello!');
|
|
324
|
+
```
|
|
325
|
+
|
|
326
|
+
### Decorator Pattern
|
|
327
|
+
|
|
328
|
+
**Concept:** Add behavior to objects dynamically
|
|
329
|
+
|
|
330
|
+
```typescript
|
|
331
|
+
interface Coffee {
|
|
332
|
+
cost(): number;
|
|
333
|
+
description(): string;
|
|
334
|
+
}
|
|
335
|
+
|
|
336
|
+
class SimpleCoffee implements Coffee {
|
|
337
|
+
cost() {
|
|
338
|
+
return 10;
|
|
339
|
+
}
|
|
340
|
+
|
|
341
|
+
description() {
|
|
342
|
+
return 'Simple coffee';
|
|
343
|
+
}
|
|
344
|
+
}
|
|
345
|
+
|
|
346
|
+
class MilkDecorator implements Coffee {
|
|
347
|
+
constructor(private coffee: Coffee) {}
|
|
348
|
+
|
|
349
|
+
cost() {
|
|
350
|
+
return this.coffee.cost() + 2;
|
|
351
|
+
}
|
|
352
|
+
|
|
353
|
+
description() {
|
|
354
|
+
return `${this.coffee.description()}, milk`;
|
|
355
|
+
}
|
|
356
|
+
}
|
|
357
|
+
|
|
358
|
+
class SugarDecorator implements Coffee {
|
|
359
|
+
constructor(private coffee: Coffee) {}
|
|
360
|
+
|
|
361
|
+
cost() {
|
|
362
|
+
return this.coffee.cost() + 1;
|
|
363
|
+
}
|
|
364
|
+
|
|
365
|
+
description() {
|
|
366
|
+
return `${this.coffee.description()}, sugar`;
|
|
367
|
+
}
|
|
368
|
+
}
|
|
369
|
+
|
|
370
|
+
// Usage
|
|
371
|
+
let coffee: Coffee = new SimpleCoffee();
|
|
372
|
+
coffee = new MilkDecorator(coffee);
|
|
373
|
+
coffee = new SugarDecorator(coffee);
|
|
374
|
+
|
|
375
|
+
console.log(coffee.description()); // "Simple coffee, milk, sugar"
|
|
376
|
+
console.log(coffee.cost()); // 13
|
|
377
|
+
```
|
|
378
|
+
|
|
379
|
+
### Observer Pattern (Pub/Sub)
|
|
380
|
+
|
|
381
|
+
**Concept:** Notify multiple objects about state changes
|
|
382
|
+
|
|
383
|
+
```typescript
|
|
384
|
+
interface Observer {
|
|
385
|
+
update(event: any): void;
|
|
386
|
+
}
|
|
387
|
+
|
|
388
|
+
class EventEmitter {
|
|
389
|
+
private observers: Map<string, Observer[]> = new Map();
|
|
390
|
+
|
|
391
|
+
subscribe(event: string, observer: Observer) {
|
|
392
|
+
if (!this.observers.has(event)) {
|
|
393
|
+
this.observers.set(event, []);
|
|
394
|
+
}
|
|
395
|
+
this.observers.get(event)!.push(observer);
|
|
396
|
+
}
|
|
397
|
+
|
|
398
|
+
emit(event: string, data: any) {
|
|
399
|
+
const observers = this.observers.get(event) || [];
|
|
400
|
+
observers.forEach(observer => observer.update(data));
|
|
401
|
+
}
|
|
402
|
+
}
|
|
403
|
+
|
|
404
|
+
// Observers
|
|
405
|
+
class EmailNotifier implements Observer {
|
|
406
|
+
update(event: any) {
|
|
407
|
+
console.log(`Sending email about: ${event.type}`);
|
|
408
|
+
}
|
|
409
|
+
}
|
|
410
|
+
|
|
411
|
+
class LoggerObserver implements Observer {
|
|
412
|
+
update(event: any) {
|
|
413
|
+
console.log(`Logging event: ${JSON.stringify(event)}`);
|
|
414
|
+
}
|
|
415
|
+
}
|
|
416
|
+
|
|
417
|
+
// Usage
|
|
418
|
+
const eventEmitter = new EventEmitter();
|
|
419
|
+
eventEmitter.subscribe('user.created', new EmailNotifier());
|
|
420
|
+
eventEmitter.subscribe('user.created', new LoggerObserver());
|
|
421
|
+
|
|
422
|
+
eventEmitter.emit('user.created', { type: 'user.created', userId: '123' });
|
|
423
|
+
```
|
|
424
|
+
|
|
425
|
+
## Clean Code Practices
|
|
426
|
+
|
|
427
|
+
### Meaningful Names
|
|
428
|
+
|
|
429
|
+
**Bad:**
|
|
430
|
+
```typescript
|
|
431
|
+
function d(a: number, b: number) {
|
|
432
|
+
return a * b * 0.0254;
|
|
433
|
+
}
|
|
434
|
+
```
|
|
435
|
+
|
|
436
|
+
**Good:**
|
|
437
|
+
```typescript
|
|
438
|
+
function calculateAreaInMeters(widthInInches: number, heightInInches: number) {
|
|
439
|
+
const INCHES_TO_METERS = 0.0254;
|
|
440
|
+
return widthInInches * heightInInches * INCHES_TO_METERS;
|
|
441
|
+
}
|
|
442
|
+
```
|
|
443
|
+
|
|
444
|
+
### Small Functions
|
|
445
|
+
|
|
446
|
+
**Bad:**
|
|
447
|
+
```typescript
|
|
448
|
+
async function processOrder(orderId: string) {
|
|
449
|
+
// 200 lines of code doing everything
|
|
450
|
+
// - validate order
|
|
451
|
+
// - check inventory
|
|
452
|
+
// - process payment
|
|
453
|
+
// - update database
|
|
454
|
+
// - send notifications
|
|
455
|
+
// - generate invoice
|
|
456
|
+
}
|
|
457
|
+
```
|
|
458
|
+
|
|
459
|
+
**Good:**
|
|
460
|
+
```typescript
|
|
461
|
+
async function processOrder(orderId: string) {
|
|
462
|
+
const order = await validateOrder(orderId);
|
|
463
|
+
await checkInventory(order);
|
|
464
|
+
const payment = await processPayment(order);
|
|
465
|
+
await updateOrderStatus(orderId, 'paid');
|
|
466
|
+
await sendConfirmationEmail(order);
|
|
467
|
+
await generateInvoice(order, payment);
|
|
468
|
+
}
|
|
469
|
+
```
|
|
470
|
+
|
|
471
|
+
### Avoid Magic Numbers
|
|
472
|
+
|
|
473
|
+
**Bad:**
|
|
474
|
+
```typescript
|
|
475
|
+
if (user.age < 18) {
|
|
476
|
+
throw new Error('Too young');
|
|
477
|
+
}
|
|
478
|
+
|
|
479
|
+
setTimeout(fetchData, 86400000);
|
|
480
|
+
```
|
|
481
|
+
|
|
482
|
+
**Good:**
|
|
483
|
+
```typescript
|
|
484
|
+
const MINIMUM_AGE = 18;
|
|
485
|
+
if (user.age < MINIMUM_AGE) {
|
|
486
|
+
throw new Error('Too young');
|
|
487
|
+
}
|
|
488
|
+
|
|
489
|
+
const ONE_DAY_IN_MS = 24 * 60 * 60 * 1000;
|
|
490
|
+
setTimeout(fetchData, ONE_DAY_IN_MS);
|
|
491
|
+
```
|
|
492
|
+
|
|
493
|
+
### Error Handling
|
|
494
|
+
|
|
495
|
+
**Bad:**
|
|
496
|
+
```typescript
|
|
497
|
+
try {
|
|
498
|
+
const user = await db.findUser(id);
|
|
499
|
+
return user;
|
|
500
|
+
} catch (e) {
|
|
501
|
+
console.log(e);
|
|
502
|
+
return null;
|
|
503
|
+
}
|
|
504
|
+
```
|
|
505
|
+
|
|
506
|
+
**Good:**
|
|
507
|
+
```typescript
|
|
508
|
+
try {
|
|
509
|
+
const user = await db.findUser(id);
|
|
510
|
+
if (!user) {
|
|
511
|
+
throw new UserNotFoundError(id);
|
|
512
|
+
}
|
|
513
|
+
return user;
|
|
514
|
+
} catch (error) {
|
|
515
|
+
logger.error('Failed to fetch user', {
|
|
516
|
+
userId: id,
|
|
517
|
+
error: error.message,
|
|
518
|
+
stack: error.stack,
|
|
519
|
+
});
|
|
520
|
+
throw new DatabaseError('User fetch failed', { cause: error });
|
|
521
|
+
}
|
|
522
|
+
```
|
|
523
|
+
|
|
524
|
+
### Don't Repeat Yourself (DRY)
|
|
525
|
+
|
|
526
|
+
**Bad:**
|
|
527
|
+
```typescript
|
|
528
|
+
app.post('/api/users', async (req, res) => {
|
|
529
|
+
if (!req.body.email || !req.body.email.includes('@')) {
|
|
530
|
+
return res.status(400).json({ error: 'Invalid email' });
|
|
531
|
+
}
|
|
532
|
+
// ...
|
|
533
|
+
});
|
|
534
|
+
|
|
535
|
+
app.put('/api/users/:id', async (req, res) => {
|
|
536
|
+
if (!req.body.email || !req.body.email.includes('@')) {
|
|
537
|
+
return res.status(400).json({ error: 'Invalid email' });
|
|
538
|
+
}
|
|
539
|
+
// ...
|
|
540
|
+
});
|
|
541
|
+
```
|
|
542
|
+
|
|
543
|
+
**Good:**
|
|
544
|
+
```typescript
|
|
545
|
+
function validateEmail(email: string) {
|
|
546
|
+
if (!email || !email.includes('@')) {
|
|
547
|
+
throw new ValidationError('Invalid email');
|
|
548
|
+
}
|
|
549
|
+
}
|
|
550
|
+
|
|
551
|
+
app.post('/api/users', async (req, res) => {
|
|
552
|
+
validateEmail(req.body.email);
|
|
553
|
+
// ...
|
|
554
|
+
});
|
|
555
|
+
|
|
556
|
+
app.put('/api/users/:id', async (req, res) => {
|
|
557
|
+
validateEmail(req.body.email);
|
|
558
|
+
// ...
|
|
559
|
+
});
|
|
560
|
+
```
|
|
561
|
+
|
|
562
|
+
## Code Refactoring Techniques
|
|
563
|
+
|
|
564
|
+
### Extract Method
|
|
565
|
+
|
|
566
|
+
**Before:**
|
|
567
|
+
```typescript
|
|
568
|
+
function renderOrder(order: Order) {
|
|
569
|
+
console.log('Order Details:');
|
|
570
|
+
console.log(`ID: ${order.id}`);
|
|
571
|
+
console.log(`Total: $${order.total}`);
|
|
572
|
+
|
|
573
|
+
console.log('Items:');
|
|
574
|
+
order.items.forEach(item => {
|
|
575
|
+
console.log(`- ${item.name}: $${item.price}`);
|
|
576
|
+
});
|
|
577
|
+
}
|
|
578
|
+
```
|
|
579
|
+
|
|
580
|
+
**After:**
|
|
581
|
+
```typescript
|
|
582
|
+
function renderOrder(order: Order) {
|
|
583
|
+
printOrderHeader(order);
|
|
584
|
+
printOrderItems(order.items);
|
|
585
|
+
}
|
|
586
|
+
|
|
587
|
+
function printOrderHeader(order: Order) {
|
|
588
|
+
console.log('Order Details:');
|
|
589
|
+
console.log(`ID: ${order.id}`);
|
|
590
|
+
console.log(`Total: $${order.total}`);
|
|
591
|
+
}
|
|
592
|
+
|
|
593
|
+
function printOrderItems(items: OrderItem[]) {
|
|
594
|
+
console.log('Items:');
|
|
595
|
+
items.forEach(item => {
|
|
596
|
+
console.log(`- ${item.name}: $${item.price}`);
|
|
597
|
+
});
|
|
598
|
+
}
|
|
599
|
+
```
|
|
600
|
+
|
|
601
|
+
### Replace Conditional with Polymorphism
|
|
602
|
+
|
|
603
|
+
**Before:**
|
|
604
|
+
```typescript
|
|
605
|
+
function getShippingCost(order: Order) {
|
|
606
|
+
if (order.shippingMethod === 'standard') {
|
|
607
|
+
return 5;
|
|
608
|
+
} else if (order.shippingMethod === 'express') {
|
|
609
|
+
return 15;
|
|
610
|
+
} else if (order.shippingMethod === 'overnight') {
|
|
611
|
+
return 30;
|
|
612
|
+
}
|
|
613
|
+
}
|
|
614
|
+
```
|
|
615
|
+
|
|
616
|
+
**After:**
|
|
617
|
+
```typescript
|
|
618
|
+
interface ShippingMethod {
|
|
619
|
+
getCost(): number;
|
|
620
|
+
}
|
|
621
|
+
|
|
622
|
+
class StandardShipping implements ShippingMethod {
|
|
623
|
+
getCost() {
|
|
624
|
+
return 5;
|
|
625
|
+
}
|
|
626
|
+
}
|
|
627
|
+
|
|
628
|
+
class ExpressShipping implements ShippingMethod {
|
|
629
|
+
getCost() {
|
|
630
|
+
return 15;
|
|
631
|
+
}
|
|
632
|
+
}
|
|
633
|
+
|
|
634
|
+
class OvernightShipping implements ShippingMethod {
|
|
635
|
+
getCost() {
|
|
636
|
+
return 30;
|
|
637
|
+
}
|
|
638
|
+
}
|
|
639
|
+
```
|
|
640
|
+
|
|
641
|
+
## Code Quality Checklist
|
|
642
|
+
|
|
643
|
+
- [ ] SOLID principles applied
|
|
644
|
+
- [ ] Functions are small (< 20 lines ideal)
|
|
645
|
+
- [ ] Meaningful variable/function names
|
|
646
|
+
- [ ] No magic numbers (use constants)
|
|
647
|
+
- [ ] Proper error handling (no silent failures)
|
|
648
|
+
- [ ] DRY (no code duplication)
|
|
649
|
+
- [ ] Comments explain "why", not "what"
|
|
650
|
+
- [ ] Design patterns used appropriately
|
|
651
|
+
- [ ] Dependency injection for testability
|
|
652
|
+
- [ ] Code is readable (readable > clever)
|
|
653
|
+
|
|
654
|
+
## Resources
|
|
655
|
+
|
|
656
|
+
- **Clean Code (Book):** Robert C. Martin
|
|
657
|
+
- **Refactoring (Book):** Martin Fowler
|
|
658
|
+
- **Design Patterns:** https://refactoring.guru/design-patterns
|
|
659
|
+
- **SOLID Principles:** https://en.wikipedia.org/wiki/SOLID
|