One of the problems with content types (there are quite a few!) is that the design with site and list content types works very poorly with the declarative (XML) approach.
If you just update your Content Type manifest and re-install the feature new content types will be affected, but not all the list content types already "instantiated" from the site content type.
This is the main reason why people choose the code approach, since this effectively "unghosts" the content types placing all logic in the content database like the list content types.
In SharePoint 2010 the story is a bit better than in SP2007 though, since we have feature upgrade. Feature upgrade, as Jim mentions, gives you the possibility to add new manifest code to be run, and more importantly the
AddContentTypeField makes it possible to add fields to existing content type, specifying if the changes must be pushed down through the list content types. More advanced scenarios can be handled in feature upgrade code. More on feature upgrade here.
In SP2007 i always took the code approach, and lots of my colleagues still do (some even outside of feature framework, calling custom code that reads XML definitions). However since feature upgrade addresses some of the upgrade issues with Content Types, i have fallen back to using XML. There are disadvantages with the XML approach with poor documentation on specific attributes, especially regarding taxonomy fields (read this article by Ari Bakker along with some of my comments at the bottom regarding DisplaceOnUpgrade and Override.
I often only create the most basic content types in XML and publish them to the CT hub. These could typically be sealed on high level and then be modifiable on the more specific levels.
I wrote up a longer answer some time ago on Stack Overflow: https://stackoverflow.com/questions/446451/sharepoint-what-happens-to-lists-based-on-content-type-when-content-type-is-upd