The first thing I like to do is solve the problem, period. Without inventing anything, just simply write code to cover most cases. Then I'll start improving on it in small ways, cutting down on duplication and inventing abstractions; until I reach a tipping point where I can visualize a complete design, which results in a major refactoring.
It looks messy in comparison to so called best practices, but it's faster and the code that comes out of the process is clearly better.
DRY is hurting more than helping if you ask me; because it shames inexperienced developers into premature abstraction, causing plenty of pain and misery along the way.
Also one can get over-eager with abstractions over things that are not real duplicates. They just happen to look similar at this moment in time.
In this category, I would also put premature automation before learning what it actually is you are automating among other things.
Or more generally: Don't try to be clever about something you don't (yet) understand.
i think i read that in POODR by sandi metz
Also quite like Fowler’s observation in Refactoring that (to paraphrase) abstractions are earned, not enforced.
I fell into the trap of premature abstraction yesterday: I spent an hour breaking down functionality to make it “easier” to implement different backends, only to realise that the “abstraction” was strongly coupled to the structure of the single backend I’d written.
Young me would have forged on regardless because “abstractions”. Old me threw it away.
https://en.wikipedia.org/wiki/Rule_of_three_(computer_progra...