What is DRY?
"Every piece of knowledge must have a single, unambiguous, authoritative representation within a system."
DRY = Don't Repeat Yourself
✓ Single source of truth
✓ Reduce duplication
✓ Centralize logic
✓ Easier maintenance
Extract Functions
// ❌ Bad - repeated validation logic
function createUser(email: string) {
if (!email.includes('@') || email.length < 5) {
throw new Error('Invalid email');
}
// create user...
}
function updateEmail(email: string) {
if (!email.includes('@') || email.length < 5) {
throw new Error('Invalid email');
}
// update email...
}
// ✅ Good - extracted reusable function
function validateEmail(email: string): boolean {
return email.includes('@') && email.length >= 5;
}
function createUser(email: string) {
if (!validateEmail(email)) throw new Error('Invalid email');
// create user...
}
function updateEmail(email: string) {
if (!validateEmail(email)) throw new Error('Invalid email');
// update email...
}
Use Constants
// ❌ Bad - magic numbers repeated
function calculateShipping(weight: number) {
return weight * 5.99;
}
function calculateTax(price: number) {
return price * 0.08; // 8% tax
}
// Tax rate 0.08 and shipping rate 5.99 appear in multiple files...
// ✅ Good - centralized constants
const SHIPPING_RATE_PER_KG = 5.99;
const TAX_RATE = 0.08;
function calculateShipping(weight: number) {
return weight * SHIPPING_RATE_PER_KG;
}
function calculateTax(price: number) {
return price * TAX_RATE;
}
Create Base Classes
// ❌ Bad - repeated code in similar classes
class Dog {
name: string;
eat() { console.log(`${this.name} is eating`); }
sleep() { console.log(`${this.name} is sleeping`); }
bark() { console.log('Woof!'); }
}
class Cat {
name: string;
eat() { console.log(`${this.name} is eating`); }
sleep() { console.log(`${this.name} is sleeping`); }
meow() { console.log('Meow!'); }
}
// ✅ Good - shared behavior in base class
abstract class Animal {
constructor(public name: string) {}
eat() { console.log(`${this.name} is eating`); }
sleep() { console.log(`${this.name} is sleeping`); }
}
class Dog extends Animal {
bark() { console.log('Woof!'); }
}
class Cat extends Animal {
meow() { console.log('Meow!'); }
}
Use Utility Functions
// ❌ Bad - repeated formatting logic
function displayUserDate(user: User) {
const date = user.createdAt;
return `${date.getMonth()+1}/${date.getDate()}/${date.getFullYear()}`;
}
function displayOrderDate(order: Order) {
const date = order.placedAt;
return `${date.getMonth()+1}/${date.getDate()}/${date.getFullYear()}`;
}
// ✅ Good - reusable utility
function formatDate(date: Date): string {
return `${date.getMonth()+1}/${date.getDate()}/${date.getFullYear()}`;
}
function displayUserDate(user: User) {
return formatDate(user.createdAt);
}
function displayOrderDate(order: Order) {
return formatDate(order.placedAt);
}
Configuration Files
// ❌ Bad - hardcoded values everywhere
// file1.ts
const apiUrl = 'https://api.example.com/v1';
// file2.ts
const apiUrl = 'https://api.example.com/v1';
// ✅ Good - single configuration source
// config.ts
export const config = {
apiUrl: 'https://api.example.com/v1',
timeout: 5000,
retries: 3,
};
// file1.ts & file2.ts
import { config } from './config';
fetch(config.apiUrl);
Template/Component Reuse
// ❌ Bad - repeated UI structure
const UserCard = () => (
<div className="card shadow rounded p-4">
<h3>{user.name}</h3>
</div>
);
const ProductCard = () => (
<div className="card shadow rounded p-4">
<h3>{product.name}</h3>
</div>
);
// ✅ Good - reusable card component
const Card = ({ children }) => (
<div className="card shadow rounded p-4">
{children}
</div>
);
const UserCard = () => <Card><h3>{user.name}</h3></Card>;
const ProductCard = () => <Card><h3>{product.name}</h3></Card>;
When NOT to Apply DRY
⚠️ Avoid premature abstraction:
• Code that looks similar but serves different purposes
• Two pieces of code that might evolve differently
• When abstraction adds more complexity than duplication
• "Rule of Three" - wait for 3 occurrences before abstracting
Remember: Some duplication is better than wrong abstraction
Quick Reference
| Technique | Use Case |
|---|---|
| Extract functions | Repeated logic blocks |
| Constants | Magic numbers/strings |
| Base classes | Shared behavior |
| Utilities | Common operations |
| Config files | Environment values |
| Components | Repeated UI patterns |