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(@_);
$cls->run($msg->build());
}
sub run {
my ($obj, $msg) = @_;
ref $obj ? $obj->message($msg) : $obj->new($msg);
$obj->send();
}
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:
Post a Comment