I've noticed I tend to work in three passes, although not necessarily three tries.
First is an over-abstracted mess that may or not work before it eventually collapses. Brainstorming.
Second is a rewrite aiming for compactness, that could end up impossible for anyone else to understand.
Third pulls just the right amount of abstraction out of the terseness of the second pass.
I treat it like a feedback driven control-system. Too much abstraction? Dial it down. Not enough abstraction? Dial it up. Repeat until good enough.
If I stop at 1 or 2, the code is poor. If I don't oscillate, it takes more passes.
I tend to wait until I've solved a problem in similar ways three[1] or so times before I generalize it.
[0] Because other developers want to solve for a more general problem. [1] Three is such a comfortable number, isn't it?