For me, since M has no build-in debugger to speak of, I waste 50% of my time just in debugging, which could have been saved if there was a debugger. 50% of my development code is Print statements, since without these, I'll be lost finding where an error is coming from. (this is bad also, since too much print messages in the code, makes it hard to see the algorithm sometime, it gets in the way, but can't remove it, since I might needs it later on).
I find it amazing that such a powerful and flexible computational tool like M, still has a relatively less advanced development environment. When I am using Matlab, It takes me few seconds to find where a bug is, using the debugger.
Someone might say use Workbench for debugging. I tried to use to debug a Manipulate demo, and I can't figure it out. Too complicated to use. M needs a simple easy to use debugger build-in (in the notebook itself, not a separate program), and with line numbers!
Ok, Given the above introduction :), this is what I do myself in response to your question:
have different level of debug messages. coarse level, and detailed level. Coarse level prints only a message when it enters a function and when it exists the function.
I have a button on the UI to use to turn on/off debugging (if you are doing UI based program, else it will be in the code).
Use a separate debug function, where debugging message go through before being printed. In there, you can add time stamp to each message and such before printing (can also control if you want messages to go to text file, from one place). Rest of your code, just calls this debug function with the message to print. I print everything now to console, not to current notebook.
Each debug message with have the function name that called it at its start.
If you want to control debugging at the module level, what I do, it simply make a local debug flag inside the Module, and turn that on/off each time I want to debug that one specific module. This local debug flag takes over the setting of the global debug flag. This way, I can debug just one module if I want, and not the rest of the code.
There are many other ways to customize all of this. But I found that if I spend more time early on to make a good debugging message system, it help allot in finding bugs when needed.
Here are some useful link
http://reference.wolfram.com/mathematica/guide/TuningAndDebugging.html
workbench debugger (if you can figure how to use to debug Manipulate and Dynamics, please let me know)
http://www.wolfram.com/products/workbench/features/debug.html