I really like continuous integration. Having come from a company that didn't practice it at all (this was a time I used to regularly work 12 to 16 hours a day), I was so happy when I got into a company that actually practiced it. I found it to be a really effective mechanism to ensure that developers are on the same page -- it encourages programmers to move in small steps (changes) with respect to the code base. Those in the team who like to check in lots of changes at a time are those who tend to break the build! Making smaller changes and checking it in quickly into the source control is a safer way of making things work with this system. Because people move in small steps, the system encourages developers to frequently sync with each other's changes. I couldn't do justice to it using mere words -- it takes doing it to actually appreciate continuous integration!
Of course I wasted no time applying the same process in my project at my current employer. However I encountered a few "hang-ups" with the process. I say "hang-up" because getting feedback after checking in my changes takes a loooong time. For the first few weeks, it was very fast to complete a build from the time a check-in is done, but now it takes us like 50 MINUTES for a single build to complete! I'd love to blame the single core 1 GB hardware for it, but sadly an upgrade to the build server is not in the horizon for our team.
In an effort to streamline our build, I realised that we were doing stuff that wasn't really necessary everytime a build is run by the server. First off, the server runs FxCop. Then it runs unit tests via NCover even after it has already run unit tests -- meaning, each set of unit test DLL is run twice, first by NUnit, then second by NCover running each DLL through nunit-console! And finally it sends the source for analysis by SourceMonitor. While this produces the stats that our company bean counters like to pore over, it is not really needed for every build. So what I did was to "cache" the NCover and NUnit XML output files for those assemblies that are not very much in flux -- I copied them to another directory. Ditto with the XML output of SourceMonitor. And instead of running NUnit tasks (via NAnt) and exec-ing NCover afterwards to get code coverage stats I just settled for NCover launching nunit-console, thus generating the NUnit and NCover XML files in one shot. Which is the way it should be anyway -- why should unit tests have to be run twice?! 
So now...our build gets done in around 12 minutes. I'll still be looking for ways to speed it up, but this is already a marked improvement from the previous 50 minutes or so. To ensure that we get "fresh" SourceMonitor and NCover analysis everyday I put in a NAnt "if" task that would delete the "cached" XML files from NCover and SourceMonitor every 2 am, and enclosed the "exec" tasks for these in another "if" block so that if the cached files are missing, the tasks are run. CruiseControl.NET is then configured to force a build daily at 2 am (hopefully I don't have to be in the office when this happens). This way, we get to run SourceMonitor and other reports once a day while speeding up the builds for the rest of the day. No more continuous integration hang-ups for me! 