This.
I often encounter situations where a day or two were spent creating a mess of classes and abstractions, yet the actual logic to solve the problem still hasn't materialised. A defense about "code quality" or "not wanting to write spaghetti code" is often made.
My recommendations for a problem you don't have a clear solution in mind for:
1) Hack some pseudo-code spaghetti together in a blank file until you think "you got it"
2) Write some theoretical test scenarios in another blank file (given state, steps, outcome) to verify that it's actually "solved". Discuss with a team member if possible.
3) then write out those functions from 1) inside the existing codebase
4) verify stuff is working
5) only then do abstractions / splitting up into multiple files
For a problem where the solution is already existing, but the implementation lacking (e.g. a refactoring)
1) design the new code (data structures, interfaces)
2) always propose to the team - no ninja-architecture/refactors
3) ensure the solution can be tested, document what should be tested
4) execute on the implementation
YMMV