When you're going to write a 3D shadows engine, your choice is basically restricted to two possibilities: shadow volumes or shadow mapping in one of its flavours.
There's no reason to choose shadow mapping but the performances: shadow volumes are more accurate, because a shadow map is a simple texture spread on a scene and used for depth comparisons. It's obvious that texture's detail affects render realism, and all sort of aliasing will happen.
The quickest way to improve an image-space based algorythm is to improve the image.. space! You should render the scene with higher resolution. But you can't. Reason is that even if you raise the viewport size, anything greater than the actual container window will be dropped.
There are also restrictions for the texture shape and dimensions, but you could get around them using some of the latest extensions (ARB_texture_rectangle, ARB_texture_non_power_of_two)... but anyway, the problem remains: we are in need for detail. There are sophisticated geometric solutions, such as trapezoidal/perspective shadow maps and cascading shadow maps, but we could simply... render elsewhere!
Here come frame buffer objects. They are basically "containers" that you can use as targets for your renders. You can also use them to directly render on a texture, and this is our case: we render there our huge shadow map.
The difference is clear and performance hit is not dramatic. The coolest part is that using FBOs does not take modifications to previous routines (just bind the directly generated texture as usual!), and can be turned on in every moment. Approved!