As one of my professors used to say, "There's no problem that can't be solved by adding another layer of abstraction". He was joking, but there's a little bit of truth to that.
I've been working on my other website for a while. It's all PHP4, not entirely by my choice but I'm limited what can be installed on my server. PHP4 turned out to be a lot more powerful than I'd initially thought. Namely the OOP options available are mostly adequate and in a few places surprisingly OK. PHP has some nice meta-programming sorts of functions like
call_user_func() which let you play around with doing weird things dynamically at runtime, which were almost essential in putting all this crap together. It lacks the completeness or elegance of Ruby, and PHP's syntax is generally horrific and painful, but it'll do.
I recently read Head First Design Patterns which is quite a good book. I was able to use plenty of what I learned there in designing a sort of templating system for my other website. Basically I have tons and tons of tables of different sorts of data. CSS goes a long way to making the presentation of the tables easy to change given that they are properly marked-up, but actually marking them up properly and consistently was the problem.
So I put together a bunch of classes that generate HTML tables. One of the things from Design Patterns that really makes sense when you hear it is to lean toward composition rather than inheritance. In other words, an object that has another object as an instance variable is often easier to deal with than an object that inherits the same functionality from a parent class; the reason being that you can use polymorphism to your advantage, and have your object contain a member of a GENERIC type, and then you can give your object an object of any subtype of that generic type you want. So your class then does not depend on the type of its instance variable at all, so long as all possible objects that end up in that variable have the same interface. Loose coupling and all that.
I have used this to great advantage in adding flexibility in marking up table cells. A cell will be a different class (actually a different composition of lots of classes) depending on the kind of data it stores. A TextCell holds text, so I know to pad it and format it (differently than an ImageCell, or a cell containing an unordered list). I can composite TextCells with other more specific types; a value that represents a percentile is a PercentileCell; the class handles formatting the numeric value and sticking a % on the end. I could composite it with an ImportantCell which will give it a special background color. It's as simple as
$cell = new TextCell( new ImportantCell( new PercentileCell( 56 )));
The nifty thing is that I can composite the cells arbitrarily in any order or combination, because each simply holds a generic "cell" member and calling a method on an object only causes it to call the same method on its child object, all the way down the stack. Also, if I later decide to take the % off the end of all my percentile values, I can do it by changing a single class definition. That's the kind of thing you can't handle well with HTML/CSS alone. Before, it'd take me a month and half to go mucking around in static HTML files fixing it all. (Or an hour worth of Perl regexing, but still, no fun.) Or if I want my HTML to validate as XHTML Strict, I can change the HTML for all my tables at once by screwing with the base Cell class. If I want to turn it into XML or some other markup, I could do that too, in theory.
At this point I'm essentially writing most of my pages entirely in PHP, never needing to write any raw HTML by hand at all, which is a very nice change of pace. I wish they'd have taught more of this sort of thing in college. We learned how to write searching and sorting algorithms until blue in the face. But we never really touched on how to design software at a very high level. I still think I'm not too good at it in many ways, but I'm learning, at least.