15.2.06. A Gut Feel Comparison of Code between Zope 2 and Zope 3

I’m getting ready to work on a large Zope 2 system that we’ve developed in house over the last few years. This system is a bit of a framework in its own right, with some inspirations coming from the “Component Architecture” influencing bits of the CMF and also from Zope 3 itself (while Zope 3 was being developed). This internal framework has long since moved from code managed through the web and into Python based products. It’s fairly modular, and we’ve even been able to bridge a couple of very different systems together using some relatively smart architectures.

I was looking at some code I wrote for this system. This code is comparatively recent and lightweight compared to what is in the core. I noticed something as I was looking at it though – I felt really claustrophobic. It’s not that it’s bad Python code or anything, really. But it was just claustrophobic. Methods were too long. Lines were too long! There were too many strings, strangely enough…. There was just something off. And again, I must say that it’s not bad code. It’s not being too complex, too tricky, too verbose, nor is it riddled with shortcuts. There was just a gut feel that didn’t sit quite right with me.

I decided to do a quick comparison against some of the recent code I’ve written for Zope 3 based applications. I decided to check against some of the more hairy “written under deadline” code at that, and I tried to find comparable situations (doing custom adds / edits). The verdict? The Zope 3 targeted code did not feel so claustrophobic! At all.

Now, maybe it has something to do with the older code feeling more alien and the the new code feeling more fresh.

But I think it has to do with something else that I’ve noticed about Zope 3.

I think it’s easier to chunk code up into smaller units of work in Zope 3. I think it’s easier to refactor by doing common refactorings like “Extract Method” and not have to pass as much information around. It’s easier to look up adapters and utilities that provide certain functionality instead of having all of that functionality heaped onto an object through a large inheritance tree.

And it seems like it’s really easy to abstract out common concepts into helpful tools and utilities, which grow into ones own helpful module, toolkit, or framework. At least, it’s easy in comparison to Zope 2.

I certainly know that I’ve been able to easily extract out helpful tools from common actions and update my Zope 3 based code to use those abstractions. And every time I do it, my code gets tighter and more powerful and then taken for granted since we no longer have to worry about it.

For example, a few months ago I worked hard on making a nice “undo” interface. Many ZODB storages can undo actions at the database layer. As I saw applications like GMail provide a nice “Message discarded (Undo Discard)” message for certain actions, I thought “I’d like to provide that, and hey! the ZODB can already undo things for me so I don’t have to track them myself!” So I went to work on providing a nice undo message. I ran into some snags along the way (related to things like how I was using sessions to send page messages to the user), but soon got it all buttoned down nice and neat. I was able to wrap it up in a nice API and handle deletes like this:

        name = zapi.getName(item)
        message="Deleted %s" % name

        del self.context[name]
        undomsg = cmsapi.undomessage(self, message)
        cmsapi.flash(self, undomsg)

After I checked this work in, I also added it to our oldest Zope 3 code, a content management system, in just a couple of lines, and got rid of an annoying Javascript alert box in the process. And then I promptly forgot about it until I was watching a co-worker using the CMS yesterday and saw the “undo delete” message. And watched it work flawlessly, with even the undo being undoable.

The point of this? Zope 3 eases refactoring and restructuring. I’m still amazed at how quickly our content management system came together, and how easily it was to separate out the stack into increasingly vertical levels. We almost didn’t even have to think about it. During post-mortems after major releases, consolidating code that had been copied and pasted into three different customer libraries into a single unit, without breaking our customer’s sites, was almost too easy. And on more than one occasion, just after such a restructuring had happened, a feature request would come along that was easy to apply due to that recent restructuring. “We need to make all of these things cacheable.” “Wow, a week ago that would have been four times the effort had we not boiled all of this stuff down into a core package and updated everyone already.”

And I think that’s the difference I notice between the code I was looking at today from our well-factored Zope 2 efforts compared to our more recent Zope 3 ones: we’ve been able to get rid of a lot of the line noise in our Zope 3 code, and much of the good Zope 3 code (like ‘formlib’) does a good job of clearing out line noise already. Fascinating.

3.2.06. iPods and USB 2

Today I added to my iPod collection with the iPod Shuffle. I actually wanted to get it last night, but a late day at work caused me to miss the store being open. A couple of other important errands got bumped back too. The plan was – get iPod Shuffle, go skiing. Since here is something nice and simple that can (theoretically) be operated with gloves. Or even, perhaps, by just hitting the middle of your chest. At some point soon I’ll have to test this theory for real. But in any case – I’m liking the iPod Shuffle conceptually right now. I have a playlist that I’m listening to quite heavily these days that just barely fits in the shuffle’s space. It has better battery life than my aging 3rd Gen iPod. It probably responds to cold environments better too. And it’s so tiny!

One problem. The Shuffle is geared towards USB 2.0. USB2 is only a feature on very recent Macs (within the last year or two). My main iTunes library is at the office, which is an older machine (dual 867 G4 tower). It’s not that old of a machine. But, no USB2. So I can fill it via USB1.1 at 12MBPS, and holy hell – slow.

I’ve been considering replacing my aging 3rd Gen main iPod with a new video model if I see a good price (refurbished, etc). It’s only been lightweight consideration so far. Today, however, I found out that the video (aka 5th generation) iPods and iPod Nano will not work with Firewire at all. They can charge via firewire, but need USB to be recognized by a computer.

It looks like it might take close to an hour for this 1GB shuffle to fill. Some of the slowness may be related to an extra option I have set, “Encode higher bit rate songs to 128KBPS for this iPod” to squeeze space out of it. But still – this is ridiculously slow.

I can’t imagine trying to fill a 30 or 60 GB iPod over USB 1.1. Yet if I were to get one and still expect to use it with the music library I have on my office machine, that’s the only option I have (short of buying a USB 2 card). This is a strange direction for Apple to take. I mean – I guess it is obvious that USB 2 has equalled or beaten Firewire in many markets and is used heavily in the ‘Wintel’ PC crowd. But still – to not offer support for Firewire at all? If I were still using my old home iMac G3, I’d be furious. There’s no easy upgrade option for it or for many fairly recent (2-5) year old Macs. I find that very strange.