Skip to main content

When to Abstract and When to Keep It Simple

How to decide whether a new layer is helping or whether the code is still better when it stays direct.

Andrews Ribeiro

Andrews Ribeiro

Founder & Engineer

The problem

There is a very common moment in development:

you see two similar things and think:

I should abstract this now so I do not repeat myself.

Sometimes that helps.

Very often it does not.

Because the abstraction arrives before the understanding does.

And when that happens, the team gets:

  • one more layer
  • nicer names
  • less clarity
  • more cost when something needs to change

Mental model

Think about it like this:

abstraction is the act of compressing a pattern that has already become clear enough to deserve its own shape.

If the pattern is still fuzzy, the abstraction is not compressing understanding.

It is compressing uncertainty.

And compressed uncertainty usually comes back as:

  • too many optional props
  • weird parameters
  • special cases
  • an internal API nobody really understands

Breaking it down

Check whether the code changes for the same reason

This is the most useful test.

If two pieces of code look similar but are likely to evolve for different business reasons, abstraction can glue together things that should stay separate.

That is where the trouble starts.

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

A small amount of local repetition can be cheaper than:

  • creating the helper
  • naming the helper
  • explaining the helper
  • changing the helper when the third case arrives

Not every duplicated line deserves architecture wrapped around it.

Prefer simplicity while the pattern is still maturing

If you are still discovering the variations, direct code often teaches more than a generic layer.

Later, once the pattern becomes clear, abstraction gets much easier and much safer.

Good abstraction reduces questions

A good layer makes the reader ask fewer questions.

A bad layer makes the reader ask:

  • what does this really do?
  • when does it stop working?
  • why does this parameter exist?

If the abstraction increased the number of questions, it made the code worse.

Simple example

Imagine three notification flows.

All of them seem to do this:

  • build a message
  • call a provider
  • store the result

The first impulse is to create a highly generic sendNotification().

But looking closer:

  • one flow is marketing
  • one is a security alert
  • one is an operational confirmation

Now retry rules, audit needs, and priority are already different.

At that point, the better move may be to keep things explicit for a while.

Once it becomes clear what is truly shared, then you can extract the right layer.

Common mistakes

  • abstracting too early just to satisfy DRY
  • treating small repetition as a bigger problem than structural confusion
  • joining behaviors that change for different reasons
  • creating a generic API full of flags, parameters, and exceptions

How a senior thinks

More experienced engineers often ask:

Is this abstraction happening because the pattern is mature, or because I feel uncomfortable seeing repetition?

That difference matters a lot.

Seniority here is not making the code look more sophisticated.

It is knowing when it is still better to keep things simple.

What the interviewer wants to see

In interviews, this topic tests design judgment.

The interviewer wants to see whether you:

  • distinguish acceptable repetition from dangerous coupling
  • avoid premature abstraction
  • think about maintenance cost, not only elegance
  • can defend simplicity without sounding careless

A strong answer often sounds like this:

I abstract when the pattern is already clear and when the new layer reduces reading and maintenance cost. If I am still discovering the variations, I usually keep the code more direct for a while.

Good abstraction reduces cost. Early abstraction mostly redistributes confusion.

Sometimes the more senior move is resisting the urge to be clever too early.

Quick summary

What to keep in your head

Practice checklist

Use this when you answer

You finished this article

Next article Reuse Without Overcomplicating Previous article Debugging Rounds: How to Investigate Broken Code Like a Real Engineer

Keep exploring

Related articles