The same eight lines
turned up in two places.
So you did the responsible thing
and pulled them into a function.
Both callers use it now.
The duplication is gone,
and the review approved in a minute,
because nobody has ever argued
against removing duplication.
Then billing needed the version
that rounds a different way.
You added a parameter.
Then reporting needed it
to skip the audit write.
You added another.
Six months on, that function
takes five arguments,
three of which only matter
in combinations nobody wrote down,
and the body is a staircase of branches
describing which caller is asking.
None of those steps was wrong.
Each was the smallest
reasonable next thing to do.
The mistake happened at the beginning.
You saw two pieces of code
that looked alike
and decided they were the same thing.
They were not.
They were two separate rules
that happened, that month,
to be worked out identically.
A shared function is a claim.
It says these callers will change together,
forever, because they are one idea.
When they change apart instead,
you have not removed duplication.
You have welded a joint
between two things
that were never connected,
and every change to one
now arrives as a risk to the other.
That is the costly part.
Not the branches.
The coupling nobody declared.
Duplication is at least visible.
You can see it, count it,
and remove it on any quiet afternoon
once you finally know
what the rule underneath is.
The wrong abstraction hides,
and it defends itself,
because pulling it apart
looks like going backwards
in front of people
who will ask why you are adding duplication.
So wait a while.
Two copies is not a problem.
It is an unfinished sentence.
Let the third one turn up.
Three copies will show you
which parts are the rule
and which parts were only that month.
And when you catch yourself
adding a flag to a shared helper
so one caller can behave differently,
read it as the message it is.
These were two things all along.
Separate them again
while separating is still cheap.
– Serguey Asael Shinder
Top comments (0)