finally released: less piggish email code

rjbs on 2007-02-21T02:25:53

Last week, I finally released the long-ago-announced new versions of Email::Send and Email::MIME, which together greatly reduce the memory used to store an email (and, in effect, to do many other things with PEP). There was one glitch that required a small tweak to Email::MIME's part-inflating code, but for the most part it went quite well. The only other non-bogus error reports I got were from people who relied on private Email::Simple code, or used code that did so.

For example, Email::LocalDelivery::Mbox needs to escape lines in the body that begin with "From ". To do this, it parsed the message into a header and body, and then returned the header followed by the escaped body. That sounds fine, except it did it like this:

# breaking encapsulation is evil, but this routine is tricky
my ($head, $body) = Email::Simple::_split_head_from_body($$mail_r);
$body =~ s/^(From\s)/>$1/gm;

It couldn't just create an Email::Simple to do that, because there was no Email::Simple method to stringify just the headers -- except for _headers_as_string, which was private. (Of course, that didn't stop older versions of Email::MIME from using it.) Instead, it relied on a different method (well, subroutine) for doing something similar.

The clincher here is the comment! I don't really know what it means: the routine is tricky? If it does something that is tricky, and that is useful enough to use elsewhere, why isn't it just made public so nobody needs to break encapsulation? After all, both modules had the same author!

PEP has a lot of interface problems. Sometimes, fixing them is an enjoyable challenge. Other times, it's just annoying tedium.

Still, I think that a lot of the core ideas, and certainly the central goal of being as simple as possible, are good ones. What I'm most afraid of (and slightly exhilarated by) is the likelihood that I'll need to write new modules that replace the interface of a number of modules. Email::Send has some problems that, I fear, cannot be easily fixed without significant backcompat problems. Email::LocalDelivery, Email::Folder, and Email::Delete have interfaces so minimal (and in the case of Email::Delete, so unusual) that they seem difficult to reconcile into a set of tools that really seem designed to work together. Still, more modules will mean that even under Email:: there will be multiple choices for any single task, which hurts the value of the presently (mostly) one-module-per-task namespace.

I'll probably mumble about some of these plans on the PEP mailing list.


So ask the damned author already

Simon on 2007-02-21T09:09:03

Interface design is always a trade-off between simplicity and functionality. For Email::Simple the key was simplicity, but that restricted the functionality of the public interface, which of course makes it harder to build on top of that interface. We could, of course, have had an Email::Base with a big public interface, and Email::Simple and Email::MIME built on top of that, but I was really trying to get away from complex inheritance relationships. You seem to be wanting both simplicity and functionality, which is pretty much impossible.

Re:So ask the damned author already

rjbs on 2007-02-21T15:01:43

Sure, but if it's difficult to build on a base class's public interface, the preferable solution is either to build your own support structure or extend the foundation provided by the public interface, not to drive pylons through the other guy's ceiling.

It's silly to say this is just a question of features versus simplicity. It's just about encapsulation: if the feature wasn't provided publicly, it should not have been used. It should have been reimplemented or placed in a public place.

The existing code didn't choose simplicity over functionality. It used the functionality through back channels.