````markdown
# C002_no_duplicate_code - CODING Rule

## 📋 Overview

**Rule ID**: `C002_no_duplicate_code`  
**Category**: coding  
**Severity**: Error  
**Status**: active

## 🎯 Description

Detects and warns about duplicate code blocks of 10 or more lines across functions and classes. This rule enforces the **DRY (Don't Repeat Yourself)** principle to maintain clean, refactorable code and reduce maintenance burden.

**Key Objectives:**
- 🎯 Avoid messy, hard-to-refactor code
- ♻️ Apply DRY principle consistently
- 🔧 Improve code maintainability
- 🧪 Enhance testability

**Detection Criteria:**
- Warns when duplicate code ≥ 10 lines found in functions/classes
- Ignores comments and whitespace variations
- Uses similarity threshold (85%) to detect near-duplicates
- Cross-file duplicate detection

## 🔄 Migration Info

**ESLint Rule**: `c002-no-duplicate-code`  
**Compatibility**: Full  
**Priority**: High


## ✅ Valid Code Examples

### Example 1: Extract Common Logic into Utility Functions

```typescript
// ✅ GOOD: Extracted validation logic into reusable functions
function validateEmail(email: string): void {
  if (!email || !email.includes('@')) {
    throw new ValidationError('Invalid email format');
  }
}

function validatePassword(password: string): void {
  if (!password || password.length < 8) {
    throw new ValidationError('Password must be at least 8 characters');
  }
}

function registerUser(userData: UserData): void {
  validateEmail(userData.email);
  validatePassword(userData.password);
  // Registration logic
}

function updateUserProfile(userId: string, profileData: ProfileData): void {
  if (profileData.email) {
    validateEmail(profileData.email);
  }
  if (profileData.password) {
    validatePassword(profileData.password);
  }
  // Update logic
}
```

### Example 2: Using Inheritance for Shared Behavior

```typescript
// ✅ GOOD: Base class with common logic
abstract class BaseRepository<T> {
  protected async findById(id: string): Promise<T | null> {
    const result = await this.db.query(
      `SELECT * FROM ${this.tableName} WHERE id = ?`,
      [id]
    );
    return result.length > 0 ? this.mapToEntity(result[0]) : null;
  }
  
  protected async save(entity: T): Promise<void> {
    const data = this.mapToData(entity);
    await this.db.query(
      `INSERT INTO ${this.tableName} VALUES (?, ?, ?)`,
      Object.values(data)
    );
  }
  
  protected abstract mapToEntity(row: any): T;
  protected abstract mapToData(entity: T): any;
  protected abstract tableName: string;
}

class UserRepository extends BaseRepository<User> {
  protected tableName = 'users';
  protected mapToEntity(row: any): User { /* ... */ }
  protected mapToData(entity: User): any { /* ... */ }
}

class ProductRepository extends BaseRepository<Product> {
  protected tableName = 'products';
  protected mapToEntity(row: any): Product { /* ... */ }
  protected mapToData(entity: Product): any { /* ... */ }
}
```

### Example 3: Composition for Shared Logic

```typescript
// ✅ GOOD: Shared service for common operations
class ErrorLogger {
  logError(context: string, error: Error): void {
    console.error(`[${context}] ${error.message}`);
    this.sendToMonitoring(error);
  }
  
  private sendToMonitoring(error: Error): void {
    // Send to monitoring service
  }
}

class UserService {
  constructor(private errorLogger: ErrorLogger) {}
  
  async getUser(id: string): Promise<User> {
    try {
      return await this.userRepo.findById(id);
    } catch (error) {
      this.errorLogger.logError('UserService.getUser', error);
      throw error;
    }
  }
}

class OrderService {
  constructor(private errorLogger: ErrorLogger) {}
  
  async getOrder(id: string): Promise<Order> {
    try {
      return await this.orderRepo.findById(id);
    } catch (error) {
      this.errorLogger.logError('OrderService.getOrder', error);
      throw error;
    }
  }
}
```

## ❌ Invalid Code Examples

### Example 1: Duplicated Validation Logic

```typescript
// ❌ BAD: Duplicated validation in multiple functions
function registerUser(userData: UserData): void {
  // Duplicated validation logic
  if (!userData.email || !userData.email.includes('@')) {
    throw new ValidationError('Invalid email format');
  }
  if (!userData.password || userData.password.length < 8) {
    throw new ValidationError('Password must be at least 8 characters');
  }
  // Registration logic
}

function updateUserProfile(userId: string, profileData: ProfileData): void {
  // Same validation logic duplicated here
  if (profileData.email && (!profileData.email || !profileData.email.includes('@'))) {
    throw new ValidationError('Invalid email format');
  }
  if (profileData.password && (!profileData.password || profileData.password.length < 8)) {
    throw new ValidationError('Password must be at least 8 characters');
  }
  // Update logic
}
```

**Violation Message:**
```
Duplicate function detected (12 non-comment lines). Extract into a shared utility 
module or helper file. Found in 2 locations: registerUser.ts:5-16, updateUserProfile.ts:10-21
```

### Example 2: Duplicated Repository Logic

```typescript
// ❌ BAD: Same database logic repeated in multiple repositories
class UserRepository {
  async findById(id: string): Promise<User | null> {
    const result = await this.db.query(
      'SELECT * FROM users WHERE id = ?',
      [id]
    );
    if (result.length === 0) return null;
    return {
      id: result[0].id,
      name: result[0].name,
      email: result[0].email
    };
  }
}

class ProductRepository {
  async findById(id: string): Promise<Product | null> {
    const result = await this.db.query(
      'SELECT * FROM products WHERE id = ?',
      [id]
    );
    if (result.length === 0) return null;
    return {
      id: result[0].id,
      name: result[0].name,
      price: result[0].price
    };
  }
}
```

**Suggested Fix:**
- Use inheritance to share common behavior
- Extract shared logic into a base class or mixin

## ⚙️ Configuration

```json
{
  "rules": {
    "C002_no_duplicate_code": ["error", {
      "minLines": 10,
      "similarityThreshold": 0.85,
      "ignoreComments": true,
      "ignoreWhitespace": true,
      "ignoreEmptyLines": true
    }]
  }
}
```

**Configuration Options:**
- `minLines` (default: 10): Minimum number of lines to consider as duplicate
- `similarityThreshold` (default: 0.85): Similarity percentage (0-1) to detect near-duplicates
- `ignoreComments` (default: true): Ignore comments when comparing code
- `ignoreWhitespace` (default: true): Ignore whitespace differences
- `ignoreEmptyLines` (default: true): Ignore empty lines

## 🔧 Refactoring Strategies

### 1. Extract Functions/Utilities
When you have duplicated logic in multiple functions:
```typescript
// Extract common logic into a utility function
const validateUserInput = (email: string, password: string) => {
  validateEmail(email);
  validatePassword(password);
};
```

### 2. Use Inheritance
When you have duplicated logic in multiple classes with similar responsibilities:
```typescript
// Create a base class with common behavior
abstract class BaseService {
  protected abstract entityName: string;
  
  protected async findById(id: string) {
    // Common implementation
  }
}
```

### 3. Use Composition
When inheritance doesn't fit or you need more flexibility:
```typescript
// Create a shared service that can be injected
class CommonOperations {
  logError(context: string, error: Error) { /* ... */ }
  validateInput(data: any) { /* ... */ }
}
```

### 4. Create Shared Libraries
For cross-cutting concerns used across multiple modules:
```typescript
// utils/validation.ts
export const validators = {
  email: (email: string) => { /* ... */ },
  password: (password: string) => { /* ... */ }
};
```

## 🧪 Testing

```bash
# Run rule-specific tests
npm test -- c002_no_duplicate_code

# Test with SunLint CLI
sunlint --rules=C002_no_duplicate_code --input=examples/

# Analyze specific files
sunlint analyze --rules=C002 src/**/*.ts
```

## 📚 Related Rules

- **C005**: Each function should do one thing (Single Responsibility)
- **C047**: Retry logic must not be duplicated
- **C014**: Use Dependency Injection instead of direct instantiation

## 🔗 References

- [DRY Principle](https://en.wikipedia.org/wiki/Don%27t_repeat_yourself)
- [Code Duplication (Martin Fowler)](https://refactoring.guru/smells/duplicate-code)
- [SonarQube: Duplicated Blocks](https://rules.sonarsource.com/java/RSPEC-1192)

---

**Migration Status**: active  
**Last Updated**: 2025-10-16

````
