A ICE (In-Circuit Emulator) replaces the target chip. It acts like the real chip to the rest of the circuit, but has all kinds of hooks inside so you can see what's going on, set break points, load new code, grab traces, etc. A ICD (In-Circuit Debugger) uses special debug hardware added to the target chip for that purpose and tries to give you ICE-like capability. Unfortunately, marketing people have gotten envolved and tried to redefine these long standing terms in their attempt to deceive you into thinking their product is better than the next one. Microchip's RealIce is a particularly egregious example of this. It is real, but the one thing it's not is a ICE.
A real ICE (not the RealIce) is the best in-circuit debugging environment. Unfortunately these have pretty much gone away because of the high cost of making a special bondout version of the target chip for use in the ICE, and the fact that speeds have gotten so high that taking anything off chip is problematic. Another problem is that a ICE requires the target chip be in a socket, or requires a special adapter mounted in place of the target chip so the ICE can connect to its lines.
So today we're stuck with ICDs. Fortunately they do most of the things you would want to do with a ICE. They even have one advantage in that the code is running on the real target chip, not something trying to be like the target chip. The downside is that they require on-chip resources so aren't completely transparent to your code and hardware like a ICE is. The ICD needs access to debugging lines, which can often have multiple roles. You can't use those pins in other roles while debugging. The amount of debug circuitry built into each part must be kept to a small fraction of the total else the cost would be too high, so features have to be compromised. One nice feature that would be too expensive to add on every chip is true trace capability, since that requires a large RAM buffer.
Every problem can be eventually solved with a variety of tools. It's not whether you can solve it, but how long and how much effort it takes. When I was regularly using ICEs (Microchip ICE-2000 and ICE-4000), I didn't use the trace feature often, but when I did other means would have been significantly more costly. Sometimes you have a bug where a variable suddenly has the wrong value in it. You step thru the code and everything is fine and the routine that manipulates the variable seems to do everything right, but when you run it eventually things crap out and you find that variable trashed. The cause is some other code with a bad pointer, buffer overflow, stack mismatch, or the like. With a ICE you can set a breakpoint on the variable being changed, then look backwards in the trace buffer to see how code got there and how things got messed up.
Most of the time, a ICD will do well enough. Especially with large chips, the couple pins dedicated to debugging isn't that much of a problem. Nowadays I mostly use the RealIce for debugging. It's a lot more stable and less flaky than the ICD2. You learn to live with it.