Skip to main content

Reuse Without Overcomplicating

How to share logic and structure without turning the code into a fragile web of dependencies that is expensive to understand and change.

Andrews Ribeiro

Andrews Ribeiro

Founder & Engineer

The problem

Code reuse looks like an easy win at first.

You see two similar features and the temptation shows up immediately:

I should merge this now so we do not repeat ourselves.

Sometimes that helps.

Very often it does not.

Because reusing code too early does not remove cost.

It only changes where that cost will show up.

And it often comes back as:

  • hidden coupling
  • too many optional parameters
  • special behavior
  • more expensive maintenance

Mental model

Think about it like this:

good reuse shares logic that belongs to the same problem and changes for the same reasons.

That matters more than visual similarity.

Two functions can look like siblings today and still belong to different domains.

Before extracting a shared layer, the most useful question is usually:

am I removing real domain duplication, or am I just gluing together things that only look similar right now?

Breaking it down

Check whether the responsibility is actually the same

This is the first filter.

It is not enough that both code paths build a similar object or call the same API.

What matters is:

  • do they solve the same kind of problem?
  • do they belong to the same business flow?

If the answer is no, the reuse can become architectural makeup.

Check whether they will keep changing for the same reasons

This is the test that avoids the worst kind of coupling.

When two pieces of code evolve for different reasons, joining them too early usually creates a layer that looks clean from the outside and turns into negotiation inside.

Every new difference enters as:

  • a flag
  • an exception
  • a parameter
  • a special branch

And what was supposed to simplify things becomes the center of confusion.

Compare the cost of repetition with the cost of the new shared layer

A little local repetition can cost less than:

  • creating the helper
  • naming the helper
  • explaining the abstraction
  • teaching when it should and should not be used

There are many cases where copying a short function and adjusting two lines is cheaper than making the whole team learn a new layer.

Good reuse reduces maintenance and questions

A good shared layer makes the code easier to change and easier to read.

A bad one makes the reader ask:

  • what does this really cover?
  • which cases were excluded?
  • why does this parameter exist?
  • when should this utility not be used?

If reuse increased the number of questions, it probably made the system worse.

Simple example

Imagine two email flows.

Both of them:

  • build a message
  • call a provider
  • store a log

That looks like the same problem.

But looking closer:

  • one sends a welcome email
  • the other sends a critical security alert

On paper, both are just “sending email.”

In practice, they can have very different needs for:

  • priority
  • retry
  • auditing
  • template logic

If you join them too early, you hide those differences behind a generic function that slowly fills with conditions.

In that case, keeping them separate for longer may be the cleaner choice.

Common mistakes

  • extracting too early just because two functions look similar today
  • sharing logic that will soon change for different reasons
  • creating a “flexible” utility that needs too many optional parameters to work
  • treating small duplication as a bigger sin than structural coupling

How a senior thinks

More experienced engineers use reuse with healthy suspicion, not by reflex.

The calculation often sounds like this:

If understanding this shared layer costs more than copying and adjusting a short function, the abstraction already started in the red.

Seniority here is not making the code look more elegant on a diagram.

It is knowing when the sharing benefit actually pays for the mental cost and the coupling it introduces.

What the interviewer wants to see

In architecture, design, or maintainability interviews, this topic separates mature answers from automatic ones.

The interviewer wants to see whether you:

  • distinguish visual similarity from real shared responsibility
  • think in reasons for change, not only DRY
  • consider reading and maintenance cost
  • can defend honest duplication when it is still the cheaper option

A strong answer often sounds like this:

I share logic when it belongs to the same problem and when I expect it to keep changing for the same reasons. If the code only looks similar today but is likely to diverge, I usually keep it separate for longer.

Reuse is worth it when it reduces future maintenance without multiplying present confusion.

Quick summary

What to keep in your head

Practice checklist

Use this when you answer

You finished this article

Next article Avoiding Overengineering Previous article When to Abstract and When to Keep It Simple

Keep exploring

Related articles