By Piotr Sikora

  • Development

  • 28 January 2026

DRY, WET, AHA: Finding the Right Balance in Code Reuse

Every developer learns "Don't Repeat Yourself" early in their career. But like most principles, applying it dogmatically can cause more harm than good. Let's explore three philosophies around code duplication and when each makes sense.

DRY: Don't Repeat Yourself

The DRY principle states that every piece of knowledge should have a single, unambiguous representation in your system. When you spot duplicate code, you extract it into a shared function, class, or module.

// Before: repetition
function calculateUserTotal(user) {
  return user.items.reduce((sum, item) => sum + item.price * 1.23, 0);
}

function calculateGuestTotal(guest) {
  return guest.items.reduce((sum, item) => sum + item.price * 1.23, 0);
}

// After: DRY
function calculateTotal(items) {
  return items.reduce((sum, item) => sum + item.price * 1.23, 0);
}

Benefits: Fewer bugs (fix once, fixed everywhere), easier maintenance, smaller codebase.

The trap: Developers often merge code that looks similar but serves different purposes. When requirements diverge later, the abstraction becomes a tangled mess of conditionals.

WET: Write Everything Twice

WET is sometimes jokingly expanded as "We Enjoy Typing" or "Write Every Time," but its real meaning is more nuanced: don't abstract until you've seen the pattern at least twice.

The idea is simple—duplication is cheaper than the wrong abstraction. The first time you write something, you don't know if it will be reused. The second time, you start seeing a pattern. Only then should you consider extracting shared logic.

// First occurrence: just write it
function processOrder(order) {
  const tax = order.subtotal * 0.23;
  // ...
}

// Second occurrence: still okay to duplicate
function processRefund(refund) {
  const tax = refund.amount * 0.23;
  // ...
}

// Third occurrence: now consider abstracting
function calculateTax(amount) {
  return amount * 0.23;
}

Benefits: Avoids premature abstraction, keeps code straightforward, easier to understand each function in isolation.

AHA: Avoid Hasty Abstractions

Coined by Kent C. Dodds, AHA programming takes WET further by emphasizing that you should optimize for change, not for reducing duplication.

The core insight: duplicated code is easy to refactor later, but a bad abstraction is painful to undo. When you merge two similar pieces of code prematurely, you couple their evolution. When one needs to change independently, you either add ugly conditionals or painfully untangle the abstraction.

AHA suggests you ask yourself: "Do these really need to change together?" If not, duplication might be the better choice.

// Looks similar, but serves different business purposes
function validateUserRegistration(data) {
  if (!data.email) return { valid: false, error: 'Email required' };
  if (!data.password) return { valid: false, error: 'Password required' };
  if (data.password.length < 8) return { valid: false, error: 'Password too short' };
  return { valid: true };
}

function validateNewsletterSignup(data) {
  if (!data.email) return { valid: false, error: 'Email required' };
  return { valid: true };
}

// Don't merge these! They'll evolve differently as business rules change.

Practical Guidelines

Here's how to decide:

  1. First occurrence — Just write the code. Don't think about reuse yet.

  2. Second occurrence — Notice the duplication but resist the urge. Copy-paste is fine.

  3. Third occurrence — Now evaluate: Do these cases share the same reason to change? If yes, abstract. If not, keep them separate.

  4. When in doubt — Prefer duplication. It's easier to merge duplicate code later than to split a bad abstraction.

The Real Enemy: Wrong Abstractions

Sandi Metz put it best: "Duplication is far cheaper than the wrong abstraction."

A bad abstraction doesn't just fail to save time—it actively costs time. Every developer who touches it must understand the abstraction's quirks. Every new requirement must work around its assumptions. Eventually, someone rewrites it from scratch.

Conclusion

DRY is a useful heuristic, not a law. WET reminds us that some duplication is acceptable. AHA teaches us to wait until we truly understand the pattern before abstracting.

The goal isn't eliminating all duplication—it's building code that's easy to change. Sometimes that means sharing logic. Sometimes it means keeping things separate. Wisdom is knowing which situation you're in.

Categories

Recent Posts

About Me

Piotr Sikora - Process Automation | AI | n8n | Python | JavaScript

Piotr Sikora

Process Automation Specialist

I implement automation that saves time and money, streamlines operations, and increases the predictability of results. Specializing in process automation, AI implementation, and workflow optimization using n8n, Python, and JavaScript.

n8n Workflows

n8n workflow automation templates

Explore my workflow templates on n8n. Ready-to-use automations for blog management, data collection, and AI-powered content processing.

3Workflow Templates

• Auto-Categorize Blog Posts with AI

• Collect LinkedIn Profiles

• Export WordPress Posts for SEO

If somebody offers you an amazing opportunity but you are not sure you can do it, say 'yes' – then learn how to do it later!
Richard Branson
View more quotes

Similar Articles

Discover more related content

Why You Shouldn't Cram Multiple Webhooks Into One n8n Workflow

The hidden costs of combining webhooks and why separate workflows save you headaches

API vs Webhook: Understanding the Difference

Learn when to pull data with APIs and when to let webhooks push it to you

Hands On Tech - Internet of Things (IOT)

Hands On Tech - Internet of Things (IOT)

It was great to be on Hands On Tech meeting in Kielce.