>Making a change across 5 redundant functions is not time consuming work and is not easy to mess up.
You're ignoring the hardest part: Knowing that there are 5 redundant functions and finding all of them.
Store them all in the same place. Or if you wish to, make them use the same type signature or interface and search for this with your editor.
e.g.
widgets/
simple/
index
test
advanced/
index
test
weird-as-hell/
index
test
company-x-wanted-different-features/
index
test
tophats/
index
test
In the structure above, each of the widgets are tested separately, each are very easy to find, and each might have redundant code doing the same thing.
This is way simpler and easier to work with than if people have created an `uber-widget` that has a configuration object and some dependency injection to handle all of its features because some overzealous engineer once decided that he was certain that all of the widgets would be able to be represented by a fully generalised `Widget`.
I'm obviously not saying that all cases of DRY are like this, but I am saying that there are far too many people that end up doing this because they make decisions to generalise code too early.
e.g.
In the structure above, each of the widgets are tested separately, each are very easy to find, and each might have redundant code doing the same thing.This is way simpler and easier to work with than if people have created an `uber-widget` that has a configuration object and some dependency injection to handle all of its features because some overzealous engineer once decided that he was certain that all of the widgets would be able to be represented by a fully generalised `Widget`.
I'm obviously not saying that all cases of DRY are like this, but I am saying that there are far too many people that end up doing this because they make decisions to generalise code too early.