It's taken a good few years, but I have learned that it's always better to write at least two or three implementations of a repeating code pattern before trying to generalize it, because there's always situational tweaks you haven't thought of each time you reuse it.
But it is still so very satisfying to go back after the third, write that general interface, and watch hundreds of lines of code wash away.