I usually do enough analysis of the problem domain on paper/white board to get a good enough understanding of the problem domain to start writing code. I rarely draw implementation or class diagrams on paper. A key technique I've found to achieve better design is to not get too attached to the code you write. If I don't like it, I delete, rename, move and shuffle it around until it expresses a good enough solution to what I'm trying to solve. Sounds easy? Not at all! But with good "coding" tools, actually writing the code is not the major effort. Write some, refactor, delete, write again...
Good design almost never start out good. It evolves to good. Accepting this makes it easier to work in small steps without getting frustrated why the design isn't "perfect". In order for this process to work you have to posses good design skills though. The point being, even excellent designers don't get it right the first time.
Many times, I thought I understood the problem domain when I started, but I didn't. I then go back to the white board, talk to someone or read up on the problem domain if I realize I don't understand it well enough. I then go back to the code.
It is a very iterative processes.
An interesting question to ask when dealing with how programmers think, is how they developed their way of thinking. Personally, my way of thinking has evolved over the years, but a few events have had profound influence on the way I develop software. The most important among them have been to design software with people who are expert designers. Nothing has influenced me more than spending iterations with great designers. Another event that has, and still do, affect the way I think is going back and look at software I wrote some time back.