Monday, October 29, 2012

When Layering Goes Bad

A lot of systems are built in layers.  Games are often split into engines and scripts.  Another classic is the "three tier" architecture with data storage, application model, and view-controllers split out onto individual machines.

But more often, I run into systems where code is taking a core sample instead of building on the layers.

Here's a little example:
package Contoso::Mailer;
sub send_new {
  my ($cls) = shift;
  my ($msg) = Contoso::MIME->new(@_);
sub run {
  my ($obj, $msg) = @_;
  ref $obj ? $obj->message($msg) : $obj->new($msg);
Contoso::MIME is a thin layer around Email::MIME which in turn extends Email::Simple with MIME features.  To use Contoso::Mailer successfully, you need to know all of that; whenever you're using Contoso::MIME, you're using something documented in three separate places, because each package only describes what it provides.  And then you have to be careful of what was overridden, because the parent documentation doesn't know anything about the children.

The Email::* packages also rely on you understanding email and MIME from their respective RFCs.  Much is implicit, because they define a translation between words that make for convenient Perl hash keys (content_type) and the actual header names that go on the wire (Content-Type), then leave you to know what headers you should be able to provide.

Making matters worse in my particular case is that Contoso::MIME has some major disagreements with Email::MIME about how a message-building API should look, so it's not so much a simple "extension" as half-replacement.  Even better, you can look at Contoso::Mailer and it indicates nothing about that, unless you happened to catch build() lurking in there—in which case you still need to know what type that returns.

In essence, a successful layer is like asphalt: all the dirt gets hidden, and that's okay because you didn't actually need to handle the dirt.  Less successful layers are full of potholes, and may occasionally need to be cut through to access important plumbing that was supposed to be hidden.

No comments: