File size: 10,964 Bytes
1dbc34b
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
# Clean Code Guidelines

## Overview

This document serves as a comprehensive guide for writing clean, maintainable, and extensible code. It outlines principles and practices that ensure code quality, reusability, and long-term maintainability. When writing or reviewing code, follow these guidelines to create software that is easy to understand, modify, and extend. This file is used by LLMs to understand and enforce coding standards throughout the codebase.

---

## Core Principles

### 1. DRY (Don't Repeat Yourself)

**Principle**: Every piece of knowledge should have a single, unambiguous representation within a system.

**Practices**:

- Extract repeated logic into reusable functions, classes, or modules
- Use constants for repeated values
- Create shared utilities for common operations
- Avoid copy-pasting code blocks
- When you find yourself writing similar code more than twice, refactor it

**Example - Bad**:

```typescript
// Repeated validation logic
if (email.includes('@') && email.length > 5) {
  // ...
}
if (email.includes('@') && email.length > 5) {
  // ...
}
```

**Example - Good**:

```typescript
function isValidEmail(email: string): boolean {
  return email.includes('@') && email.length > 5;
}

if (isValidEmail(email)) {
  // ...
}
```

---

### 2. Code Reusability

**Principle**: Write code that can be used in multiple contexts without modification or with minimal adaptation.

**Practices**:

- Create generic, parameterized functions instead of specific ones
- Use composition over inheritance where appropriate
- Design functions to be pure (no side effects) when possible
- Create utility libraries for common operations
- Use dependency injection to make components reusable
- Design APIs that are flexible and configurable

**Example - Bad**:

```typescript
function calculateUserTotal(userId: string) {
  const user = getUser(userId);
  return user.items.reduce((sum, item) => sum + item.price, 0);
}
```

**Example - Good**:

```typescript
function calculateTotal<T extends { price: number }>(items: T[]): number {
  return items.reduce((sum, item) => sum + item.price, 0);
}

function calculateUserTotal(userId: string) {
  const user = getUser(userId);
  return calculateTotal(user.items);
}
```

---

### 3. Abstract Functions and Abstractions

**Principle**: Create abstractions that hide implementation details and provide clear, simple interfaces.

**Practices**:

- Use interfaces and abstract classes to define contracts
- Create abstraction layers between different concerns
- Hide complex implementation behind simple function signatures
- Use dependency inversion - depend on abstractions, not concretions
- Create factory functions/classes for object creation
- Use strategy pattern for interchangeable algorithms

**Example - Bad**:

```typescript
function processPayment(amount: number, cardNumber: string, cvv: string) {
  // Direct implementation tied to specific payment processor
  fetch('https://stripe.com/api/charge', {
    method: 'POST',
    body: JSON.stringify({ amount, cardNumber, cvv }),
  });
}
```

**Example - Good**:

```typescript
interface PaymentProcessor {
  processPayment(amount: number, details: PaymentDetails): Promise<PaymentResult>;
}

class StripeProcessor implements PaymentProcessor {
  async processPayment(amount: number, details: PaymentDetails): Promise<PaymentResult> {
    // Implementation
  }
}

function processPayment(processor: PaymentProcessor, amount: number, details: PaymentDetails) {
  return processor.processPayment(amount, details);
}
```

---

### 4. Extensibility

**Principle**: Design code that can be easily extended with new features without modifying existing code.

**Practices**:

