angry emails and api breakage

rjbs on 2006-04-17T23:50:04

I did some overhauling to a module a few months ago. I added a new interface to it, and left the old one in with a deprecation warning. After a little while, the original author uploaded a new release that totally removed the old interface. Within a day or two I'd received comments on IRC and via email. They were all something like, "The new interface is definitely better, but I had code using the old one!"

This kind of angry email is a great compliment. It tells you that your code is valued enough that someone relies on it and would like to keep using it -- as long as you don't break your promises anymore. Your public API, after all, is a promise. You can cross your fingers when you make it, by putting in a big THIS MIGHT CHANGE warning, but as likely as not people will rely on it anyway, if it's good. If you don't even provide that warning, people will assume that things will be backwards compatible forever. The CPAN (which has spoiled me for doing serious work in other languages that I like more than Perl) helps enforce this promise in a few ways. For one, more people have easy access to your code, and to code that requires your code. For another, even if you go from "v1" to "v2" -- which largely identifies when APIs can break -- there is no way to indicate that in your distribution metadata. Some of the mod_perl team pushed for this when Apache::Request (and more) modules were going to come out for Apache 2. Apache::Request 1.x and 2.x weren't going to be interchangeable, but they had the same name. The request to add metadata to do this was denied, so they had to move to a new namespace.

The only module does a bit to mitigate this problem, but it ends up with the same issues as Firefox's extension compatibility metadata. Authors are encouraged to give a maximum compatible version, and their code then breaks for no reason other than that arbitrary metadata. (I am under the impression that the 1.5.0.x versioning is, in part, a way to deal with this, but I'm not a Firefox developer.)

The "sacred promise" nature of APIs came up recently in a discussion with Johan Lodin, who wrote Sub::Define. Sub::Define is a similar module to my Sub::Install. (Both, in turn, are reactions to our mixed feelings about Sub::Installer.) We talked about the extensibility mechanisms provided by both our modules. He said something like, "supporting new behaviors is hard. How do you do that in a clean, safe way? What if you change the interface?"

I responded that, basically, you don't. You offer a new interface, maybe, but you leave in some kind of support for the old one. Otherwise, your users' code breaks when they upgrade -- and, sure, they should know that upgrading from 0.03 to 2.91 might cause problems, but they'll upgrade anyway. Once you break their code by changing things, they will no longer trust you, and you will have a harder time getting any market penetration. They will send you angry emails. (Maybe you don't care. That's OK, but you should be ready to receive those emails.)

After talking with Johan, I decided to steal some of his ideas, and got back into the guts of Sub::Install. I was not thrilled to find that I'd documented one interface to a subsystem (which I suggested avoiding), but implemented another. My tests were written to the implementation, so they passed. The documented interface was superior.

Today, I uploaded a new release to the CPAN. It has a number of little improvements, one of which is fixing the code to match the documentation. I'm not sure whether I'm breaking a promise now, or mending my ways for a previously broken one. More than that, I'm really not sure whether I'm hoping to receive any "complimentary" angry emails.


That's not the full story with Apache

Alias on 2006-04-18T05:01:03

The way you've laid it out is not entirely how it went down.

The problem with the Apache::Request situation was not that they were going to chance Apache::Request 1 to an incompatible Apache::Request 2.

You would great a major incompatibility, which would mean you had to immediately drop support for Apache::Request 1 (no more releases) and you could only ever have either Apache::Request 1 or Apache::Request 2 installed, you could never have both installed without a completely seperate dedicated Perl install.

But that has been done before. GD did it. It hurt, but it was their choice. And I for one will never use GD again because of it.

But the problem was that in doing so, they THOUGHT that they could work around the problem. They thought they could have their cake and eat it too. But they were wrong, and it took a _lot_ to convince them of that.

The doomed scheme would have ultimately meant changing EVERYTHING else to fit their workaround. They'd already written their own version of MakeMaker, they were starting to write their own version of perldoc (mp2doc!!!), they wanted CPAN changed to suit them, and if they had kept going, we would have seen a gradual expansion to replace pretty much everything with their own versions.

That was the real problem.

The point at which things changed was when half a dozen people including me managed to finally convince the mod_perl group that they COULDN'T have their cake and eat it to.

That the workaround scheme was ultimately unworkable, and that Perl just did not work that way. So the choice they had was either 1. Do a GD.pm, break of legacy support entirely, and go with the complete API change in the same namespace. 2. Do something else (I think I suggested about 5 options at one point) the most attractive of which was moving to a different namespace (Apache2:: being the obvious choise).

And after much deliberation by the group on the merits, they decided that the level of pain that would be introduced by doing an API change, once the workaround was no longer an option, exceeded the threshold of what they were willing to do to their userbase.

And so they decided to go with Apache2:: instead.

The problem was not the API change, it was that the solution to that problem that they'd gone with up until the first release candidate was a bad one.

Re:That's not the full story with Apache

rjbs on 2006-04-18T11:07:21

Yeah, I remember the whole thing pretty well, and I'm glad they ended up changing names. It was a real nightmare.

I just simplified, since I wasn't writing really about mod_perl. ;)