I am sort of in the same place you are, but I'm not sure I could have done it any differently, in my case.
I usually try to do a process of constant refinement. I program the first working part of the program, then the next. Any time I feel the urge to cut and paste from the first program I pop the routine into a shared module. So my modules are built from routines that absolutely have to be shared, and nothing else.
The trouble with this approach is I am practically garanteed to paint myself into a corner at least once. So at some point I have to take some time off and redo functions in the modules (combine some, separate others, etc). I then have no choice but to take some time to reprogram stuff I've already done. To aid this process I usually document every variable and function using Lyx, and constantly update the docs as I move functions around. The upside of this is I can tidy up the notes and give them to the client as part of the documentation.
I didn't believe in evil until I dated it.