
The 1, 2, n pattern - terodox
https://terodox.tech/one-two-n-pattern/
======
keithnz
This advice has been around for a while (in various forms) I would say most
people converge on this after a while. The only problem I have is with

"My response is generally the same to all of them, the maintenance for two
function is very small compared to a bad abstraction that can grown into a
monster very quickly."

That's a little bit of a red flag. Bad abstractions shouldn't lead to
monsters. This is more important than when to abstract! Bad abstractions are
going to happen no matter what way you create them, but you should always have
a design mindset that leads you to being able to back out of them and change
your code. Two very simple design concepts (but often have very deep
implications) help with that: composability and modularity. They should guide
your refactoring a lot, not just that there is duplication, but if you do
extract it, where to? and how will it compose with other things ? you do that
well, often your abstractions are easier to change. (Do it badly and often you
will see an explosion of types to allow composition that often then make your
abstractions much harder to change)

~~~
terodox
That's a hard argument to argue with. I have to agree with you.

------
malcolmwhite
I've heard a similar pattern called the rule of three:
[https://en.m.wikipedia.org/wiki/Rule_of_three_(computer_prog...](https://en.m.wikipedia.org/wiki/Rule_of_three_\(computer_programming\))

~~~
preommr
If you google 'when to refactor rule', the first hit is "rule of three"
followed by a bunch of other articles also calling it by this name. It's a
fairly popular term/idea.

------
256
The problem with this in practice is that you're often not the person
implementing the 3rd instance. It's some other dev who comes and sees 2
copy/pasted implementations, either figures there's a good reason for it, or
is lazy, or is risk adverse, or just wants to get the job done and move on,
and copy/pastes it a 3rd time.

~~~
aaronbrethorst
Explanatory comments that tell the reader to go look for other instances of
this pattern are the key to success.

    
    
        // AB-20200405 - Hi future developer (probably me),
        // if you're copying and pasting this code, then
        // please take an extra five minutes to locate the
        // other similar instance of this code snippet in
        // the codebase, and refactor both of these into a
        // method first. The other snippet will have the
        // same comment that precedes this one.
        // 
        // Here's what this overly clever snippet of code 
        // is doing, so that when you do refactor it into a
        // method in 2023, you don't miss an important edge
        // case. Ta!

~~~
heavenlyblue
Another life hack: reference the same “AB-20200405” in the other code snippet.

~~~
aaronbrethorst
Right, it all falls apart otherwise.

------
nkozyra
There's an art to knowing when it's time to generalize/create an abstraction.
Because of this I find it silly to create heuristics or rules for doing so.
They're as likely to be wrong as to be right.

Which leaves us in a spot where this is always subjective. Sometimes the third
duplication is the time to generalize. Sometimes it's the tenth. Sometimes the
first.

~~~
setr
Genrralizing is only helpful for the future; in the present, it doesn't do
much (unless you're simplifying egregiously complex code -- but this doesn't
require a generalization, just hygiene).

Thus, every generalization is a guess, at best based on previous experience,
unless you already know you're going to repeatedly use it already. So you'll
always have some kind (experienced-based) hueristic; you might as well define
one explicitly to go by, as a rule of thumb

------
dustingetz
The wrong abstraction is worse than repeating yourself ... DRY is how we ended
up with AbstractSingletonProxyFactoryBean or whatever

------
flipcoder
I generally agree with this, although this is more helpful when you can't
predict future usages of an abstraction. I don't think there's anything wrong
with an early abstraction if you know for certain it will be reused, or if it
makes the code easier to understand.

------
pezo1919
The funny thing is that what we'd really need and lack of is inlining an
abstraction. If we could just systematically broke down the abstraction
hierarchy and rebuild it from the ground when needed with a helper tool, then
many issues would go away. The stress is on "systematically" & "helper tool".
Sure you are smart and you can do it but its easy to forget about cases.
Coding is not hard at all from this perspective, not to forget about any case
is hard - and tedious - can be automated for sure.

------
fastball
The more important thing to me is to make sure the code is written a way that
makes it easy to refactor / add abstractions _whenever_ it becomes necessary.
Things like:

\- having explicit variable / function names to make global search/replace
easier when necessary, but generally just for clarity.

\- thinking about file structure early and often

\- always using constants to represent any value that is repeated across the
system

------
fralewsmi
You learn this pretty quickly in practice, I think every junior dev has tried
to make an abstraction the first time they saw some complicated business logic
and failed miserably. Now if I think an abstraction is easy I'll do it the
second time around, otherwise I'll wait until its absolute (n)ecessary.

------
cryptoz
A related (but distinct) concept I've heard is "0, 1, n" rule: there are
rarely actually 2 or 3 or 10 of a "thing". But often there are 0 of a thing,
or 1 of a thing. If it's not 0 or 1 thing, it's probably _n_ things.

~~~
AnimalMuppet
I've heard a slightly different version of that. 0, 1, infinity. For a data
item, there should be 0 items, exactly one item, or (up to) an infinite
number. You shouldn't have, for example, a fixed limit on the size of a string
or the number of different phone numbers a person can have. If they can have
more than one phone number, they should be able to have an infinite number.

------
Forge36
I'm doing this on a project I was pulled in on. I have 5 sizable behaviors,
all copy pasted. I finished merging them this weekend. "When you find yourself
making the same enhancement in many places".

~~~
terodox
Or fixing the same mistake in several locations, which is happens now in my
case.

~~~
AnimalMuppet
One of the first things I learned as a programmer was "Did you fix it
_everywhere_?" Then, later, I realized how nice it was to have only one place
that it needed to be fixed.

------
dang
Related from a few days ago:
[https://news.ycombinator.com/item?id=22749837](https://news.ycombinator.com/item?id=22749837)

------
schemathings
Had this described as "Three or more, use a for"

------
3pt14159
"Once, trice, never thrice."

