Let me start by saying that what follows is my own personal experience and everyone else's mileage might well vary (actually, not so long ago I myself would have regarded what I'm going to write as a lot of superfluous fluff).
That said, I can very well relate to your plight, for it has been my own. And if you're designed more or less like I am, I'm pretty confident that this part can be greatly improved:
Then I think about each main step (stage) and then divide into little steps - writing all steps down for future reference.
I start to code. For example, little step #1.1 is aim XYZ.
After phase 3, you will have a series of little steps. Try noting down the inputs and outputs of each step, and the procedures that will go into each step (for example: "validate this object"). Do not yet think about coding.
In this 3.1 phase, you might give a long hard look to the problems involved in those steps and how they are solved. This is a great [if maybe a bit late] place to think about design patterns (I can't recommend Gamma's book enough), and *anti*patterns.
Then, go back to the blueprint, and every time little-step-A connects to little-step-B, consider whether the information involved in the exchange is optimal. This will uncover places where you need some data that isn't there and needs to be injected in the previous, say, five steps? Which is easy if you're still in phase 3.1, but can be sometimes murder when you're deeply committed into coding in phase 4. Or might uncover the need of some "data repository" where step B stores something that will be needed by step Y. Try to make each step need as little data as possible.
At this stage you should also have an idea of the overall performances: the steps are small enough that their complexity is known even if you haven't written them yet, and a ballpark figure about the number of times each step is called should be available (if not, there's something fishy about the specifications you're working with).
Now you will have a plethora of elementary thingies - objects, functions, matrices - that have an input, an output, and a list of things that could go wrong. Document these; this is the "contract" that each object has to fulfill.
Here is where you can further optimize and reuse code - two or more objects that are really instances of a more general object. From the contract, test cases should flow naturally: if on receiving such-and-such input object A does XYZ, then XYZ is the correct answer (or is it? Is it the only one answer to such-and-such?), such-and-such is correct (what could go wrong here? What weird inputs might occur? How to cope?), and so on.
These test cases will "fix" in time the correctness of that block of code. If further down the road you make some changes, and an automatic system is able to run those tests, you will have much fewer (ideally zero) chances of breaking something inadvertently.
When devising such cases, still in phase 3-and-a-half, you will (at least, it happens to me all the time) come up with borderline cases that were not covered in the initial specifications. That's where you get back to the customer and illustrate the situation. The time invested is significant, but... think what might happen if this was discovered later on?
And finally you're at stage 4, and when done right this is actually a comedown. You won't enjoy writing code so much; the creativity, fun stage is somewhere between 2 and 3.5. If it comes at stage 4, you'll notice that it comes from aspects of coding that should have been covered before.
Stage 4 should need little brains - it is little more than doing good-copy of a detailed draft. Yes, you'll add some nice touches and curlicues, but the real work is all there in the draft.
Most of my own experiences of brain-frying derived by overlong hours (easy solution, if available: a good night's rest), or more often by the need to shift mental gears to face some problem belonging to an earlier phase to that I was in. Which often meant to un-do or alter some work of the current phase to accommodate a patch-on solution. Rinse, repeat, go crazy.