Engineering Story · Architecture

5,000 Lines of Copy & Paste

How roughly 5,000 lines of copied code became a burden — and what untangling them taught us about the right time to abstract. A lesson learned, no heroics.

What is this? · Engineering Story

A lesson learned — a mistake, why it happened and what it taught us. Anonymized, no client named, no drama. The mistake is the teacher, not the hero. Go to overview

Author
Batunet Engineering
Reading time
4 min
Level
Advanced
Status
Approved
On this page

This story is about a mistake you don't recognize as a mistake at first, because it looks like its opposite: like caution. It is deliberately kept general — no system, no people involved, no point in time. What remains is the lesson, and it applies far beyond this one case.

Situation

In an organically grown codebase, there was a recurring task that had to be done in many places. The first time, it was written. The second time, it was copied. By the third time, copying was already the habit. Over time, this accumulated into roughly 5,000 lines of nearly identical code spread across the entire system — each copy slightly adapted, none quite like the others.

Initial assumptions

The assumption behind it wasn't laziness but a deliberate, defensible stance: copying is safe. Each copy is independent; a change here can't break anything there. A shared abstraction, by contrast, would be a bet that all these places really mean the same thing — and a wrong abstraction is more expensive than duplication. As long as the shape of the thing wasn't clear, waiting seemed like the right decision. Up to that point, this stance is even correct.

Problem

Over time, the balance flipped. What was meant as safety became a burden. Whenever the shared rule needed to change, it had to be changed in many copies at once — and you could never be sure you'd found them all. The copies drifted apart: a fix in one place didn't reach the others, and the same task behaved differently depending on the copy. "Independent" had become "inconsistent," without any single day marking the turning point.

Root cause

The real root cause wasn't the duplication itself — duplication is a legitimate tool. The cause was an overlooked signal. Duplication is cheap as long as the copies are truly independent and evolve separately. It becomes expensive at exactly the moment the copies start changing together — because then they're no longer coincidentally similar pieces of code, but a single rule in many versions. That signal was there: the places always changed together, and they drifted apart. The mistake was not reading it for what it was for too long.

Decision

The decision came when the shape was finally clear — and precisely because it was clear. Over time, the many copies had revealed the true form of the shared rule, which earlier could only have been guessed. Now there was no bet anymore: the abstraction was no longer premature but proven. So we consolidated — the shared task got a single, clear home.

Implementation

The rework didn't happen in one leap, but in small, reversible steps. First, the actual commonality was extracted — what all copies truly shared, separated from what only looked the same by coincidence. That commonality was expressed exactly once, behind a clear boundary. Then the copies were switched over one by one, each with the goal of leaving behavior unchanged before anything was improved. In the end, the code was about 90 percent smaller — the same capability, in one place instead of many.

Trade-offs

Consolidation isn't free, and it isn't always right. The single abstraction now has to be maintained; it bundles what was previously scattered and makes that one place important. The price of early duplication — the waiting — was the deliberate trade-off for not building the wrong abstraction, which would have been more expensive than any copy. We would have decided differently if the copies had truly stayed independent: then merging them would have been a mistake, coupling things that belong apart.

What we learned

The lesson isn't "never copy" and it isn't "always abstract." Both are dogmas, and dogmas replace thinking. The useful question is: do these places have to change together? As long as the answer is no, duplication is cheap and honest. As soon as the answer becomes yes — as soon as the copies start moving together — the time to abstract has come, and then you should do it decisively. DRY targets knowledge that belongs together, not lines that happen to look the same. The mistake was never the copying; it was failing to notice the turning point.

How this changed Batunet

Since then, we treat "Don't Repeat Yourself" not as a rule but as a question — and we ask it deliberately in reviews: does this change together? We copy with a clear conscience as long as the copies are independent, and we watch for the signal that they no longer are. An overlooked turning point has become a habit of paying attention. That is the value of a lesson you paid for yourself: it becomes part of how you work.

Further reading


Good lessons feel obvious in hindsight. The value lies not in knowing them, but in recognizing the moment they apply.

Referenced entities

Knowledge graph

Continue your engineering journey.

Related concepts, decisions, playbooks and perspectives — as one connected path, not a list of links.

A concrete project in this field?

Reference Guides show how we think. For your system, talk to our management — technical, no sales pitch.