Blog
Jul 9, 2025 - 5 MIN READ
My Rule of Three for Reusability

My Rule of Three for Reusability

How I decide when to extract, refactor, or modularize code—without falling into the overengineering trap.

Surelle

Surelle

Reusability is one of those software ideals we’re all taught to chase. DRY your code. Abstract early. Build shared components.

But here’s the problem: abstracting too soon can slow you down. You spend hours making something “generic” that no one else uses—or worse, that you have to fight every time the use case slightly changes.

That’s why I follow one simple rule:

Don’t extract until the third time you need it.

I call it The Rule of Three—and it’s helped me avoid unnecessary abstractions, while still creating solid reusable pieces that evolve from real needs.

First Time: Just Build It

The first time I solve a problem, I go direct.
No fancy wrappers. No helper functions. No reusable components.

I treat it as a one-off. Because honestly, it might be.

I’ve found that most code only ever runs once. Or gets deleted a month later when the product changes. And that’s okay.

At this point, my priority is clarity, speed, and shipping.

Second Time: Copy With Care

The second time I need a similar solution, I’ll copy/paste—but with awareness.

I try to:

  • Keep the structure similar so patterns emerge naturally
  • Leave a // TODO: Consolidate if used again comment
  • Start noticing what varies and what stays the same

This is a data-gathering phase. It helps me resist the temptation to abstract prematurely. Sometimes the second use case looks similar—but ends up being just different enough that shared code would’ve made it worse.

Third Time: Extract with Purpose

The third time is the tipping point.

If I’m solving the same problem a third time, I pause and ask:

  • What’s the common logic across all uses?
  • What are the real differences? Can they be passed as config/options?
  • Will this abstraction reduce friction—or add it?

If the answers make sense, I extract. And I try to make the reusable piece focused, boring, and low-maintenance.

Some examples from my own projects:

  • A JSON validator used across multiple forms → validate_json(schema, data)
  • A PyQt form section that renders array fields with edit/delete → extracted into a reusable component
  • A Vue table config builder → became a helper to normalize field metadata across tabs

Bonus Rule: Reusability ≠ Generalization

One trap I try to avoid is over-generalizing.

Just because something is reused doesn’t mean it has to support every future use. I write utilities that solve my three current cases, not 30 imaginary ones.

If a fourth or fifth use breaks the abstraction, I fork it or extend it consciously—not preemptively.

Final Thoughts

Reusability is powerful when it’s earned, not forced.

The Rule of Three gives me a simple signal: once a pattern proves it’s real, extract it. Until then, optimize for clarity and delivery.

You’ll write less code that fights you. You’ll maintain fewer abstractions you regret. And you’ll build tools that grow with your project, not ahead of it.


Do you follow your own rule for when to extract code or components? Would love to hear how you decide when to refactor—or when to leave it messy and move on.

Copyright © 2025