I recently made the argument that abstraction layers are a bad idea. It’s not the most popular of opinions.
It is one that I stand by whole-heartedly.
In the .Net World
I once was tasked with building an entire wed CMS from scratch in C#. Before you panic, know that it was an exciting project!
I had the opportunity to learn about URL mapping, MVC principles, query optimization, and caching. I also learned how to navigate a sharded, load-balanced cloud hosting infrastructure.
It was a blast!
But I also learned that ASP.NET hid a lot of nastiness under the hood of its abstraction layer. Luckily, I’d invested in a copy of .NET Reflector, so I could easily identify that nastiness.
The biggest offender was the built-in cache.
In .NET, you can declare a view[ref]A method that populates and renders a page template.[/ref] as cached just by decorating it with an attribute. It’s simple, powerful, and means you don’t have to touch the caching layer at all.
Well, if you’re using HTML explicitly, that is.
My web app exposed a handful of JSON endpoints for consumption by an API. After we launched, we opted to enable caching on these endpoints to alleviate some of the database load. I added the attribute; our API ceased to work.
It turns out the built-in cache for that version of .NET automatically rewrite the content type of the returned document to “text/html.”
That meant my cached JSON endpoints, my cached XML endpoints, my cached file endpoints – they were all declaring themselves as HTML documents!
Trusting the abstraction layer led to hundreds of angry customer calls, hours of debugging for me, and an eventually rewriting of the default cache to avoid the issue.
JavaScript
We don’t need someone who knows JavaScript, they just need to know jQuery.
Yes, I’ve heard the above – verbatim – from a hiring manager. The concept terrifies me.
I love jQuery. It’s a fantastic way to keep your code light and cross-browser compatible. The powerful Deferred object is one of my favorites.
But if you’re writing code for jQuery without understanding the underlying JavaScript it’s built upon, you’re setting yourself up for a world of pain. I once worked with a jQuery-based table library that was pretty powerful, had a fully-featured front-end UI, and possessed the worst performance of any library I’ve ever seen.
For small tables, the library worked just fine. For larger tables, though, it became an endless memory sink.
To work around the lack of [cci]:hover[/cci] support in IE6, the library added a mouseover event to each cell of the table to automatically change the cell’s class so it would be properly highlighted. The way the library did this, however caused issues. Here’s some (horrendous) pseudo code to show how the library was functioning:
$( 'table td' ).each( function() {
$( this ).mouseenter( function() {
$( 'table' ).find( '.hover' ).removeClass( 'hover' );
$( this ).addClass( 'hover' );
} ).mouseleave( function() {
$( this ).removeClass( 'hover' );
} );
} );
If it’s not immediately obvious, the above is a bad idea. First, it’s recreating the jQuery object containing the table on every iteration of the table cells in [cci].each()[/cci]. Second, it’s binding an event to every single cell in the table.
For a small table, you probably wouldn’t even notice. The table I was building, however, had 30 columns across 300 rows of data – meaning this library was binding 900 discrete mouseover events just to handle animating the table as the cursor moved across the screen!
On Internet Explorer, it took 5 minutes to load the entire table.
I rewrote the library – creating my own fork – to instead bind a single (throttled) mouseover event on the table itself that used event delegation to detect when the cursor hovered over table cells.
My rewrite took the table load time down to 10 seconds.
Understand What You’re Doing
I’m not saying abstraction layers have no purpose in development. When you know what you’re doing, certain tools can save considerable time and make your application more stable.
But when you don’t understand the underlying principles used by your abstraction layer of choice, you can run into issues. Errors due to underlying framework assumptions. Performance issues. You name it.
I like abstraction layers because they make life easier for developers. I dislike abstraction layers because they raise issues for new developers who have yet to master them.