- Follow the Open/Closed Principle: open for extension, closed for modification
- Use plugin architectures and hooks for extensibility
- Design with future requirements in mind (but don't over-engineer)
- Use configuration over hardcoding
- Create extension points through interfaces and callbacks
- Use composition and dependency injection
- Design APIs that can accommodate new parameters/options

**Example - Bad**:

```typescript
function sendNotification(user: User, type: string) {
  if (type === 'email') {
    sendEmail(user.email);
  } else if (type === 'sms') {
    sendSMS(user.phone);
  }
  // Adding new notification types requires modifying this function
}
```

**Example - Good**:

```typescript
interface NotificationChannel {
  send(user: User): Promise<void>;
}

class EmailChannel implements NotificationChannel {
  async send(user: User): Promise<void> {
    // Implementation
  }
}

class SMSChannel implements NotificationChannel {
  async send(user: User): Promise<void> {
    // Implementation
  }
}

class NotificationService {
  constructor(private channels: NotificationChannel[]) {}

  async send(user: User): Promise<void> {
    await Promise.all(this.channels.map((channel) => channel.send(user)));
  }
}
// New notification types can be added without modifying existing code
```

---

### 5. Avoid Magic Numbers and Strings

**Principle**: Use named constants instead of hardcoded values to improve readability and maintainability.

**Practices**:

- Extract all magic numbers into named constants
- Use enums for related constants
- Create configuration objects for settings
- Use constants for API endpoints, timeouts, limits, etc.
- Document why specific values are used

**Example - Bad**:

```typescript
if (user.age >= 18) {
  // What does 18 mean?
}

setTimeout(() => {
  // What does 3000 mean?
}, 3000);

if (status === 'active') {
  // What are the valid statuses?
}
```

**Example - Good**:

```typescript
const MINIMUM_AGE_FOR_ADULTS = 18;
const SESSION_TIMEOUT_MS = 3000;

enum UserStatus {
  ACTIVE = 'active',
  INACTIVE = 'inactive',
  SUSPENDED = 'suspended',
}

if (user.age >= MINIMUM_AGE_FOR_ADULTS) {
  // Clear intent
}

setTimeout(() => {
  // Clear intent
}, SESSION_TIMEOUT_MS);

if (status === UserStatus.ACTIVE) {
  // Type-safe and clear
}
```

---

## Additional Best Practices

### 6. Single Responsibility Principle

Each function, class, or module should have one reason to change.

**Example**:

```typescript
// Bad: Multiple responsibilities
class User {
  save() {
    /* database logic */
  }
  sendEmail() {
    /* email logic */
  }
  validate() {
    /* validation logic */
  }
}

// Good: Single responsibility
class User {
  validate() {
    /* validation only */
  }
}

class UserRepository {
  save(user: User) {
    /* database logic */
  }
}

class EmailService {
  sendToUser(user: User) {
    /* email logic */
  }
}
```

### 7. Meaningful Names

- Use descriptive names that reveal intent
- Avoid abbreviations unless they're widely understood
- Use verbs for functions, nouns for classes
- Be consistent with naming conventions

**Example**:

```typescript
// Bad
const d = new Date();
const u = getUser();
function calc(x, y) {}

// Good
const currentDate = new Date();
const currentUser = getUser();
function calculateTotal(price: number, quantity: number): number {}
```

### 8. Small Functions

- Functions should do one thing and do it well
- Keep functions short (ideally under 20 lines)
- Extract complex logic into separate functions
- Use descriptive function names instead of comments

### 9. Error Handling

- Handle errors explicitly
- Use appropriate error types
- Provide meaningful error messages
- Don't swallow errors silently
- Use try-catch appropriately

**Example**:

```typescript
// Bad
function divide(a: number, b: number) {
  return a / b; // Can throw division by zero
}

// Good
function divide(a: number, b: number): number {
  if (b === 0) {
    throw new Error('Division by zero is not allowed');
  }
  return a / b;
}
```

### 10. Comments and Documentation

- Write self-documenting code (code should explain itself)
- Use comments to explain "why", not "what"
- Document complex algorithms or business logic
- Keep comments up-to-date with code changes
- Use JSDoc/TSDoc for public APIs

### 11. Type Safety

- Use TypeScript types/interfaces effectively
- Avoid `any` type unless absolutely necessary
- Use union types and discriminated unions
- Leverage type inference where appropriate
- Create custom types for domain concepts

**Example**:

```typescript
// Bad
function processUser(data: any) {
  return data.name;
}

// Good
interface User {
  id: string;
  name: string;
  email: string;
}

function processUser(user: User): string {
  return user.name;
}
```

### 12. Testing Considerations

- Write testable code (pure functions, dependency injection)
- Keep functions small and focused
- Avoid hidden dependencies
- Use mocks and stubs appropriately
- Design for testability from the start

### 13. Performance vs. Readability

- Prefer readability over premature optimization
- Profile before optimizing
- Use clear algorithms first, optimize if needed
- Document performance-critical sections
- Balance between clean code and performance requirements

### 14. Code Organization

- Group related functionality together
- Use modules/packages to organize code
- Follow consistent file and folder structures
- Separate concerns (UI, business logic, data access)
- Use barrel exports (index files) appropriately

### 15. Configuration Management

- Externalize configuration values
- Use environment variables for environment-specific settings
- Create configuration objects/interfaces
- Validate configuration at startup
- Provide sensible defaults

**Example**:

```typescript
// Bad
const apiUrl = 'https://api.example.com';
const timeout = 5000;

// Good
interface Config {
  apiUrl: string;
  timeout: number;
  maxRetries: number;
}

const config: Config = {
  apiUrl: process.env.API_URL || 'https://api.example.com',
  timeout: parseInt(process.env.TIMEOUT || '5000'),
  maxRetries: parseInt(process.env.MAX_RETRIES || '3'),
};
```

---

## Code Review Checklist

When reviewing code, check for:

- [ ] No code duplication (DRY principle)
- [ ] Meaningful variable and function names
- [ ] No magic numbers or strings
- [ ] Functions are small and focused
- [ ] Proper error handling
- [ ] Type safety maintained
- [ ] Code is testable
- [ ] Documentation where needed
- [ ] Consistent code style
- [ ] Proper abstraction levels
- [ ] Extensibility considered
- [ ] Single responsibility principle followed

---

## Summary

Clean code is:

- **Readable**: Easy to understand at a glance
- **Maintainable**: Easy to modify and update
- **Testable**: Easy to write tests for
- **Extensible**: Easy to add new features
- **Reusable**: Can be used in multiple contexts
- **Well-documented**: Clear intent and purpose
- **Type-safe**: Leverages type system effectively
- **DRY**: No unnecessary repetition
- **Abstracted**: Proper separation of concerns
- **Configurable**: Uses constants and configuration over hardcoding

Remember: Code is read far more often than it is written. Write code for your future self and your teammates.