Rare check-insThe most important practice for CI to work properly is frequent check-ins to trunk.
Many projects use branches and forget that if you are not merging your changes to trunk often then you are not doing truly continuous integration since you are not integrating the changes done in different branches.
There's a collision between branching and CI. That's why branches are not recommended except in very limited circumstances.
Lack of a comprehensive test suiteWithout unit, component and acceptance tests being run by your CI system, how do you know that your software is working?
Many projects just rely on a passing compile build which is clearly not enough for most applications.
Long build timesTen minutes is probably the limit. More than that will make people check in code less often which in turn could lead to more failing builds.
The problem is usually long-running tests. To overcome the problem, split your test process into 2 stages that run separately: the commit stage that just creates a deployable binary after running unit-tests (on every check in) and the heavy-testing stage that uses the binary from the first stage and runs a series of acceptance, integration, performance or other type of long-running tests against it.
Slow development workspaceThe most common problem is that the application cannot be run locally or it takes a long time to do so. This means that the application cannot be tested on the developer's machine prior to check-in without going through a lot of pain.
Possible solutions include deploying the application on lighter containers on the local machine or use products e.g JRebel that make it possible to skip (longer) redeployment phases.