Opening the book…
Premature optimization and premature abstraction are two of the most reliable ways to waste time, because you're solving problems you don't yet have and often guessing wrong about which problems you'll get. The healthier order is to first make it work, prove the thing is even the right thing with the simplest version that functions, then make it right, clean it up now that you understand the shape of the problem, and only then make it fast, if measurement actually shows you need to. Jumping straight to elegant or fast means building sophistication on top of an idea you haven't validated, and half the time you'll throw it away. This order also keeps us honest about performance, because 'fast' should be driven by real measurement, not by a hunch about where the bottleneck is, and our hunches about performance are famously bad. Doing it in order isn't sloppiness, it's sequencing your effort so you spend it on problems you actually have.
Start with the simplest version that works, even if it's ugly, and get it in front of reality to confirm you're building the right thing. Once it works and you understand the problem, make it right: clean structure, good names, the abstractions that are now obviously warranted rather than speculatively invented. Only reach for performance work when you have a measured reason, profile first, optimize the actual bottleneck, and stop when it's good enough rather than chasing diminishing returns. Resist building the general, configurable, future-proof version until you have at least two or three real cases to generalize from. Let the design emerge from the problem instead of imposing it up front, because the problem usually knows better than your initial guess.
Some constraints are known up front and can't be bolted on later, security, a hard latency budget, a scale requirement you're certain of, and those you design for from the start. The rule is against speculative polish, not against thinking ahead when the need is real and clear.