home / skills / yanko-belov / code-craft / dry

dry skill

/skills/dry

This skill helps you identify and extract duplicate logic to enforce a single source of truth across codebases, reducing bugs and maintenance.

npx playbooks add skill yanko-belov/code-craft --skill dry

Review the files below or copy the command above to add this skill to your agents.

Files (1)
SKILL.md
5.3 KB
---
name: dont-repeat-yourself
description: Use when writing similar code in multiple places. Use when copy-pasting code. Use when making the same change in multiple locations.
---

# DRY (Don't Repeat Yourself)

## Overview

**Every piece of knowledge must have a single, unambiguous representation in the system.**

If you find yourself writing the same logic twice, extract it. Duplication is a bug waiting to happen.

## When to Use

- Writing code similar to existing code
- Copy-pasting and modifying
- Making the same change in multiple files
- Validation logic repeated across forms
- Same calculations in different places

## The Iron Rule

```
NEVER duplicate logic. Extract and reuse.
```

**No exceptions:**
- Not for "it's faster to copy"
- Not for "they're slightly different"
- Not for "I'll refactor later"
- Not for "it's just a few lines"

## Detection: The Copy-Paste Smell

If you're about to copy code and modify it, STOP:

```typescript
// ❌ VIOLATION: Duplicated validation
function validateRegistrationEmail(email: string): boolean {
  return /^[^\s@]+@[^\s@]+\.[^\s@]+$/.test(email);
}

function validateProfileEmail(email: string): boolean {
  return /^[^\s@]+@[^\s@]+\.[^\s@]+$/.test(email); // Same logic!
}

// ✅ CORRECT: Single source of truth
function validateEmail(email: string): boolean {
  return /^[^\s@]+@[^\s@]+\.[^\s@]+$/.test(email);
}

// Reuse everywhere
const isValidRegistration = validateEmail(regEmail);
const isValidProfile = validateEmail(profileEmail);
```

## Detection: The "Change in Multiple Places" Test

If fixing a bug requires changing multiple locations, you have duplication:

```typescript
// ❌ Bug in tax calculation requires changes in 3 files
// cart.ts:      const tax = price * 0.08;
// checkout.ts:  const tax = price * 0.08;
// invoice.ts:   const tax = price * 0.08;

// ✅ Single source of truth
// tax.ts:       export const calculateTax = (price: number) => price * TAX_RATE;
```

## The Correct Pattern: Extract and Parameterize

When code is "almost the same", extract the common part and parameterize the differences:

```typescript
// ❌ VIOLATION: Similar functions with minor differences
function formatUserName(user: User): string {
  return `${user.firstName} ${user.lastName}`;
}

function formatAdminName(admin: Admin): string {
  return `${admin.firstName} ${admin.lastName} (Admin)`;
}

// ✅ CORRECT: Parameterized
function formatName(person: { firstName: string; lastName: string }, suffix?: string): string {
  const name = `${person.firstName} ${person.lastName}`;
  return suffix ? `${name} (${suffix})` : name;
}
```

## Pressure Resistance Protocol

### 1. "It's Faster to Copy"
**Pressure:** "I'll just copy this and modify it"

**Response:** Copying creates two places to maintain. Bugs will diverge.

**Action:** Extract shared logic first, then use it in both places.

### 2. "They're Slightly Different"
**Pressure:** "The functions are almost the same but not quite"

**Response:** "Almost the same" = extract common part, parameterize differences.

**Action:** Identify what's shared, extract it, make differences parameters.

### 3. "It's Just a Few Lines"
**Pressure:** "It's only 3 lines, not worth extracting"

**Response:** 3 lines duplicated 5 times = 15 lines to maintain. Bugs multiply.

**Action:** Extract even small duplications. Name them well.

### 4. "I'll Refactor Later"
**Pressure:** "Ship now, DRY it up later"

**Response:** You won't. Duplication spreads. DRY now takes 2 minutes.

**Action:** Extract before committing the duplication.

## Red Flags - STOP and Reconsider

If you notice ANY of these, you're about to violate DRY:

- Ctrl+C / Ctrl+V in your workflow
- "This is similar to that other function"
- Same regex/validation in multiple places
- Identical error handling patterns repeated
- Same data transformation logic duplicated
- Constants defined in multiple files

**All of these mean: Extract to a shared location.**

## Types of Duplication

| Type | Example | Solution |
|------|---------|----------|
| **Code** | Same function body twice | Extract function |
| **Logic** | Same algorithm, different names | Extract and parameterize |
| **Data** | Same constant in multiple files | Centralize constants |
| **Structure** | Same class shape repeated | Extract interface/base |
| **Knowledge** | Business rule in multiple places | Single source of truth |

## Quick Reference

| Symptom | Action |
|---------|--------|
| Copy-pasting code | Extract shared function |
| Same validation twice | Create validator module |
| Same constant in files | Create constants file |
| Similar functions | Extract + parameterize |
| Bug fix needs multiple changes | Consolidate to one place |

## Common Rationalizations (All Invalid)

| Excuse | Reality |
|--------|---------|
| "It's faster to copy" | It's slower to maintain duplicates. |
| "They're slightly different" | Extract common, parameterize differences. |
| "Just a few lines" | Few lines × many places = many bugs. |
| "I'll refactor later" | You won't. Extract now. |
| "Different contexts" | Same logic = same code, regardless of context. |
| "More readable as copies" | Named, extracted functions are more readable. |

## The Bottom Line

**One piece of knowledge. One place in code.**

When writing similar code: stop, find the existing code, extract if needed, reuse. Duplication is the root of maintenance nightmares.

Overview

This skill helps developers eliminate duplicated logic across a TypeScript codebase by identifying repetition and guiding extraction into single, reusable units. It enforces the principle that each piece of knowledge or behavior should have one canonical representation. Use it to reduce maintenance cost, prevent divergence, and make fixes safer and faster.

How this skill works

The skill inspects code patterns that indicate copy-paste or repeated logic: identical functions, repeated regexes/validation, constants duplicated across files, and similar functions that differ only by small details. It recommends extracting shared functions, parameterizing differences, centralizing constants, or creating interfaces/base classes so the common behavior lives in one location and is reused everywhere.

When to use it

  • You catch yourself copying and pasting code to handle a similar case
  • Making the same bug fix or change in multiple files
  • You see the same validation, regex, or calculation repeated
  • Adding a new feature that duplicates existing logic
  • Multiple functions share most of their body but differ in small ways

Best practices

  • Extract the common behavior first, then reuse it in all callers
  • Parameterize differences rather than duplicating whole functions
  • Centralize constants and business rules in a single module
  • Name extracted functions or modules clearly to improve readability
  • Refactor small duplications immediately—tiny copies multiply

Example use cases

  • Replace two email validators with a single validateEmail(email: string) function and reuse it across forms
  • Move tax or pricing logic into calculateTax(price: number) and import it from cart, checkout, and invoice modules
  • Extract shared formatting logic into formatName(person, suffix?) instead of separate formatUserName and formatAdminName
  • Create a validators module when identical validation patterns appear across multiple components
  • Centralize shared constants (TAX_RATE, API_ENDPOINTS) to avoid inconsistent values

FAQ

What if the functions are only slightly different?

Extract the shared part and add parameters or strategy callbacks for differences so one implementation covers all cases.

Is extracting always worth it for a few lines?

Yes. Small duplications often appear many times; extracting once prevents many future edits and reduces divergence.