What I’m going to rant here though is about abstractions, that claim to be “thin layers” over something else and that makes them “good” because they can switch “backends” easily and then are “more flexible”. In case you don’t know what I’m talking about, here’s some examples: Phonon, XUL, Cairo
The biggest problem abstractions have is the lowest common denominator problem. You need a fallback mechanism if one of your backends doesn’t implement your feature. Most of the time, this fallback mechanism is not implemented, so using it ends up either being a “query capability and only use it if available” dance in applications or it just does nothing and users on weird backends (like BSD ;)) wonder why your application doesn’t work.
And even if you have a fallback mechanism, it often is very suboptimal and behaves wrong when compared to “native” output. Firefox’s awesomebar dropdown still looks totally out of place in GNOME compared to Epiphany’s and sometimes selecting text in cairo-generated PDFs is impossible, because the text was rendered using an image fallback.
Another similar problem is that you have to limit the API you design to the backends. You cannot sensibly make use of a real cool feature if most of your backends don’t support it – or you have to implement it yourself for all the backends. Depending on your choice, you either end up with unhappy users or N times as much work.
In the same vein there’s the problem with additional API burdened upon the user to properly support all backends. Cairo is going to gain the useful feature to mark text as a link or attach the riginal JPEG data to an image, so the PDF and SVG backends can include this information. However, this information is completely useless if you output to the screen.
And finally you’re writing a lot of code – mostly compatibiltiy code matching your API with the backends or fallback mechanisms for their unimplemented features. So you have to ask yourself if the “thin layer” you’re writing is really that thin or if you’d better use the underlying features directly. From my experience the answer usually is to use the underlying feature directly unless the “thin layer” adds some substantial features itself.