June 30, 2006

MJD on Class::Observable and false trade-offs

(aka, "at least he said I'm competent!")

Back in April Mark-Jason Dominus visited Pittsburgh in support of his upcoming book Perl Program Repair Shop and Red Flags.[1] Actually, "in support" doesn't quite capture his intent. Instead of a typical process where the author dictates from his experience about X technology or Y methodology, MJD is creating a book showing standard programming and design mistakes people make and how you can fix them. It's similar to refactoring but the focus is on real-world problems rather than the standard examples (bonus calculations, calculators, scoring games, etc.).

The announcement to the group asked people to send in their code for MJD to fix up. Of course nobody did, I think partly because a lot of code people work on is internal and they're not sure whether it can/should be shared with the world. And partly because nobody likes to see their code torn up in front of a group of people, much less in a book where it'll be preserved forever.

In the absence of volunteered code MJD scoured the CPAN directories of pgh.pm members, finding Class::Observable which fit the bill very nicely:

  • what it does is easily understood,
  • there's only one file to review, and
  • the non-POD LOC is around 225.

We didn't know what he was going to review beforehand, and I came in as they were passing out paper copies of the code, just before he started. I sat down and looked at the paper: 'Observable.pm'. "Aww, shit," I muttered, just loud enough for the person next to me to hear. At least I didn't have time to worry about it beforehand.

Now he's written up a good summary of what he said at the meeting. It sounds more painful than it was, honest. Partly because I haven't touched Class::Observable in a while, partly because he was straightforward and professional (non-personal) about it, and partly because I think I took it in the spirit it was intended.

A couple of the questions he had were easily answered. But the main problem he has with the class is that it doesn't use the object to store data about the object. This is so common-sense that it shouldn't even bear repeating, right? It's a little murkier than that, as he alludes to in the writeup. (The fact that he made the same mistake in something he wrote was comforting.)

The real reason I didn't use the object was that I did not want to touch the object. At all. Why not? My original thought was that I didn't want to assume anything about the object's implementation. This is something you need to worry about in Perl that you don't with languages that are built around OO. Since an object is just a reference with metadata about where it belongs, and a reference can be a scalar, array or hash, you can't assume a way to store object data.

But you can assume methods, which is the whole point of the object anyway. And as Mark showed in his implementation, all you need to do is define a default behavior for the common case (object-as-hashref) and let people implement their own uncommon cases by providing method hooks for them to do so. It's a much clearer implementation and makes a lot more sense.

So my reluctance to touch the object was really a type of cargo cult behavior[2]: You can't depend on object implementations so don't put anything in the object. Instead of thinking about the general problem and the best implementation I didn't even consider a set of solutions because "you don't do that" -- a false trade-off. It's humbling when you realize this sort of behavior in yourself; I don't think I'd make the same mistake today, but maybe I already have and just don't realize it yet.

[1] I heard he did this same talk at YAPC 2006 a few days ago. Hopefully he didn't use my absence to be harsher than he was in Pittsburgh :-)

[2] I seem to remember a great writeup of this from MJD's blog, maybe somewhere else, but I can't find it now. If you have a link please send it on.

Next: Some recent technical books: Concurrency, Messaging, Ajax, Web design
Previous: Stranded at LGA