<?xml version='1.0' encoding='UTF-8'?><?xml-stylesheet href="http://www.blogger.com/styles/atom.css" type="text/css"?><feed xmlns='http://www.w3.org/2005/Atom' xmlns:openSearch='http://a9.com/-/spec/opensearchrss/1.0/' xmlns:georss='http://www.georss.org/georss'><id>tag:blogger.com,1999:blog-13463691</id><updated>2009-02-20T19:26:01.968-07:00</updated><title type='text'>Griddle Noise</title><subtitle type='html'></subtitle><link rel='http://schemas.google.com/g/2005#feed' type='application/atom+xml' href='http://griddlenoise.blogspot.com/feeds/posts/default'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/13463691/posts/default'/><link rel='alternate' type='text/html' href='http://griddlenoise.blogspot.com/'/><link rel='hub' href='http://pubsubhubbub.appspot.com/'/><link rel='next' type='application/atom+xml' href='http://www.blogger.com/feeds/13463691/posts/default?start-index=26&amp;max-results=25'/><author><name>Jeff Shell</name><uri>http://www.blogger.com/profile/08875953026022510741</uri><email>noreply@blogger.com</email></author><generator version='7.00' uri='http://www.blogger.com'>Blogger</generator><openSearch:totalResults>111</openSearch:totalResults><openSearch:startIndex>1</openSearch:startIndex><openSearch:itemsPerPage>25</openSearch:itemsPerPage><entry><id>tag:blogger.com,1999:blog-13463691.post-1871609019212871398</id><published>2008-09-03T07:27:00.004-06:00</published><updated>2008-09-03T07:35:37.579-06:00</updated><title type='text'>New Blogging Pastures</title><content type='html'>&lt;p&gt;With a fair amount of success, I've pulled in the entries from the old &lt;em&gt;Griddle Noise&lt;/em&gt; into a Squarespace account. I've long been dissatisfied with Blogger... It was good enough for a free service, I guess, but I just couldn't take it any more. It was hard to use Markdown, and it was hard to use its "wysiwyg" editor on Safari. Results were unpredictable. So I'm giving &lt;a href="http://www.squarespace.com/"&gt;Squarespace&lt;/a&gt; a try.&lt;/p&gt;
&lt;p&gt;It's really quite a nice service, and it will definitely do for now. The big issue is to either:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Make time to write&lt;/li&gt;
&lt;li&gt;Write smaller&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;
So head over to &lt;a href="http://eucci.squarespace.com/griddle-noise/"&gt;eucci.squarespace.com/griddle-noise&lt;/a&gt;. Gods and time willing, I'll get around to knocking out my tech thoughts again on topics such as:
&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Python&lt;/li&gt;
&lt;li&gt;Zope 3 Component Architecture&lt;/li&gt;
&lt;li&gt;Buildout and the realization of the component dream (almost)&lt;/li&gt;
&lt;li&gt;Git&lt;/li&gt;
&lt;li&gt;Object publishing&lt;/li&gt;
&lt;li&gt;etc...&lt;/li&gt;
&lt;/ul&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/13463691-1871609019212871398?l=griddlenoise.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/13463691/posts/default/1871609019212871398'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/13463691/posts/default/1871609019212871398'/><link rel='alternate' type='text/html' href='http://griddlenoise.blogspot.com/2008/09/new-blogging-pastures.html' title='New Blogging Pastures'/><author><name>Jeff Shell</name><uri>http://www.blogger.com/profile/08875953026022510741</uri><email>noreply@blogger.com</email><gd:extendedProperty xmlns:gd='http://schemas.google.com/g/2005' name='OpenSocialUserId' value='03384692759758802531'/></author></entry><entry><id>tag:blogger.com,1999:blog-13463691.post-7240753574623946703</id><published>2008-07-25T19:26:00.002-06:00</published><updated>2008-07-25T19:40:12.116-06:00</updated><title type='text'>Remembering Pausch</title><content type='html'>&lt;p&gt;
There are three things that I remember about IPC 8 (International Python Conference 8), besides it being the only Python conference which I've had the luxury of attending.
&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Riding from Fredericksburg to somewhere outside of DC in a major Virginia snowstorm, only the first or second such snowstorm I had seen since moving to the area in late 1997.&lt;/li&gt;
&lt;li&gt;Meeting &lt;em&gt;Tres Seaver&lt;/em&gt;.&lt;/li&gt;
&lt;li&gt;The final keynote, masterfully given by &lt;strong&gt;Randy Pausch&lt;/strong&gt;.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;
Pausch, who passed away earlier today (July 25, 2008),  was charismatic, smart, and opinionated, and his keynote was funny and engaging. I must admit that I forgot Randy's name, but I'll also gladly admit that many of the points he made have remained with me and I still think of them often. There are even a couple of anecdotes which I repeat to others. Not many people can give such memorable speeches and presentations. Thanks, Randy. I'm glad to have met and heard him in person once, and wish I had been able to do so again to thank him for some great insights and inspirations.
&lt;/p&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/13463691-7240753574623946703?l=griddlenoise.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/13463691/posts/default/7240753574623946703'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/13463691/posts/default/7240753574623946703'/><link rel='alternate' type='text/html' href='http://griddlenoise.blogspot.com/2008/07/remembering-pausch.html' title='Remembering Pausch'/><author><name>Jeff Shell</name><uri>http://www.blogger.com/profile/08875953026022510741</uri><email>noreply@blogger.com</email><gd:extendedProperty xmlns:gd='http://schemas.google.com/g/2005' name='OpenSocialUserId' value='03384692759758802531'/></author></entry><entry><id>tag:blogger.com,1999:blog-13463691.post-8697119096017739855</id><published>2008-07-16T12:35:00.000-06:00</published><updated>2008-07-16T13:07:23.406-06:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='mac'/><category scheme='http://www.blogger.com/atom/ns#' term='iphone'/><category scheme='http://www.blogger.com/atom/ns#' term='omnifocus'/><category scheme='http://www.blogger.com/atom/ns#' term='gtd'/><title type='text'>OmniFocus Revisited</title><content type='html'>&lt;p&gt;
  I've been using &lt;a href="http://www.omnigroup.com/applications/omnifocus/" title="The Omni Group - OmniFocus"&gt;OmniFocus&lt;/a&gt; for a while now on my Mac, and made occassional
  use of it's predecessor, &lt;a href="http://kinkless.com/kgtd" title="kgtd | Kinkless"&gt;Kinkless GTD&lt;/a&gt;. As an implementation of the
  &lt;a href="http://www.davidco.com/what_is_gtd.php" title="What is GTD ?"&gt;"Getting Things Done"&lt;/a&gt;
  method, or just as a personal "what am I doing?"
  manager, OmniFocus 1.0 was pretty good. I, personally, liked it better than
  the alternatives I tried, but some of that may be due to familiarity with
  the &lt;a href="http://www.omnigroup.com/applications/omnioutliner/" title="The Omni Group - OmniOutliner"&gt;OmniOutliner&lt;/a&gt; heritage.
  And OmniOutliner remains one of the greatest Mac OS X applications ever written.
  I believe it's one of the greatest outliners ever written. Sure, it doesn't have Mind Mapping support and it
  can't run a slideshow (although its data can be exported to OmniGraffle or Keynote).
  OmniOutliner is a joy because it's fast, beautiful, ridiculously easy to use,
  while still having a fair amount of power and flexibility. Kinkless GTD was
  actually a set of AppleScripts that made OmniOutliner act like a specialized
  GTD application (which OmniFocus now does natively).
&lt;/p&gt;
&lt;p&gt;
  But when it came to OmniFocus, I only used it at work, and even there I only used it intermittently. 
  But with the 1.1 "Sneaky-Peek" version of the desktop client (still under development), OmniFocus
  supports synchronization via &lt;a href="http://www.apple.com/mobileme/" title="Apple - MobileMe"&gt;MobileMe&lt;/a&gt; or any WebDAV server. This not only
  enables me to share this information between the office, home, and the
  rarely used laptop, but it enables sharing with the awesome new 
  &lt;a href="http://www.omnigroup.com/applications/omnifocus/iphone/" title="The Omni Group - OmniFocus for iPhone and iPod touch"&gt;OmniFocus for iPhone&lt;/a&gt;.
&lt;/p&gt;
&lt;p&gt;
  Second only to the iTunes Remote, OmniFocus for iPhone is the coolest mobile
  application I've seen so far on this young platform. OmniFocus for iPhone
  (or iPod Touch) can synchronize over Wi-Fi, Edge, or 3G. That alone makes it
  very useful. Cooler still is that it's location aware. "GTD" has a strong
  concept of contexts. A project may require picking up supplies at an office
  supply store, assembling at home, and mailing out items at the post office.
  With OmniFocus, you can add location information to any context. This
  location information may be based on where you currently stand (using
  Location Services), on a manually entered address, on an address from a
  Contact record, or on a business search. Then when looking at the "By
  Location" screen in OmniFocus, available actions get grouped by their
  location in relation to where you currently stand. "Grocery Store: 1 Mile;
  Post Office: 3 Miles..." &lt;strong&gt;Very Cool&lt;/strong&gt;.
&lt;/p&gt;
&lt;p&gt;
  This is the first electronic implementation of GTD that actually appears
  usable. Even if you don't follow GTD religiously (I certainly don't), the
  projects/contexts combination is an effective way of organizing actions.
  The location-aware contexts in OmniFocus for iPhone help answer the 
  question "what can I do based on where I am?" When used well, it should make
  it harder to forget those little items that you needed to do or pick up
  for some small project.
&lt;/p&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/13463691-8697119096017739855?l=griddlenoise.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/13463691/posts/default/8697119096017739855'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/13463691/posts/default/8697119096017739855'/><link rel='alternate' type='text/html' href='http://griddlenoise.blogspot.com/2008/07/omnifocus-revisited.html' title='OmniFocus Revisited'/><author><name>Jeff Shell</name><uri>http://www.blogger.com/profile/08875953026022510741</uri><email>noreply@blogger.com</email><gd:extendedProperty xmlns:gd='http://schemas.google.com/g/2005' name='OpenSocialUserId' value='03384692759758802531'/></author></entry><entry><id>tag:blogger.com,1999:blog-13463691.post-2530876269572653946</id><published>2008-07-12T00:27:00.003-06:00</published><updated>2008-07-12T00:40:40.477-06:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='mac'/><category scheme='http://www.blogger.com/atom/ns#' term='iphone'/><category scheme='http://www.blogger.com/atom/ns#' term='apple'/><title type='text'>iPhone 2.0 and the iTunes Remote</title><content type='html'>&lt;p&gt;Like many others, I was bit &lt;strong&gt;hard&lt;/strong&gt; by the server failure that crippled the big iPhone 2.0 update process this morning. It robbed me of said morning, and I opted to take the day off work. It's been a bit of a tough week, and last night I did my first show in months, and had company over until past 3AM afterwards. Since things are about to get crazy at work, I decided that I needed a day to catch back up on sleep while waiting for my phone to work again.&lt;/p&gt;
&lt;p&gt;A few hours later, the phone worked.&lt;/p&gt;
&lt;p&gt;One of the most surprising and enjoyable elements is the iTunes Remote. Full and comprehensive access to my fairly large iTunes library on the iMac: all playlists, etc, with the ability to control volume, jump around in songs, see artwork - just like the 'iPod' iPhone application! Sometimes, particularly in the morning, I might turn on Front Row and carry the nice little Apple Remote around with me to have some control over songs while getting dressed in the upstairs loft, but using the remote from up there often required reaching far over the edges and trying to point the remote in the direction of the iMac, just to be able to skip forward a track or two.&lt;/p&gt;
&lt;p&gt;But now, I can control it all from the iPhone, without needing a line of sight! In fact, this might be what pushes me to pick up an &lt;em&gt;Airport Express&lt;/em&gt; or two (one for speakers in said upstairs loft, maybe one to bring music out on the patio or the bathroom). Full access and control of 29 and a half days of available music playable out of real speakers and controlled by an untethered iPod size device - beautiful.&lt;/p&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/13463691-2530876269572653946?l=griddlenoise.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/13463691/posts/default/2530876269572653946'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/13463691/posts/default/2530876269572653946'/><link rel='alternate' type='text/html' href='http://griddlenoise.blogspot.com/2008/07/iphone-20-and-itunes-remote.html' title='iPhone 2.0 and the iTunes Remote'/><author><name>Jeff Shell</name><uri>http://www.blogger.com/profile/08875953026022510741</uri><email>noreply@blogger.com</email><gd:extendedProperty xmlns:gd='http://schemas.google.com/g/2005' name='OpenSocialUserId' value='03384692759758802531'/></author></entry><entry><id>tag:blogger.com,1999:blog-13463691.post-2608284779460250005</id><published>2008-06-10T14:34:00.001-06:00</published><updated>2008-06-10T14:35:19.772-06:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='development'/><category scheme='http://www.blogger.com/atom/ns#' term='design'/><category scheme='http://www.blogger.com/atom/ns#' term='mac'/><category scheme='http://www.blogger.com/atom/ns#' term='iphone'/><category scheme='http://www.blogger.com/atom/ns#' term='apple'/><title type='text'>Looking to a Snow Leopard Winter.. er... Summer.</title><content type='html'>&lt;p&gt;I&amp;#8217;m a bit excited about Mac OS X &amp;#8220;Snow Leopard&amp;#8221;. Few user-visible changes, with a focus on fine-tuning and giving developers better access to capabilities of modern hardware. It appears that Apple&amp;#8217;s experience in making a lightweight Mac OS X &amp;#8220;Core OS&amp;#8221; for the iPhone will also drive this release.&lt;/p&gt;

&lt;p&gt;One of my favorite operating system releases was OS/2 &amp;#8220;Warp&amp;#8221; (OS/2 3.0). OS/2 2.0 was a fascinating creature - completely divorced from Microsoft, OS/2 2.0 delivered an aggressively object-oriented runtime built on SOM (a desktop implementation of some of CORBA 1.x, I believe). It was radically different from Window 3.x. It&amp;#8217;s hardware requirements were a bit high for the times, but it was a solid OS.&lt;/p&gt;

&lt;p&gt;What impressed me about OS/2 3.0 &amp;#8220;Warp&amp;#8221; was that it&amp;#8217;s system requirements were in some cases significantly LESS than OS/2 2.0, while performing better. I don&amp;#8217;t know of any majoro user-visible adjustments (this was before operating system releases became the giant dog&amp;#8217;n&amp;#8217;pony shows that have been expected since both Windows 95 and Mac OS X).&lt;/p&gt;

&lt;p&gt;I think that even though desktop and laptop hardware continue to get better, the rapid growth rates seen between 1995 and 2005 are slowing down. Now the pressure is on connectivity, portability, and storage storage storage for all of those mp3s and movies and photos. I think both Windows XP and Vista, along with Mac OS X 10.4 and particularly 10.5 have been a bit cavalier about their usage / expectation of resource availability without doing a good job of cleaning up afterwards. Removing a &amp;#8216;TemporaryFiles&amp;#8217; folder used by Apple&amp;#8217;s &amp;#8220;Soundtrack Pro&amp;#8221; program gave me back 25 GB of disk space. 25GB! I expect that when doing lossless audio work, I&amp;#8217;m going to leave a lot of turds behind. But not that many. That&amp;#8217;s an accumulation over only a few months. Now some of that may have been due to crashes brought on by the instability in Mac OS X 10.5.2&amp;#8217;s audio subsystem (particularly in relation to some USB audio devices). But still - 25 gig! Over the course of just a couple of months!&lt;/p&gt;

&lt;p&gt;I think that Apple is at a good place to do this. Good housekeeping is required - otherwise you end up with situations like Mac OS &amp;#8216;Classic&amp;#8217; or even Windows Vista, where there is so much old baggage, bad hacks, outdated mentalities, etc, all in play; it makes it difficult to move the platform forward. Some companies and developers have always been mindful of this, electing to keep their products lean and fast, always (see Ableton Live - hands down, the most impressive audio application out there). Other companies don&amp;#8217;t support that philosophy for whatever reason - backwards compatibility, rush to market, a combination of the two, etc.&lt;/p&gt;

&lt;p&gt;This far into the Mac OS X life cycle, there&amp;#8217;s not many new dog&amp;#8217;n&amp;#8217;pony features to add. The API&amp;#8217;s have stabalized, the developer tools offer more than they ever have (Interface Builder 3 is a terrific update), the Finder and Spotlight are actually fast and usable; applications and utilities from both inside and outside of Apple are going to really shine on Mac OS X 10.5 with all that it offers to developers. A new age of PDA&amp;#8217;s are upon us, whether it&amp;#8217;s a device like an iPhone, an ultra-mobile Asus Eee-PC style portable, or even the Macbook Air: secondary and tertiary devices are really taking off. &lt;/p&gt;

&lt;p&gt;I think that an underlying aspect part of the &amp;#8216;Snow Leopard&amp;#8217; plan is to allow such devices, made by Apple (naturally), to proliferate. When it was announced that the iPhone was built on Mac OS X, I was surprised - Mac OS X has been a pretty wasteful OS - or at least, one that would consume more resources than realized (often for caching, interestingly enough). A standard install is full of crap that may be useful, but often takes up space. How many gigabytes of printer drivers now? To take the fine tuning and resource management ideas from the iPhone variation of OS X into the main system is what I think will allow for Apple to finally make the Eee PC style portable that everyone wanted the Macbook Air to be.&lt;/p&gt;

&lt;p&gt;I&amp;#8217;m putting my money on some kind of small device, priced around $600-$800, coming out at or around the same time as Snow Leopard. Combined with Mobile Me and Snow Leopard Server&amp;#8217;s increasingly Exchange-like feature set (but better priced and more understandable for small organizations), the ubiquitous-data-access capability is there.&lt;/p&gt;

&lt;p&gt;Today&amp;#8217;s full-featured laptops (MacBooks, Inspirons, whatever) are their own entities; my aging iBook gets used rarely as I just don&amp;#8217;t have as much data or software set up on it, and it&amp;#8217;s sometimes too big of a pain to keep in sync.&lt;/p&gt;

&lt;p&gt;The XO and Eee-PCs (or whatever they&amp;#8217;re called) are also separate from the rest of one&amp;#8217;s life; useful as a fun or educational toy, or as a geek&amp;#8217;s favorite gadget to see what they can get running on such a little device. Most of the other developments I&amp;#8217;ve seen in this area have centered around &amp;#8220;how cheap and how small can we make a laptop/portable that will run (Linux/Windows XP)&amp;#8221;. But outside of education, if this is the only focus being given, then these companies are going to be making nothing more than the next round of casual gadgets that get tossed or buried after a few months - especially if a key factor of what made Palm devices so popular (for a while) is completely neglected.&lt;/p&gt;

&lt;p&gt;The Macbook Air is deliberately designed as a complementary computer, using the master&amp;#8217;s optical drive even. While sexy, I think the Macbook Air misses the mark on a few items. But I think it&amp;#8217;s an indication of things to come - laptops deliberately designed to complement your main machine. Smaller devices, from the Palm to the iPhone, have done this. And they&amp;#8217;ll also be designed to work with your (or your company&amp;#8217;s) data, which the Blackberry has done (and the iPhone will do when its new &amp;#8216;enterprise&amp;#8217; support rolls out). Getting this onto other devices, without being constrained to an enterprisey system like Notes or Outlook, is where things really appear to be headed. It&amp;#8217;s certainly something that I&amp;#8217;d like to have. And the more I look at Snow Leopard, the more I believe that Apple is sneaking ahead of the crowd into delivering this into the hands of consumers. They&amp;#8217;re skating to where the puck is going to be.&lt;/p&gt;

&lt;p&gt;Granted, Windows &amp;#8220;Live Mesh&amp;#8221; looks to be heading in the same direction. But after Vista, Microsoft needs to reign in the Windows kernel and distribution. Windows Server 2008 and some of what has been leaked (or speculated) about &amp;#8220;Windows 7&amp;#8221; seem to indicate that Microsoft is aware of this. And how could they not be? But I think that even with their vast resources, Microsoft has a long ways to go to catch up - even though it appears that they&amp;#8217;ve been playing in this area (tablet computing, ultra-mobile pc&amp;#8217;s) for a while. A deep cleansing of the Windows core is desparately needed. And then a deep re-implementation of the UI may be needed.&lt;/p&gt;

&lt;p&gt;Apple had a terrific luxury (and great idea) with the iPhone. While sharing the same kernel and many same APIs as the desktop (and server) Mac OS X, it has an entirely new UI that is dedicated to its intended use. Windows CE, on the other hand, tried to bring the Windows 95 look and feel to tiny devices and now I&amp;#8217;m really not so sure it was a good idea. It allowed Microsoft to punt on some usability and design issues by falling back on the way things work on the desktop. I still see this, even in some of the newest and fanciest &amp;#8220;iPhone killers&amp;#8221;: some of these have a very fancy launcher app; some even have a very fancy phone and contact app that spins around in 3D and responds to gestures. But then, suddenly, you&amp;#8217;re in the tiny-font, tiny-scrollbar, pixelated, stylus-driven world of the interior. It&amp;#8217;s like going into a grand building like The Plaza (back when it was a hotel, at least), and finding the inside full of grey linoleum floors, flickering flourescent lights, and cinderblock walls reminiscent of an old hospital or elementary school. Quite the let-down (a lot of courthouses are like this, actually).&lt;/p&gt;

&lt;p&gt;I also think Apple was smart to NOT have an SDK at the launch of the iPhone. I bet they would have liked one, but I think the iPhone had to launch when it did, and perhaps not-quite-everything was ready yet. If one looks back at the classic Macintosh and Palm devices and operating systems, you see systems that pulled of very clever hacks to fit within the price and size constraints of the time. The Lisa was much more than a $10,000 Macintosh - it had many features from power management to an OpenDoc style multi-tasking document based UI. But to offer those features, it was priced well out of reach. The Macintosh squeezed as much as it could down into a 128K Ram machine, and the compromises they had to make in order for that to work would end up haunting the company until its near-death. The Palm, too, took the ideas of the Newton and other tablet devices and stripped them down into a size and price point approachable by the masses. And like Apple, the design decisions that were made to make that work have crippled the Palm OS so much that even Palm sells half of its devices with Windows CE (or whatever CE is called these days). Those compromises are bad enough to deal with on your own - but when having to support third party developers and then provide some degree of backwards compatibility, it can just kill you.&lt;/p&gt;

&lt;p&gt;By taking the time to put the SDK into beta, to polish up the OS and its APIs, I think Apple will avoid a repeat of that story. Instead of having to support every little exposed compromise that may have been made to get the iPhones out the door last June, Apple could tidy them up. By using a beta period for the SDK and next major release of the software, Apple can respond to feedback and make changes and adjustments before they become permanent.&lt;/p&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/13463691-2608284779460250005?l=griddlenoise.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/13463691/posts/default/2608284779460250005'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/13463691/posts/default/2608284779460250005'/><link rel='alternate' type='text/html' href='http://griddlenoise.blogspot.com/2008/06/looking-to-snow-leopard-winter-er.html' title='Looking to a Snow Leopard Winter.. er... Summer.'/><author><name>Jeff Shell</name><uri>http://www.blogger.com/profile/08875953026022510741</uri><email>noreply@blogger.com</email><gd:extendedProperty xmlns:gd='http://schemas.google.com/g/2005' name='OpenSocialUserId' value='03384692759758802531'/></author></entry><entry><id>tag:blogger.com,1999:blog-13463691.post-3763099836331524967</id><published>2008-04-29T00:48:00.001-06:00</published><updated>2008-04-29T00:49:59.975-06:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='hafler trio'/><category scheme='http://www.blogger.com/atom/ns#' term='aesthetics'/><category scheme='http://www.blogger.com/atom/ns#' term='audio'/><title type='text'>The Hafler Trio, Dislocation</title><content type='html'>&lt;p&gt;I just received the Korm Plastics re-release of The Hafler Trio&amp;#8217;s &lt;a href="http://brainwashed.com/h3o/Dislocation/re/"&gt;Dislocation&lt;/a&gt;. I&amp;#8217;ve been waiting for this one more than any of the others thus far. The &lt;a href="http://www.brainwashed.com/h3o/korm_plastics.html"&gt;Korm Plastics re-issue series&lt;/a&gt; is a magnificent undertaking wherein a large chunk of Hafler Trio material that has long been unavailable or available only in &amp;#8220;wrong&amp;#8221; versions is being re-issued in definitive form. The packaging for each has been stunning: each release in a booklet sized &amp;#8220;wallet&amp;#8221; form, with full booklets, posters, post-cards, and more. The releases are all wrapped in a vellum (or vellum-like) material with additional writing. The packaging alone is of the highest grade - far higher than what these releases saw in their original forms (even ones that were also in wallet/booklet form).&lt;/p&gt;

&lt;p&gt;I first became interested in The Hafler Trio when the Hafler Trio / Nurse With Wound &lt;a href="http://brainwashed.com/h3o/mfo.html"&gt;collaboration was issued on CD&lt;/a&gt;, which I picked up in &amp;#8230; 1995? 96? I was a big Nurse With Wound fan at the time and, thus, gobbled this one up. I was blown away. While I recognized many Nurse With Wound sounds, the overall production and flow was of a different nature. Similar, yes, in it all being (perhaps) some form of &lt;em&gt;Musique:Concrete&lt;/em&gt;. It just sounded a bit more &amp;#8230; polished? Subtle? In any case, it remains a personal favorite.&lt;/p&gt;

&lt;p&gt;At this time, I was 20-21 years old, poor, bla bla bla. Most of these CDs that I liked were all import and out of my price range (when they could even be found). But one day around this time, I was in a used cassette shop, and came across the original Hafler Trio &lt;a href="http://www.brainwashed.com/h3o/Dislocation/tape.html"&gt;Dislocation cassette&lt;/a&gt;. For $4! It was a Staaltape release, in a bag (my second one - a couple of years earlier I picked up what turned out to be a fairly rare Legendary Pink Dots cassette in the same style of packaging, mostly because I didn&amp;#8217;t yet have a CD player). Not knowing much of The Hafler Trio at the time, I knew that this was something I should get, as it was unlikely that I would easily come across such a find for years to come.&lt;/p&gt;

&lt;p&gt;I liked the tape, but I admit that it took a while to grow on me. It was very quiet and subtle, with a lot of field recordings. It was something that I enjoyed, but I found that I had to give it more attention than similar recordings from other artists. I loved having it on tape, though. It heightened the &amp;#8220;found sound&amp;#8221; feeling. And I loved what was inside the bag (besides the unlabeled cassette). Inside, there was heavy paper with fragments of maps on one side and various clippings on the other. It was far more interesting than some of the cheap shock imagery (or just cheap packaging) used, again, by somewhat similar artists that interested me at that time.&lt;/p&gt;

&lt;p&gt;However, as fascinating as it all was, that would be it for me and The Hafler Trio until 3-4 years later when, after moving to the east coast, I&amp;#8217;d find a copy of &lt;a href="http://www.brainwashed.com/h3o/BagofCats/index.html"&gt;A bag of cats&lt;/a&gt; at &lt;a href="http://printedmatter.org/"&gt;Printed Matter&lt;/a&gt;&amp;#8217;s old Wooster Street location in NYC. After that find, I&amp;#8217;d lap up whatever I could.&lt;/p&gt;

&lt;p&gt;So &lt;a href="http://brainwashed.com/h3o/Dislocation/re/"&gt;Dislocation&lt;/a&gt; has been held in a special place, and I&amp;#8217;d been watching that &lt;a href="http://www.brainwashed.com/h3o/korm_plastics.html"&gt;Korm re-issue series&lt;/a&gt; list tick along, waiting for this one to show up. Now it&amp;#8217;s here. And it&amp;#8217;s much more impressive than imagined. First, the booklet is a new heavy-stock foldout variation of the same maps found within the &lt;a href="http://www.brainwashed.com/h3o/Dislocation/tape.html"&gt;cassette version&lt;/a&gt;. When folded up&amp;#8230; I can&amp;#8217;t even describe it, really. It&amp;#8217;s just beautiful and very different from the booklets that have accompanied the rest of the re-issue series.&lt;/p&gt;

&lt;p&gt;But what&amp;#8217;s really been impressive has been the audio. This time, I have no prior CD to compare; only tape. And I love tape. But now, more than any other re-issue done thus far, I can really see how well done the audio restoration has been. Remarkably well done. This album deserved (and required) it. As much as I loved the &amp;#8220;found sound&amp;#8221; fuzzy feeling I got from the tape, there are a lot of nuances here that I may now appreciate. Goddamn well done.&lt;/p&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/13463691-3763099836331524967?l=griddlenoise.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/13463691/posts/default/3763099836331524967'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/13463691/posts/default/3763099836331524967'/><link rel='alternate' type='text/html' href='http://griddlenoise.blogspot.com/2008/04/i-just-received-korm-plastics-re.html' title='The Hafler Trio, Dislocation'/><author><name>Jeff Shell</name><uri>http://www.blogger.com/profile/08875953026022510741</uri><email>noreply@blogger.com</email><gd:extendedProperty xmlns:gd='http://schemas.google.com/g/2005' name='OpenSocialUserId' value='03384692759758802531'/></author></entry><entry><id>tag:blogger.com,1999:blog-13463691.post-2278235399758343043</id><published>2008-04-07T23:28:00.004-06:00</published><updated>2008-04-08T08:43:08.279-06:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='scm'/><category scheme='http://www.blogger.com/atom/ns#' term='mercurial'/><category scheme='http://www.blogger.com/atom/ns#' term='git'/><category scheme='http://www.blogger.com/atom/ns#' term='dvcs'/><title type='text'>What a DVCS gives me</title><content type='html'>I've seen some posts floating around about what a distributed version control system might give you. For me, these are the key elements:&lt;div&gt;
&lt;/div&gt;&lt;div&gt;
&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span" style="font-weight: bold;"&gt;Committing changes is separate from sharing.&lt;/span&gt; While the phrase "you can edit on a plane!" gets thrown around quite frequently, I think this is the far more important aspect of that vision. As a developer, you don't always know how a particular path of development might impact the code base. With a purely centralized system, you have to think first about where a path may be taking you as it could affect everybody else. Time and time again, I've seen developers work without any revision control safety net for days or weeks at a time because they don't want to "break the build", and they don't have time to look up the policies for branch naming, merging, etc. Not that such a thing should take a long time, but when under pressure, it's the last thing one wants to deal with. And the untracked changes keep getting bigger, and bigger. And when I say "I've seen developers..." here, I include myself.&lt;/div&gt;&lt;div&gt;
&lt;/div&gt;&lt;div&gt;
&lt;/div&gt;&lt;div&gt;With a DVCS, I can commit immediately. I took heavy advantage of this on a recent project where the set of work for which I was responsible was in no state to be set up on other systems. It required new configuration and possibly new tool installations and I didn't have time to help everyone else install and update their sandboxes. They didn't need my code anyways. Instead, I was able to pull in and rebase my work on updates from my co-workers while my personal branch was in development. When my code was mature, it was easy to merge into a more centralized branch. Very easy. In fact, it was just a fast-forward (in Git parlance), since I was rebasing my changes on top of those by my colleagues.&lt;/div&gt;&lt;div&gt;
&lt;/div&gt;&lt;div&gt;
&lt;/div&gt;&lt;div&gt;Again, this is &lt;span class="Apple-style-span" style="font-style: italic;"&gt;possible&lt;/span&gt; with a purely centralized system, but it would have required me to realize the significance of my changes and their impact on others. My sandbox was in a "guts on the table" kind of state. Just about every commit I made was stable, but sharing them would have made it harder on other team members to do their work due to the changes made in tool and configuration dependencies.&lt;/div&gt;&lt;div&gt;
&lt;/div&gt;&lt;div&gt;In essence, &lt;span class="Apple-style-span" style="font-weight: bold;"&gt;a DVCS inverts the control back to individuals&lt;/span&gt;. As a developer, I can commit my changes whenever I want. With a purely centralized system, I have to think more about what I'm about to commit, since it immediately impacts all other developers.&lt;/div&gt;&lt;div&gt;
&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span" style="font-weight: bold;"&gt;A DVCS encourages experimentation&lt;/span&gt;. Being able to commit my changes whenever I want and being able to make local branches so easily makes it easier for me to start playing around with new ideas. Whether that's doing a big refactoring or restructuring of code, experimenting with a new feature of third party library, or working on updating the code to run well on the latest release of Foo, I know that I can experiment and SAVE those experiments in small chunks, without impacting anybody else. I can choose when and how I want to share my results. I can choose to throw my experiment away and not have to be reminded by its grizzly branch name for years to come.&lt;/div&gt;&lt;div&gt;
&lt;/div&gt;&lt;div&gt;
&lt;/div&gt;&lt;div&gt;We have an internal toolkit that bridges SQLAlchemy and Zope 3 and provides various other useful features and integrations. Late last year, I started looking into updating the code to work with SQLAlchemy 0.4 and to also clean up some ancient hacks. We were still using CVS at the time. I can't remember when I made the branch, but I knew at some point that I was heading down a potentially long path and that a branch would be required. Other priorities were coming up and I'd have to leave this work aside for a while.&lt;/div&gt;&lt;div&gt;
&lt;/div&gt;&lt;div&gt;
&lt;/div&gt;&lt;div&gt;Well, there's 2-3 days of feverish work, all held hostage within a single check-in. I've been wanting to pull some features out of that branch and into the current mainline branch, but since it's all in one big check-in, I can't do that easily. This is the second time I've done that (the other time was on a feature branch that lead to a dead end, but along the way I had some good ideas that I'd love to be able to extract now).&lt;/div&gt;&lt;div&gt;
&lt;/div&gt;&lt;div&gt;
&lt;/div&gt;&lt;div&gt;If I'd been using Git, I would have been making more commits, more frequently, and in much smaller sizes. Using Git, I would then be able to quite easily cherry pick individual commits out of that branch and apply them to the mainline. &lt;/div&gt;&lt;div&gt;
&lt;/div&gt;&lt;div&gt;
&lt;/div&gt;&lt;div&gt;Finally, a DVCS makes it easy to vet changes through the system. We don't have to give new employees the keys to the kingdom, particularly when their skill set is focused on a specific area. Instead, the code can go through review channels. They make commits in their local repository, and tell someone (like me) that they've made some changes. Using Git (or any other tool - but Git's named remotes makes this hella easy), I can pull in changes from their repository, verify that they're good, and push them to the canonical repository. I can merge them into other branches, if required.&lt;/div&gt;&lt;div&gt;
&lt;/div&gt;&lt;div&gt;Imagine this in a team situation: team members can share their repositories with each other as needed, giving each other chances to do code reviews and fixes before sharing those changes with the larger group or division; all without requiring permission to touch the central repository. Suddenly whole new workflows open up, based on the "networks of trust" inherent in all of us: a team leader collects commits from their team, and shares those changes with other team leaders. Those team leaders pull together changes from all of their teams (while sharing said changes across team lines) and push those on to a QA / Testing division. The QA / Testing division then puts their seal of approval on things by being the ones who control pushing to the "canonical" repository from which builds are based.&lt;/div&gt;&lt;div&gt;
&lt;/div&gt;&lt;div&gt;
&lt;/div&gt;&lt;div&gt;There's just so much more that can be done with a DVCS, and we're in an age now where there are very usable and useful tools for this job. A DVCS restores individual responsibility, encourages experimentation, enables adaptive workflows, and I believe it fits more naturally into how we humans organize our interactions. Whether this is in a rigidly defined corporate structure or a loosely connected set of worldwide open source contributors, the peer to peer nature combined with getting the whole repository enables people to step up and do bold things without having to go through channels to get any coveted "write access".&lt;/div&gt;&lt;div&gt;
&lt;/div&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/13463691-2278235399758343043?l=griddlenoise.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/13463691/posts/default/2278235399758343043'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/13463691/posts/default/2278235399758343043'/><link rel='alternate' type='text/html' href='http://griddlenoise.blogspot.com/2008/04/what-dvcs-gives-me.html' title='What a DVCS gives me'/><author><name>Jeff Shell</name><uri>http://www.blogger.com/profile/08875953026022510741</uri><email>noreply@blogger.com</email><gd:extendedProperty xmlns:gd='http://schemas.google.com/g/2005' name='OpenSocialUserId' value='03384692759758802531'/></author></entry><entry><id>tag:blogger.com,1999:blog-13463691.post-5529359661027861595</id><published>2008-04-06T10:49:00.000-06:00</published><updated>2008-04-06T10:50:09.978-06:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='hafler trio'/><category scheme='http://www.blogger.com/atom/ns#' term='aesthetics'/><category scheme='http://www.blogger.com/atom/ns#' term='drone'/><category scheme='http://www.blogger.com/atom/ns#' term='audio'/><title type='text'>Sunday Great Openings</title><content type='html'>&lt;p&gt;In my &lt;a href="http://griddlenoise.blogspot.com/2008/03/trilogy-revisited.html"&gt;last post&lt;/a&gt;, I revisited an earlier write-up of a personal experience involving &lt;a href="http://brainwashed.com/h3o/"&gt;The Hafler Trio&lt;/a&gt;’s so-called &lt;a href="http://brainwashed.com/h3o/trilogy/"&gt;Trilogy in Three Parts&lt;/a&gt;. I’ve been on a bit of a binge lately, trying to grab up a lot of Hafler Trio releases that I let slip by over the past few years. Right now, I’ve got two thirds of the &lt;a href="http://classicaldrone.blogspot.com/2007/07/drone-classics-exactly.html"&gt;Exactly&lt;/a&gt; series of long-form dual disc releases revolving around the voice of Jónsi Birgisson (Sigur Ros), with one of those releases being in the form of the deluxe packaging from &lt;a href="http://simplysuperior.org/"&gt;Simply Superior&lt;/a&gt;. I’ve been starting to pick up vinyl releases as well and will soon have all three evidences according to &lt;a href="http://www.brainwashed.com/h3o/wsc/index.html"&gt;Wolf Sheep Cabbage&lt;/a&gt;, among others. I even managed to find a well priced vinyl copy of what has become one of my all time favorite albums: &lt;a href="http://www.brainwashed.com/h3o/fish.html"&gt;A Thirsty Fish&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;But on this here Sunday morning, I find myself ill at ease. Shoulders are tense, bones are cracking, mind is dazed yet burning. To try to find a spot of calm, I first went through what I have so far of the &lt;a href="http://classicaldrone.blogspot.com/2007/07/drone-classics-exactly.html"&gt;Exactly&lt;/a&gt; set, but it wasn’t helping today. So I returned, again, to this initial &lt;a href="http://brainwashed.com/h3o/trilogy/"&gt;trilogy&lt;/a&gt;. I haven’t listened to it much since my &lt;a href="http://euc.cx/toulouse/archives/2004/04/06/trilogy_tuesday.html"&gt;grand encounter&lt;/a&gt; four years ago. That was just a little too powerful. But up until that point, I got a fair amount of comfort out of the series. It’s still a remarkably powerful. The trick is not to get too lost in it when not wanting great and terrible visions. All I need right now is a warm, sustained, and calming presence. These can do that job rather well - enough to get me through the morning and into a much needed hot shower followed by a cold walk with the dog and some lukewarm coffee.&lt;/p&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/13463691-5529359661027861595?l=griddlenoise.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/13463691/posts/default/5529359661027861595'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/13463691/posts/default/5529359661027861595'/><link rel='alternate' type='text/html' href='http://griddlenoise.blogspot.com/2008/04/sunday-great-openings.html' title='Sunday Great Openings'/><author><name>Jeff Shell</name><uri>http://www.blogger.com/profile/08875953026022510741</uri><email>noreply@blogger.com</email><gd:extendedProperty xmlns:gd='http://schemas.google.com/g/2005' name='OpenSocialUserId' value='03384692759758802531'/></author></entry><entry><id>tag:blogger.com,1999:blog-13463691.post-5341767976041398</id><published>2008-03-24T07:57:00.004-06:00</published><updated>2008-03-24T14:35:26.586-06:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='aesthetics'/><category scheme='http://www.blogger.com/atom/ns#' term='audio'/><category scheme='http://www.blogger.com/atom/ns#' term='nostalgia'/><title type='text'>A Trilogy Revisited</title><content type='html'>&lt;p&gt;I was killing late night minutes by reading through &lt;em&gt;&lt;a href="http://brainwashed.com/h3o/e-void/explain.html#no_twain"&gt;pouring empty into the void&lt;/a&gt;&lt;/em&gt; - a collection of reviews of &lt;a href="http://brainwashed.com/h3o/"&gt;Hafler Trio&lt;/a&gt; material - when I came across a review of the entire &lt;a href="http://brainwashed.com/h3o/trilogy/"&gt;trilogy in three parts&lt;/a&gt;. The writing was more personal than many of the other reviews, which were written for larger audiences (magazines, record shops, etc). And then I got to the final paragraph:
&lt;/p&gt;
&lt;blockquote&gt;Deep into &lt;em&gt;No More Twain, Of One Flesh: 11 Unequivocal Obsecrations&lt;/em&gt;, I was deep into trance and ripped apart by my own twain — two entities guiding and dividing my life right now — and had to fight my way out of such deep and frightening consciousness and back into the body. Scratches and cold medal were put to use to reinvigorate the breath and to bring myself down out of the super present to the merely present.&lt;/blockquote&gt;

&lt;p&gt;"Wow," I thought, "this guy had an experience similar to mine!"&lt;/p&gt;

&lt;p&gt;And then I clicked on the source link - &lt;a href="http://euc.cx/toulouse/archives/2004/04/06/trilogy_tuesday.html"&gt;and it was, in fact, my own&lt;/a&gt;. April 6, 2004. What a wonderful, horrible spring.&lt;/p&gt;

&lt;p&gt;And what the fuck has happened to my brain when I look back at &lt;a href="http://euc.cx/toulouse/archives/2004/03/11/luxury_spring_rising.html"&gt;many of the things produced / released at that time&lt;/a&gt; and wonder how the hell I could do that (and find time to write about it in fairly eloquent terms). Now I have a hard time making a single, simple, goddamn web page for a simple four track online album. How anyone's ever going to hear &lt;em&gt;Like the city, we're bound to last&lt;/em&gt; is beyond me at this point.&lt;/p&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/13463691-5341767976041398?l=griddlenoise.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/13463691/posts/default/5341767976041398'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/13463691/posts/default/5341767976041398'/><link rel='alternate' type='text/html' href='http://griddlenoise.blogspot.com/2008/03/trilogy-revisited.html' title='A Trilogy Revisited'/><author><name>Jeff Shell</name><uri>http://www.blogger.com/profile/08875953026022510741</uri><email>noreply@blogger.com</email><gd:extendedProperty xmlns:gd='http://schemas.google.com/g/2005' name='OpenSocialUserId' value='03384692759758802531'/></author></entry><entry><id>tag:blogger.com,1999:blog-13463691.post-3605297034738671400</id><published>2008-02-24T12:47:00.002-07:00</published><updated>2008-02-24T12:51:33.993-07:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='rage'/><category scheme='http://www.blogger.com/atom/ns#' term='vitriol'/><category scheme='http://www.blogger.com/atom/ns#' term='politics'/><title type='text'>Quit blaming Nader</title><content type='html'>&lt;p&gt;A friend of mine says, &amp;#8220;&lt;a href="http://blog.amber.org/2008/02/24/ralph-nader-is-an-idiot/"&gt;Ralph Nader is an idiot&lt;/a&gt;&amp;#8221;, just because Nader is running for president again.&lt;/p&gt;

&lt;p&gt;I fucking HATE this line of thinking. Nothing pissed me off more than when watching the documentary on Nader recently and seeing how everyone fucking turned on him in 2004 after championing him in 2000. At least Nader has principals and stands by them. Nearly every &amp;#8216;liberal&amp;#8217; voice that I had respected proved to me that they had no fucking principals.&lt;/p&gt;

&lt;p&gt;Michael Moore in 2000 at a Nader rally: &amp;#8220;If you&amp;#8217;re voting for the lesser of two evils, you&amp;#8217;re still voting for evil!&amp;#8221; Four years later, Moore was on the anti-Nader bandwagon.&lt;/p&gt;

&lt;p&gt;If we believe in democracy and having choices and voices, then anyone should be able to run for president. 2000 was not Nader&amp;#8217;s fault. Gore, and the democrats in general, should have run a better campaign. Just like when teams complained about the Patriots running up the score on them: it&amp;#8217;s not the Patriots job to take Tom Brady off the field and stop scoring. It&amp;#8217;s YOUR defense&amp;#8217;s job to get on the field and stop them (the Giants did it; Philly and Baltimore nearly did it). The democrats should have run better campaigns in 2000 and 2004. They could have stopped Nader from running in 2004 if they had picked some of his causes (just some simple ones) and championed them. But the democrats didn&amp;#8217;t.&lt;/p&gt;

&lt;p&gt;Honestly - whenever I hear this vitriol against Nader, a man who has championed consumer rights far more than anyone currently running or serving this country, it sounds like people wanting a fucking dictatorship. It&amp;#8217;s like the movie &amp;#8216;moon over paramour&amp;#8217; (or something like that) where there are two posters for the same dictator - red and blue. One guy asks the other who he&amp;#8217;s going to vote for, &amp;#8220;red or blue&amp;#8221;. The other guy says, &amp;#8220;it doesn&amp;#8217;t matter, it&amp;#8217;s a free dictatorship.&amp;#8221;&lt;/p&gt;

&lt;p&gt;I have the right to vote for whomever I want. And on principal, I will cast my vote for whomever I feel best represents what I want out of a leader. I&amp;#8217;m not going to vote for someone just because they where an elephant or donkey lapel pin. I don&amp;#8217;t care if my one single vote hands the election over to another eight years of Bush tyranny.&lt;/p&gt;

&lt;p&gt;The two party system sucks big time fucking hairy nutsacks. I think South Park represented it best with the &amp;#8220;Giant Douche versus Turd Sandwich&amp;#8221; vote for school mascot (one of the greatest, and saddest, South Park episodes).&lt;/p&gt;

&lt;p&gt;What sucks even more than the two party system is the electoral college being based on representative seats plus senate seats. This causes a vote in Wyoming to count four times as much as a vote in california. Now that&amp;#8217;s not fucking fair at all.&lt;/p&gt;

&lt;p&gt;The problem isn&amp;#8217;t Nader. The whole system is flawed and corrupt and I feel like the anti-Nader rhetoric comes from people who would like to see it stay that way as long as they think they can rig the system to swing to their guy who may be the lesser of two evils.&lt;/p&gt;

&lt;p&gt;It&amp;#8217;s still evil.&lt;/p&gt;

&lt;p&gt;And honestly - seeing the response of so many people against Nader in that film made me absolutely sick with the democratic party and the people who claim to champion its causes. They do not believe in freedom or standing for principals. They&amp;#8217;re the selfish, self-absorbed, narcissistic pricks. &amp;#8220;Oh, look at me, I write for the nation.&amp;#8221; Bit whoop. Nader actually fucking fought hard for things like seatbelts in cars. Big auto wouldn&amp;#8217;t do it. They resisted like hell. We all take this for granted now. But it took someone with actual balls to stand up and fight for something so seemingly trivial (now) but which has been a big deal when it comes to saving lives. What has Eric Alterman done for us lately?&lt;/p&gt;

&lt;p&gt;The general democratic response to Nader shows that most of these people have no spine, no guts, and they don&amp;#8217;t deserve any glory. They certainly don&amp;#8217;t deserve my support.&lt;/p&gt;

&lt;p&gt;Blaming Nader is a sign of weakness, and a sign that the general democratic party and pundits can't own up to their own fucking mistakes. If they can't do that, they can't lead.&lt;/p&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/13463691-3605297034738671400?l=griddlenoise.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/13463691/posts/default/3605297034738671400'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/13463691/posts/default/3605297034738671400'/><link rel='alternate' type='text/html' href='http://griddlenoise.blogspot.com/2008/02/quit-blaming-nader.html' title='Quit blaming Nader'/><author><name>Jeff Shell</name><uri>http://www.blogger.com/profile/08875953026022510741</uri><email>noreply@blogger.com</email><gd:extendedProperty xmlns:gd='http://schemas.google.com/g/2005' name='OpenSocialUserId' value='03384692759758802531'/></author></entry><entry><id>tag:blogger.com,1999:blog-13463691.post-1984955612308634460</id><published>2007-12-02T22:58:00.000-07:00</published><updated>2007-12-02T23:04:02.968-07:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='scm'/><category scheme='http://www.blogger.com/atom/ns#' term='mercurial'/><category scheme='http://www.blogger.com/atom/ns#' term='tools'/><category scheme='http://www.blogger.com/atom/ns#' term='development'/><category scheme='http://www.blogger.com/atom/ns#' term='git'/><category scheme='http://www.blogger.com/atom/ns#' term='subversion'/><category scheme='http://www.blogger.com/atom/ns#' term='distributed vcs'/><category scheme='http://www.blogger.com/atom/ns#' term='cvs'/><category scheme='http://www.blogger.com/atom/ns#' term='svn'/><title type='text'>Distributed VCS's are the Great Enablers (or: don't fear the repo)</title><content type='html'>&lt;p&gt;The more I play with the new breed of VCS tools, the more I appreciate them. The older generations (CVS, SVN) look increasingly archaic, supporting a computing and development model that seems unsustainable. Yet most of us lived with those tools, or something similar, for most of our development-focused lives.&lt;/p&gt;

&lt;p&gt;When I speak of the new breed, the two standouts (to me) are &lt;a href="http://git.or.cz/"&gt;Git&lt;/a&gt; and &lt;a href="http://www.selenic.com/mercurial/"&gt;Mercurial&lt;/a&gt;. There are some other interesting ones, particularly &lt;a href="http://darcs.net/"&gt;Darcs&lt;/a&gt;, but Git and Mercurial seem to have the most steam and seem fairly grounded and stable. Between those two, I still find myself preferring Git. I&amp;#8217;ve had some nasty webs to untangle and Git has provided me with the best resources to untangle them.&lt;/p&gt;

&lt;p&gt;Those webs are actually all related to CVS and some messed up trunks and branches. Some of the code lives on in CVS, but thanks to Git, sorting out the mess and/or bringing in a huge amount of new work (done outside of version control because no one likes branching in CVS and is afraid of &amp;#8216;breaking the build&amp;#8217;) was far less traumatic than usual.&lt;/p&gt;

&lt;p&gt;One of those messes could have been avoided had we been using Git as a company (which is planned). One of the great things these tools provide is the ability to easily do speculative development. Branching and merging is so easy. And most of those branches are private. One big problem we have with CVS is what to name a branch: how to make the name unique, informative, and communicative to others. And then we have to tag its beginnings, its breaking off points, its merge points, etc, just in case something goes wrong (or even right, in the case of multiple merges). All of those tags end up in the big cloud: long, stuffy, confusing names that outlive their usefulness. It&amp;#8217;s one thing to deal with all of this for an important branch that everyone agrees is important. It&amp;#8217;s another to go through all of this just for a couple of days or weeks of personal work. So no one does it. And big chunks of work are just done dangerously - nothing checked in for days at a time. And what if that big chunk of work turned out to be a failed experiment? Maybe there are a couple of good ideas in that work, and it might be worth referring to later, so maybe now one makes a branch and does a single gigantic check-in, just so that there&amp;#8217;s a record somewhere. But now, one can&amp;#8217;t easily untangle a couple of good ideas from the majority of failed-experiment code. &amp;#8220;Oh!&amp;#8221; they&amp;#8217;ll say in the future, &amp;#8220;I had that problem solved! It&amp;#8217;s just all tangled up in the soft-link-experimental-branch in one big check in and I didn&amp;#8217;t have the time to sort it out!&amp;#8221;&lt;/p&gt;

&lt;p&gt;I speak from personal experience on that last one. I&amp;#8217;m still kicking myself over that scenario. The whole problem turned out to be bigger than expected, and now there&amp;#8217;s just a big blob of crap, sitting in the CVS repository somewhere.&lt;/p&gt;

&lt;p&gt;With a distributed VCS, I could have branched the moment that it looked like the problem was getting to be bigger than expected. Then I could keep committing in small chunks to my personal branch until I realized the experiment failed. With smaller check-ins, navigating the history to cherry-pick the couple of good usable ideas out would have been much easier, even if everything else was dicarded. I wouldn&amp;#8217;t have to worry about &amp;#8216;breaking the build&amp;#8217; or worry about a good name for my branch since everyone else would end up seeing it. I could manage it all myself.&lt;/p&gt;

&lt;p&gt;This is the speculative development benefit that alone makes these tools great. It&amp;#8217;s so easy to branch, MERGE, rebase, etc. And it can all be done without impacting anyone else.&lt;/p&gt;

&lt;p&gt;One thing that I often hear when I start advocating distributed VCS&amp;#8217;s is &amp;#8220;well, I like having a central repository that I can always get to&amp;#8221; or &amp;#8220;is always backed up&amp;#8221; or &amp;#8220;is the known master copy.&amp;#8221; There&amp;#8217;s nothing inherant in distributed VCS&amp;#8217;s that prevents you from having that. You can totally have a model similar to SVN/CVS in regards to a central repository with a mixture of read-only and read/write access. But unlike CVS (or SVN), what you publish out of that repository is basically the same thing that you have in a local clone. No repository is more special than any other, but that policy makes it so. You can say &amp;#8220;all of our company&amp;#8217;s main code is on server X under path /pub/scm/&amp;#8230;&amp;#8221;. &lt;/p&gt;

&lt;p&gt;And unlike CVS (or SVN), really wild development can be done totally away from that central collection. A small team can share repositories amongst themselves, and then one person can push the changes in to the central place. Or the team may publish their repository at a new location for someone else to review and integrate. Since they all stem from the same source, comparisons and merges should all still work, even though the repositories are separate.&lt;/p&gt;

&lt;p&gt;Imagine this in a company that has hired a new developer. Perhaps during their first three months (a typical probationary period), they do not get write access to the core repositories. With a distributed VCS, they can clone the project(s) on which they&amp;#8217;re assigned, do their work, and then publish their results by telling their supervisor &amp;#8220;hey, look at my changes, you can read them here &amp;#8230;&amp;#8221; where here may be an HTTP or just a file system path. Their supervisor can then conduct code reviews on the new guys work and make suggestions or push in changes of his own. When the new developers code is approved, the supervisor or some other higher developer is repsonsible for doing the merge. It&amp;#8217;s all still tracked, all under version control, but the source is protected from any new-guy mistakes, and the new-guy doesn&amp;#8217;t have to feel pressure about committing changes to a large code-base which he doesn&amp;#8217;t yet fully grasp.&lt;/p&gt;

&lt;p&gt;But perhaps the most killer feature of these tools is how easy it is to put &lt;em&gt;anything&lt;/em&gt; under revision management. I sometimes have scripts that I start writing to do a small job, typically some kind of data transformation. Sometimes those scripts get changed a lot over the course of some small project, which is typically OK: they&amp;#8217;re only going to be used once, right?&lt;/p&gt;

&lt;p&gt;This past week, I found myself having to track down one such set of scripts again because some files had gotten overridden with new files based on WAY old formats of the data. Basically I needed to find my old transformations and run them again. Fortunately, I still had the scripts. But they didn&amp;#8217;t work 100%, and as I looked at the code I remembered one small difference that 5% of the old old files had. Well, I didn&amp;#8217;t remember the difference, I just remembered that they had a minor difference and I had adjusted the script appropriately to finish up that final small set of files. But now, I didn&amp;#8217;t have the script that worked against the other 95%.  When I did the work initially, it was done in such a time that I was probably using my editors UNDO/REDO buffer to move between differences if needed.&lt;/p&gt;

&lt;p&gt;Now if I had just gone in to the directory with the scripts and done a &lt;code&gt;git init; git add .; git commit&lt;/code&gt; sequence, I would probably have the minor differences right there. But I didn&amp;#8217;t know such tools were available at the time. So now I had to rewrite things. This time, I put the scripts and data files under git&amp;#8217;s control so that I had easy reference to the before and after stages of the data files, just in case this scenario ever happened again.&lt;/p&gt;

&lt;p&gt;I didn&amp;#8217;t have to think of a good place to put these things in our CVS repo. I just made the repository for myself and worried about where to put it for future access later. With CVS/SVN, you have to think about this up front. And when it&amp;#8217;s just a personal little project or a personal couple of scripts, it hardly seems worth it, even if you may want some kind of history.&lt;/p&gt;

&lt;p&gt;Actually, that is the killer feature! By making everything local, you can just do it: make a repository, make a branch, make a radical change, take a chance! If it&amp;#8217;s worth sharing, you can think about how to do that when the time is right. With the forced-central/always-on repository structure of CVS and SVN, you have to think about those things ahead of time: where to import this code, what should I name this branch so it doesn&amp;#8217;t interfere with others, how can I save this very experimental work safely so I can come back to it later without impacting others, is this work big enough to merit the headaches of maintaining a branch, can I commit this change and not break the build&amp;#8230;.?&lt;/p&gt;

&lt;p&gt;As such, those systems punish speculation. I notice this behavior in myself and in my colleages: it&amp;#8217;s preferred to just work for two weeks on something critical with no backup solution, no ability to share, no ability to backtrack, etc, than it is do deal with CVS. I once lost three days worth of work due to working like this - and it was on a project that no one else was working on or depending on! I was just doing a lot of work simultaneously and never felt comfortable committing it to CVS. And then one day, I accidentally wiped out a parent directory and lost everything.&lt;/p&gt;

&lt;p&gt;Now, in a distributed VCS, I could have been committing and committing and could have lost everything anyways since the local repository is contained there: but I could have made my own &amp;#8220;central&amp;#8221; repository on my development machine or on the network to which I could push from time to time. I would have lost a lot less.&lt;/p&gt;

&lt;p&gt;There are so many good reasons to try one of these new tools out. But I think the most important one comes down to this: just get it out of your head. Just commit the changes. Just start a local repository. Don&amp;#8217;t create undue stress and open loops in your head about what, where, or when to import or commit something. Don&amp;#8217;t start making copies of &amp;#8216;index.html&amp;#8217; as &amp;#8216;index1.html&amp;#8217;, &amp;#8216;index2.html&amp;#8217;, index1-older.html&amp;#8217; &amp;#8216;old/index.html&amp;#8217;, &amp;#8216;older/index.html&amp;#8217; and hope that you&amp;#8217;ll remember their relationships to each other in the future. Just do your work, commit the changes, get that stress out of your head. Share the changes when you&amp;#8217;re ready.&lt;/p&gt;

&lt;p&gt;It&amp;#8217;s a much better way of working, even if it&amp;#8217;s only for yourself. &lt;/p&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/13463691-1984955612308634460?l=griddlenoise.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/13463691/posts/default/1984955612308634460'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/13463691/posts/default/1984955612308634460'/><link rel='alternate' type='text/html' href='http://griddlenoise.blogspot.com/2007/12/distributed-vcss-are-great-enablers-or.html' title='Distributed VCS&apos;s are the Great Enablers (or: don&apos;t fear the repo)'/><author><name>Jeff Shell</name><uri>http://www.blogger.com/profile/08875953026022510741</uri><email>noreply@blogger.com</email><gd:extendedProperty xmlns:gd='http://schemas.google.com/g/2005' name='OpenSocialUserId' value='03384692759758802531'/></author></entry><entry><id>tag:blogger.com,1999:blog-13463691.post-1065664562220326273</id><published>2007-11-20T14:44:00.000-07:00</published><updated>2007-11-20T14:45:29.775-07:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='sucks'/><category scheme='http://www.blogger.com/atom/ns#' term='flash'/><title type='text'>Broken Bulb</title><content type='html'>With apologies to Johnny Cash: "Flash, I hate every inch of you."&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/13463691-1065664562220326273?l=griddlenoise.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/13463691/posts/default/1065664562220326273'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/13463691/posts/default/1065664562220326273'/><link rel='alternate' type='text/html' href='http://griddlenoise.blogspot.com/2007/11/broken-bulb.html' title='Broken Bulb'/><author><name>Jeff Shell</name><uri>http://www.blogger.com/profile/08875953026022510741</uri><email>noreply@blogger.com</email><gd:extendedProperty xmlns:gd='http://schemas.google.com/g/2005' name='OpenSocialUserId' value='03384692759758802531'/></author></entry><entry><id>tag:blogger.com,1999:blog-13463691.post-8757505951513943648</id><published>2007-11-07T21:26:00.000-07:00</published><updated>2007-11-07T21:34:01.005-07:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='scm'/><category scheme='http://www.blogger.com/atom/ns#' term='git'/><category scheme='http://www.blogger.com/atom/ns#' term='cvs'/><title type='text'>Falling for Git</title><content type='html'>&lt;p&gt;You know what? &lt;a href="http://git.or.cz/"&gt;Git&lt;/a&gt; must have come a long way in the last year. I keep reading that Git is hard to learn, has rough documentation, etc. But it&amp;#8217;s really been quite nice in comparison to many things.&lt;/p&gt;

&lt;p&gt;It&amp;#8217;s especially nice once you quickly learn that the HTML &lt;a href="http://www.kernel.org/pub/software/scm/git/docs/git.html"&gt;man pages for Git&lt;/a&gt; follow a simple pattern (as I guess many online man page collections must). Just change the end of the URL from &lt;code&gt;git-cvsimport.html&lt;/code&gt; to &lt;code&gt;git-push.html&lt;/code&gt; or &lt;code&gt;git-pull.html&lt;/code&gt; to look up documentation.&lt;/p&gt;

&lt;p&gt;That I&amp;#8217;ve been able to play around with Git quite successfully and easily just makes my frustration with some Python tools (like &lt;em&gt;easy_install&lt;/em&gt; and &lt;em&gt;zc.buildout&lt;/em&gt;, particularly its recipes) even more &amp;#8230;. frustrating.&lt;/p&gt;

&lt;p&gt;And, I&amp;#8217;ve totally fallen in love with Git. Yes, I know there are alternatives written in Python that are quite comparable. But Git&amp;#8217;s actually been easier to install and figure out (particularly the CVS interaction that I must currently suffer). And people who know me know that I&amp;#8217;m no &amp;#8220;Kernel monkey&amp;#8221;. I&amp;#8217;m really impressed with Git&amp;#8217;s implementation and general behavior. Very impressed with the implementation.&lt;/p&gt;

&lt;p&gt;By the way: if you&amp;#8217;re having to work two ways with a CVS repository, &lt;a href="http://tsunanet.blogspot.com/2007/07/git-cvs-in-5min.html"&gt;this post has been absolutely invaluable&lt;/a&gt;. &lt;a href="http://wincent.com/knowledge-base/Category:Git"&gt;This collection of Git articles&lt;/a&gt; has been invaluable in getting some good defaults established, and some tips for building on Mac OS X (with a nice tip to download and untar the &lt;a href="http://www.kernel.org/pub/software/scm/git/git-manpages-1.5.3.5.tar.bz2"&gt;man pages&lt;/a&gt; directly instead of trying to build them with the &lt;em&gt;asciidoc&lt;/em&gt; tool and its terrible dependency on troublesome XML libraries. Goddamn, how I hate XML).&lt;/p&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/13463691-8757505951513943648?l=griddlenoise.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/13463691/posts/default/8757505951513943648'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/13463691/posts/default/8757505951513943648'/><link rel='alternate' type='text/html' href='http://griddlenoise.blogspot.com/2007/11/falling-for-git.html' title='Falling for Git'/><author><name>Jeff Shell</name><uri>http://www.blogger.com/profile/08875953026022510741</uri><email>noreply@blogger.com</email><gd:extendedProperty xmlns:gd='http://schemas.google.com/g/2005' name='OpenSocialUserId' value='03384692759758802531'/></author></entry><entry><id>tag:blogger.com,1999:blog-13463691.post-9073426687678533609</id><published>2007-11-01T01:52:00.000-06:00</published><updated>2007-11-01T02:51:32.829-06:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='python'/><category scheme='http://www.blogger.com/atom/ns#' term='cocoa'/><category scheme='http://www.blogger.com/atom/ns#' term='mac'/><category scheme='http://www.blogger.com/atom/ns#' term='applescript'/><category scheme='http://www.blogger.com/atom/ns#' term='scripting'/><category scheme='http://www.blogger.com/atom/ns#' term='apple'/><title type='text'>AppleScripting Across the Universe</title><content type='html'>&lt;p&gt;After a long day at work, I wrote a long message in Basecamp about what I had accomplished, how to access it, etc. But I forgot to submit the message! Crud. I wanted to send it out before morning and didn&amp;#8217;t want to go into the office. I couldn&amp;#8217;t get any screen sharing connection to go between the machines. I just had a handful of SSH leaps.&lt;/p&gt;

&lt;p&gt;AppleScript to the rescue!&lt;/p&gt;

&lt;p&gt;This is probably the most AppleScript that I&amp;#8217;ve ever written. Fortunately, Safari supports the command &lt;code&gt;do JavaScript ... in tab&lt;/code&gt;. After some floundering around with a similar setup on my local machine, I finally figured out AppleScript&amp;#8217;s interesting reference notation and was able to ferret out the window and tab containing the unsent message, add some text to the message&amp;#8217;s textarea element, submit the form, and return the extended value.&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;tell application "Safari"
    set message_tab to current tab of window named "Web site &amp;gt; New message"

    set extended to ".... Fun fact - i wrote this before i left the office and forgot to submit it. as a result, i now know how to submit forms like this via AppleScript."
    set post_body_value to "$('post_body').value"
    set extend_value to post_body_value &amp;amp; " += '" &amp;amp; extended &amp;amp; "';"

    do JavaScript extend_value in message_tab
    set body_value to do JavaScript post_body_value in message_tab

    do JavaScript "document.forms[0].submit();" in message_tab

    return body_value
end tell
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;I pasted the above code into VIM and ran it with the command line &lt;code&gt;osascript&lt;/code&gt; command. Worked like a champ.&lt;/p&gt;

&lt;p&gt;And because sleep is for the weak, I decided to track down how to do the equivalent in Python. Mac OS X 10.5 provides a &amp;#8220;Scripting Bridge&amp;#8221; for Python and Ruby (and potentially others), which causes many frameworks and other objects to be dynamically exposed. Without the need (for better or worse) of yet-another-virtual-machine. Anyways, I cobbled the following together:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;from Foundation import *
from ScriptingBridge import *
safari = SBApplication.applicationWithBundleIdentifier_('com.apple.Safari')

def find_window_named(name):
    for win in safari.windows():
        if win.name() == name:
            return win

window = find_window_named("Web site &amp;gt; New message")
message_tab = window.currentTab()

print safari.doJavaScript_in_("$('post_body').value", message_tab)
safari.doJavaScript_in_("document.forms[0].submit()", message_tab)
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;There may be a better way to do the &lt;code&gt;find_window_named&lt;/code&gt; method, but I didn&amp;#8217;t have the time to track it down. As it was, I was able to do do the above by playing around with everybody&amp;#8217;s favorite Python tool, &lt;code&gt;dir()&lt;/code&gt;, which verified my suspicion that many of the commands exposed to AppleScript were also available via the Scripting Bridge. This is evidenced by the &lt;code&gt;currentTab()&lt;/code&gt; method of a Safari window, analogous to the &lt;code&gt;current tab of window ...&lt;/code&gt; AppleScript. And I imagine most of these are just Objective C methods. And since AppleScript editor&amp;#8217;s Dictionary browser told me about the &lt;code&gt;do Javascript [v] in tab [t]&lt;/code&gt; command, it stood to reason that it would exist on the Safari object. It was there when I did &lt;code&gt;pprint(dir(safari))&lt;/code&gt;, and I knew that I&amp;#8217;d need to pass in a Tab object.&lt;/p&gt;

&lt;p&gt;In any case, it&amp;#8217;s awesome that Apple has embraced Python and Ruby and has tied them in to the Cocoa runtime. Historical note: the first Python - Objective C bindings that I know of where commissioned by a NeXT Developer who wanted to use Python and Bobo (zope.publisher) to do web work with NeXT&amp;#8217;s Enterprise Objects Framework, without the weight and cost of WebObjects. I think that means that Python was bridged into the Objective C runtime and NeXTStep frameworks before Jython ever got going. I believe that work was done by the developer who later released &lt;a href="http://www.stepwise.com/PR/Nov/TipTop_971124.html"&gt;Objective Everything&lt;/a&gt; which bridged into Perl and TCL as well as Python.&lt;/p&gt;

&lt;p&gt;Of course, traditional MacPython from the classic Mac OS was also natively tied in to the AppleScript of that era; AppleScript has always supported other dialects (FrontierScript was a common one).&lt;/p&gt;

&lt;p&gt;But it&amp;#8217;s nice now to see support coming out of both Apple and Microsoft (and Sun too, I guess) for these languages. The above scripting of Safari was surprisingly easy. As was an earlier experiment to fish around my calendar store for incomplete To-Do items. Quite nice.&lt;/p&gt;

&lt;p&gt;But what&amp;#8217;s especially nice is that I was able to SSH into my office Mac and tell Safari to submit that form that I had neglected earlier.&lt;/p&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/13463691-9073426687678533609?l=griddlenoise.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/13463691/posts/default/9073426687678533609'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/13463691/posts/default/9073426687678533609'/><link rel='alternate' type='text/html' href='http://griddlenoise.blogspot.com/2007/11/applescripting-across-universe.html' title='AppleScripting Across the Universe'/><author><name>Jeff Shell</name><uri>http://www.blogger.com/profile/08875953026022510741</uri><email>noreply@blogger.com</email><gd:extendedProperty xmlns:gd='http://schemas.google.com/g/2005' name='OpenSocialUserId' value='03384692759758802531'/></author></entry><entry><id>tag:blogger.com,1999:blog-13463691.post-4868037104070497659</id><published>2007-10-29T22:29:00.000-06:00</published><updated>2007-10-30T01:58:02.222-06:00</updated><title type='text'>Java Crybabies</title><content type='html'>&lt;p&gt;So Mac OS X 10.5 (Leopard) doesn&amp;#8217;t ship with Java 6.  And now &lt;a href="http://www.javalobby.org/java/forums/t102936.html"&gt;Java people are all sad&lt;/a&gt; and mad and yelling at Apple for dropping the ball on this.&lt;/p&gt;

&lt;p&gt;Why should Apple go out of their way to provide Java 6? After the aborted Java - Objective C bridge experiments, what else is there to do? &amp;#8220;Native&amp;#8221; Java applications have still never come close to feeling like a native or near native piece of the operating system. Why should Apple keep throwing engineering efforts at this system?&lt;/p&gt;

&lt;p&gt;And whatever happened to OpenStep for Solaris by the way?&lt;/p&gt;

&lt;p&gt;Honestly, Apple has a dynamic object runtime environment heavily tied to a C based language already. It&amp;#8217;s done much of what Java and the .Net framework are now doing, and has been doing that since the latter half of the eighties. It&amp;#8217;s interesting to look back to the mid nineties and at the criticisms of NeXTStep/OpenStep. &amp;#8220;Why are you using this Objective C thing? Why not C++?&amp;#8221;&lt;/p&gt;

&lt;p&gt;Because what NeXT understood that others didn&amp;#8217;t was that the runtime is what&amp;#8217;s important. NeXTStep came closest to providing a Smalltalk-style runtime of dynamic collaborating objects without being the alien and self contained environment that Smalltalk can often be. Initially tied in to a Unix operating system, it later went multi-platform (at least to an extent - I think FoundationKit, Enterprise Objects Framework, WebObjects, and PDO (Portable Distributed Objects) ran on HP-UX and Solaris, while all of those plus AppKit ran on NT, along with D&amp;#8217;OLE (distributing COM/OLE while Microsoft was still struggling to provide DCOM)).&lt;/p&gt;

&lt;p&gt;In those same mid nineties, there were other attempts to provide some of the power of the NeXTStep / OpenStep platform. IBM perhaps came closes with their CORBA (Corba 1.x) based SOM, which was also to be at the heart of OpenDoc. SOM was the heart of the fascinating OS/2 2.0 and Warp. It also was used in the classic Mac OS. Of course, it was there in OpenDoc&amp;#8217;s brief life. But beyond that, SOM was used to provide contextual menu plug-ins, interestingly enough. But it was still fairly heavy, as CORBA could be. Too much wringing and wrangling to help non-dynamic languages function in a semi-dynamic world.&lt;/p&gt;

&lt;p&gt;And then there was Microsoft&amp;#8217;s Cairo. Never shipped. Some of its technologies found their way into NT&amp;#8230; But the big features? One of the big features was to be an &amp;#8220;object oriented file system&amp;#8221;. This resurfaced as WinFS for Vista. Twelve-plus years later, and it&amp;#8217;s still not done.&lt;/p&gt;

&lt;p&gt;And of course, there was Taligent. Initially, Taligent was going to be an all-new Operating System, aggressively object oriented, etc. Apple and IBM together, to make a NeXTStep for the rest of us, perhaps? Except instead of a dynamic language, they decided to go for C++. But they apparently had to pump in a lot of work to overhaul the C++ runtime and try to provide some of the dynamic loading options (of Smalltalk, NeXTStep/Objective C, etc). It was a lot of time wasted, I&amp;#8217;m sure. And they eventually had to pull back from the all-new operating system plan. That was probably wise, considering the environment of the time. Apple never was able to complete Copland and Gershwin, and Microsoft never got Cairo finished; BeOS never found a substantial market; and even early NeXT-era Apple wasn&amp;#8217;t able to sell the idea of a NeXTStep based Mac OS until they provided the Carbon migration path for the classic Mac APIs.&lt;/p&gt;

&lt;p&gt;So Taligent shifted to providing, like OpenStep, differing layers that would provide these object features on top of differing host operating systems. Still never happened. Which is a bit of a bummer - they had some paradigms that would have been interesting to see.&lt;/p&gt;

&lt;p&gt;In 1994, Jon Udell wrote a short article titled &amp;#8220;&lt;a href="http://web.archive.org/web/20020609014601/http://www.d.kth.se/~d95-aeh/taligenc.html"&gt;A Taligent Update&lt;/a&gt;,&amp;#8221; subtitled &lt;em&gt;Will systemwide object frameworks reinvent programming?&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;Well, while Taligent never delivered; and OpenStep faded into WebObjects (providing the OpenStep developer tools on NT, NeXTStep Mach, and Mac OS X Server 1.x, aka Rhapsody); this seems to have actually, finally, come to pass. Cocoa is a &lt;em&gt;killer&lt;/em&gt; framework for Mac OS X, with many fans. There are bridges to many other languages (Ruby, Perl, Python, among others). It&amp;#8217;s not quite the pervasive system-wide framework that it was in the NeXTStep days, but in Mac OS X Leopard Cocoa looks as though it&amp;#8217;s reclaiming its position as king of the hill. (For a while, there were many Carbon APIs that were a bitch to use from Cocoa; or at least those used to the comparative ease of Cocoa programming).&lt;/p&gt;

&lt;p&gt;And Microsoft&amp;#8217;s .NET framework has delivered similar in the Windows market. Of course, it doesn&amp;#8217;t have anything like Interface Builder; but it still seems to have a much better share-and-reuse model than anything that&amp;#8217;s come before it in Windows programming. And it&amp;#8217;s built on: dynamic object systems. Unlike Java (which I&amp;#8217;ll get to in a minute), the .NET framework and core languages (C#) appear to be taking cues from Objective C and purely dynamic languages/systems like Smalltalk: &lt;a href="http://community.bartdesmet.net/blogs/bart/archive/2006/12/06/C_2300_-3.0-Feature-Focus-_2D00_-Part-4-_2D00_-Extension-Methods.aspx"&gt;dynamic class extension&lt;/a&gt;, for example, is a new feature in C# 3.0. It&amp;#8217;s also been possible in &lt;a href="http://developer.apple.com/documentation/Cocoa/Conceptual/ObjectiveC/Articles/chapter_4_section_7.html#//apple_ref/doc/uid/TP30001163-CH7-TPXREF139"&gt;Objective C&lt;/a&gt;. This can be a dangerous feature; but also quite useful and usable. But it&amp;#8217;s nice to see this in languages and systems that try to combine C, which has the benefits of familiarity, with the power of dynamic object-filled worlds.&lt;/p&gt;

&lt;p&gt;And it&amp;#8217;s much better than the heavy and strained world of COM and CORBA.&lt;/p&gt;

&lt;p&gt;So anyways - NeXT, and now Apple, has been ahead of this game for quite some time. Granted, if it weren&amp;#8217;t for Apple, NeXT would be another blip like Taligent. Except with a shipping product. But still - they survived. And their system wide dynamic object framework idea seems to have been vindicated.&lt;/p&gt;

&lt;p&gt;So what of Java?&lt;/p&gt;

&lt;p&gt;Java is the bastard child here. I&amp;#8217;ve never been comfortable with it. It&amp;#8217;s not cross platform: Java IS the platform. And it&amp;#8217;s awkward. Even in its best desktop guise - Eclipse - it&amp;#8217;s still a foreign environment on Mac OS X. Even Firefox is starting to feel more natural (and Firefox 3 looks to be trying even harder in this area). Why would we want it? Sun has never seemed to care that much about Java on Macs, except to try to showcase their &amp;#8220;see, multi-platform!&amp;#8221; message. But Windows has always gotten the lions share of the attention, even though Microsoft long ago stopped caring about Java.&lt;/p&gt;

&lt;p&gt;On a side note, we&amp;#8217;re seeing the same thing happen now with Flash. Ugh. It&amp;#8217;s a memory hog on Mac OS X. Makes poor use of 
resources. If Adobe and Sun don&amp;#8217;t seem to care enough about providing a truly killer Mac experience, is it any wonder that they&amp;#8217;re being kicked off of the island? Apple&amp;#8217;s got the dynamic object system language and frameworks (Objective C, Cocoa); and it&amp;#8217;s got an increasingly impressive web environment (WebKit, with Canvas support); it has bridges into and out of AppleScript, Python, Ruby, and Perl, all included with Leopard - bridges too!&lt;/p&gt;

&lt;p&gt;One just has to look at how huge the &amp;#8220;Java in a Nutshell&amp;#8221; books have become to know that Java is no small undertaking. And again, I think that Apple probably has stopped caring. They&amp;#8217;ve tried to be good Java citizens - from the Java - Objective C bridge to the all-Java implementation of WebObjects; they&amp;#8217;ve tried to be make the Cocoa framework appealing to Java developers and probably tried to make Java appealing to Cocoa developers. But it must not have ever happened. It&amp;#8217;s all deprecated now.&lt;/p&gt;

&lt;p&gt;And I don&amp;#8217;t know what&amp;#8217;s going on, really. I just see Apple as having other priorities. It&amp;#8217;s not like they&amp;#8217;re (purely) a not-invented-here company. They have, after all, built in &lt;a href="http://www.sun.com/bigadmin/content/dtrace/"&gt;Sun&amp;#8217;s DTrace technology&lt;/a&gt;. And Apple builds on and gives back to Open Source, with projects like &lt;a href="http://launchd.macosforge.org/"&gt;launchd&lt;/a&gt;, the new &lt;a href="http://trac.calendarserver.org/projects/calendarserver"&gt;calendar server&lt;/a&gt;, &lt;a href="http://trac.macosforge.org/projects/bridgesupport/"&gt;bridge support&lt;/a&gt;, &lt;a href="http://www.webkit.org/"&gt;WebKit&lt;/a&gt;, etc.&lt;/p&gt;

&lt;p&gt;But Java&amp;#8230;? Apple has no real stake in it any more. The last Java application I ran was Eclipse, months ago, just trying to see what life in a fancy IDE would be like. It was disappointing. Desktop Java just doesn&amp;#8217;t figure into a Mac user&amp;#8217;s life all that much. I&amp;#8217;d rather see Apple focus on improving their primary object language (which inspired Java), focus on improving their APIs and offering more features for programmers (all done handily in Mac OS X 10.5 - from a programmer&amp;#8217;s standpoint, it&amp;#8217;s extremely impressive) and providing a smooth, fast, and natural platform experience (again done handily in Mac OS X 10.5 - see the still-unequaled Interface Builder 3.0; see CoreAnimation; see a &lt;a href="http://mattgemmell.com/2007/10/28/get-rid-of-your-code-with-leopard"&gt;sea of new UI object offerings from Apple&lt;/a&gt;).&lt;/p&gt;

&lt;p&gt;Why would they spend their time fighting uphill to support a platform whose chief aim is to be an anti-platform? At best, desktop Java on the Mac could mean &amp;#8220;runs a windows-like-application-almost-as-good-as-windows, maybe.&amp;#8221; Well, we now have Boot Camp and Parallels/VMWare for that. Apple wants to provide a killer alternative platform, and they&amp;#8217;ve learned that the best way to do that is to be in control. When Mac browsers were suffering - IE on Mac OS X was slow and strange (compared to near excellent behavior in OS 9), Camino and Firefox were big and slow and non-native (Camino did a decent job, but it had different widget implementations for browser skin and in-page rendering), OmniWeb looked beautiful but its support for new HTML and Javascript was far behind, etc - Apple took control of their destiny by building Safari. And they built in on a toolkit that would let them plug in the right widgets and behavior for a native experience. Hence, all Safari users have long enjoyed having spell checking support in their TextAreas. We get that from Cocoa. As of Mac OS X 10.5, we can turn on grammar checking as well. And now, WebKit is &lt;em&gt;leading&lt;/em&gt; much of the HTML 5 charge, recently announcing preliminary support for &lt;a href="http://webkit.org/blog/126/webkit-does-html5-client-side-database-storage/"&gt;client side database storage&lt;/a&gt;, and were among the first (if not THE first) to put forward tags like &lt;strong&gt;canvas&lt;/strong&gt; which may make SVG usable and make ultimately take care of many uses of Flash (remember when Flash was purely an animation tool?). Apple has all of this in their control. They don&amp;#8217;t have to put up with lackluster players / viewers from Adobe.&lt;/p&gt;

&lt;p&gt;And I think it&amp;#8217;s become pretty clear that Apple&amp;#8217;s preferred solution at this time for rich cross-platform(ish) UI and Code is - the web. HTML, CSS, Javascript. It powers Dashboard; it&amp;#8217;s been a big selling point of the iPhone (although it is admittedly laughable that Apple said &amp;#8220;Web 2.0 apps are your iPhone API!&amp;#8221;, but it&amp;#8217;s still impressive; people have built some very impressive apps with that very system).&lt;/p&gt;

&lt;p&gt;Why does AJAX / DHTML succeed where Applets have failed? And even Flash does poorly? It&amp;#8217;s not just because it&amp;#8217;s &amp;#8220;everywhere&amp;#8221;, without a need to install and deal with a JRE. It&amp;#8217;s because AJAX is part of the web page. It&amp;#8217;s not a self contained rectangle that can do really cool things - within the realm of that rectangle. It&amp;#8217;s because AJAX leverages the browser&amp;#8217;s toolkit, so that a text field in IE behaves like a text field in IE; and a text field on a Mac behaves like a text field on a Mac. Java performance has never been that great on the Mac. Which must mean that no one cared enough to really try to make it shine, or that the technology is really heavy and inferior. I remember groaning every time I used to check the snow report page at one of the ski resorts because of the extra amount of time taken to load up Java and all that accompanies it just to render some scrolling-headlines; scrolling headlines whose text didn&amp;#8217;t match (or even anti-alias with) the surrounding text. It&amp;#8217;s absolutely useless and pointless. Granted - I have seen some impressive Java applets in the science arenas, and IBM had some cool chess ones in their old Deep Blue v Kasparov (?) challenge. But again, those have been few and far between.&lt;/p&gt;

&lt;p&gt;The two desktop Java apps that I&amp;#8217;ve used heavily at points in the past, besides my experiments with Eclipse, were with a UML tool, and then LimeWire. Both of these used on Macs. The UML tool was tolerable, but barely. Limewire was terribly slow - click and wait instead of click and point. Desktop Java is dead to me. I don&amp;#8217;t know why you&amp;#8217;d want to write in it. Cocoa is just an all out balls out better environment, especially for UI programming as (again) Interface Builder remains peerless. And .NET, especially with the Mono implementation, is a far more interesting playground that seems keen on taking in new dynamic, declarative, and functional features, (LINQ, F#, etc), while Java just feels like a big stack of alphabet soup and static typing and not much else. (Although I do understand that Java 6 has started to break this mold).&lt;/p&gt;

&lt;p&gt;And as far as languages go: please. Python, Perl, and Ruby alone offer better cross platform capabilities than Java: especially on the server side where Java is supposed to shine. I didn&amp;#8217;t have to wait for Apple&amp;#8217;s blessing to use Python 2.5 on my desktop Mac. I didn&amp;#8217;t have to wait for Apple&amp;#8217;s blessing to draw native widgets with it either. I didn&amp;#8217;t have to wait for Apple&amp;#8217;s blessing to use Python 1.x to control other applications across the scripting bridges of Mac OS 7, 8, and 9.&lt;/p&gt;

&lt;p&gt;Now that Java is Open Source (it is, isn&amp;#8217;t it?), maybe the Java community can look into what it would take to provide a good Java experience on Mac OS X. I think that is its only hope. It has to become leaner. The dynamic &amp;#8220;scripting&amp;#8221; language crowd have all been able to find ways to take advantage of different platforms. Why is it on Apple&amp;#8217;s head to provide Mac Java? Going back to what I asked earlier - is Sun going to try to get OpenStep going again on Solaris? Is Microsoft going to provide Java 6 for Windows? Is Apple going to provide .NET 3.5 for the Mac?&lt;/p&gt;

&lt;p&gt;A response I&amp;#8217;ve seen in the Java community is that Apple is arrogant for not shipping Java 6 with Leopard, and for withdrawing any development downloads and many topics related to Java on the Mac. I think that it&amp;#8217;s arrogant of the Java community to think that they matter enough for Apple to continue to sink engineering resources into the platform. They&amp;#8217;ve sunk a lot in over the years, and there&amp;#8217;s never been a huge payoff. I see no reason for them to continue. They have far better alternatives.&lt;/p&gt;

&lt;p&gt;IBM or Sun or anyone else out in the Java / Open Source community should take it upon themselves to provide a good platform if they really care. They&amp;#8217;re obviously doing it for Linux and Windows.&lt;/p&gt;

&lt;p&gt;Sorry, this is a long and rambling post and now it&amp;#8217;s quite late at night when I swore I would be going to bed early. But seriously - Java has not mattered to me as a developer or Mac user for years. It&amp;#8217;s a dead weight for Apple. Support for Mac OS &amp;#8220;Classic&amp;#8221; got the boot in Leopard, and even Carbon is looking like its days are numbered. If those two can be cut off, what the hell chance would Java have?&lt;/p&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/13463691-4868037104070497659?l=griddlenoise.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/13463691/posts/default/4868037104070497659'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/13463691/posts/default/4868037104070497659'/><link rel='alternate' type='text/html' href='http://griddlenoise.blogspot.com/2007/10/java-crybabies.html' title='Java Crybabies'/><author><name>Jeff Shell</name><uri>http://www.blogger.com/profile/08875953026022510741</uri><email>noreply@blogger.com</email><gd:extendedProperty xmlns:gd='http://schemas.google.com/g/2005' name='OpenSocialUserId' value='03384692759758802531'/></author></entry><entry><id>tag:blogger.com,1999:blog-13463691.post-8783158614436935637</id><published>2007-10-12T14:50:00.000-06:00</published><updated>2007-10-12T14:51:25.707-06:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='javascript'/><category scheme='http://www.blogger.com/atom/ns#' term='mochikit'/><category scheme='http://www.blogger.com/atom/ns#' term='jquery'/><category scheme='http://www.blogger.com/atom/ns#' term='zope3'/><category scheme='http://www.blogger.com/atom/ns#' term='python'/><category scheme='http://www.blogger.com/atom/ns#' term='coding style'/><category scheme='http://www.blogger.com/atom/ns#' term='sqlalchemy'/><category scheme='http://www.blogger.com/atom/ns#' term='toolkits'/><title type='text'>Catching Up</title><content type='html'>&lt;p&gt;These periods between posts keep getting longer, don&amp;#8217;t they?&lt;/p&gt;

&lt;p&gt;I&amp;#8217;ve got nothing earth-shattering to talk about. Work&amp;#8217;s been very busy, and we continue to be served well by &lt;a href="http://wiki.zope.org/zope3/Zope3Wiki"&gt;Zope 3&lt;/a&gt;. I&amp;#8217;m still royally confused by things like &lt;a href="http://peak.telecommunity.com/DevCenter/setuptools"&gt;setuptools and eggs&lt;/a&gt;, mostly in regards to how they work in a Zope 3 world when you&amp;#8217;ve already got long entrenched ways of doing software. I could not get a good answer from anyone I asked (in fact, I often got wildly competing opinions). So I&amp;#8217;m sticking with our internal make-rake-like-ish toolkit which is primarily helpful for automating checkouts from internal and external repositories. I did have some success with &lt;a href="http://cheeseshop.python.org/pypi/zc.buildout"&gt;zc.buildout&lt;/a&gt;, but I don&amp;#8217;t yet foresee a time when I can use it to deploy whole sites/applications. I can barely see a time when I can use it on anything but small projects that are relatively stand-alone. There&amp;#8217;s just a big gap between The Way Things Have Been Done and The Way That It Seems That Maybe Things Should Be Done In The Future.&lt;/p&gt;

&lt;p&gt;Of course, neither setuptools nor zc.buildout seem to have &amp;#8220;proper&amp;#8221; releases. &lt;em&gt;zc.buildout&lt;/em&gt; is in an endless 1.0 beta (beta-30 at this point), and &lt;em&gt;setuptools&lt;/em&gt; is at 0.6c7. Does that mean that it&amp;#8217;s not even at release 0.6 quality yet? None of this instills confidence in this hurried developer.&lt;/p&gt;

&lt;p&gt;The big problem is the legacy code, which is in CVS. Some of it is being extracted out into individual packages that have the proper &amp;#8216;setup.py&amp;#8217;, &amp;#8216;buildout.cfg&amp;#8217;, etc. Finally. But I have no idea how to apply it to the bigger picture, and I&amp;#8217;ve found very little written words that target our situation.&lt;/p&gt;

&lt;p&gt;The biggest downside of being so busy with customer related work is that it&amp;#8217;s very difficult to keep up with discussions, conversations, plans, etc. And I&amp;#8217;m sure that my frustrations with lack of documentation, seemingly unfinished releases, and so on, are really the fruit of other hurried developers. I admire them for at least releasing something. It&amp;#8217;s more than I&amp;#8217;ve done in a long time. It&amp;#8217;s more than I see myself being able to do for quite some time.&lt;/p&gt;

&lt;p&gt;Anyways, the revolving door of Javascript toolkits keeps turning. I&amp;#8217;m now deeply enamored with &lt;a href="http://jquery.com/"&gt;jQuery&lt;/a&gt;. &amp;#8220;Write less, do more&amp;#8221;. I like it. I like that it doesn&amp;#8217;t trample all over Javascript, and thus plays well with others (especially others that play well with others, like &lt;a href="http://mochikit.com/"&gt;MochiKit&lt;/a&gt;). MochiKit is just so big&amp;#8230; I think I might make a stab at writing, at least for internal use, a lightweight version that brings many of its best concepts out without overlapping jQuery&amp;#8217;s functionality. MochiKit brings many wonderful Python-ic functions and tools to the Javascript table that make general development much easier.&lt;/p&gt;

&lt;p&gt;I&amp;#8217;m also deeply enamored with &lt;em&gt;zc.resourcelibrary&lt;/em&gt; which is a Zope 3 add-on that makes it much easier to manage javascript and CSS resources and their relations to each other. Among other things, it helps save resources when they&amp;#8217;re not needed. For example::&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;if len(rendered_boxes) &amp;lt;= 3:
    return self.just_render_the_damn_boxes(rendered_boxes)
else:
    zc.resourcelibrary.need('fancy.scrolling.library')
    return self.render_the_advanced_widget(rendered_boxes)
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;I&amp;#8217;ve also adjusted my coding style, returning to the &lt;code&gt;underscore_separated_words&lt;/code&gt; style instead of the &lt;code&gt;camelCasedWords&lt;/code&gt; style, at least for functions, attributes, and methods. This is closer in style to &lt;a href="http://www.python.org/dev/peps/pep-0008/"&gt;PEP 8&lt;/a&gt; (the main style guide for Python code). The Zope style guide differs on this point, using camelCased instead. And PEP 8 does say that it&amp;#8217;s OK, if not downright preferred, to stay true to the style around you.&lt;/p&gt;

&lt;p&gt;But one thing I learned from looking through Rails code was that the underscore_style was easier to read, since the underscore acts like a space. And I&amp;#8217;ve become a big fan of writing code that communicates intent; that reads like a story (somewhat). &lt;em&gt;Extract Method&lt;/em&gt; is your friend. I&amp;#8217;ve grown very distrustful of excessive nesting, or of having very long bodies inside of a &amp;#8216;for&amp;#8217; or &amp;#8216;if&amp;#8217; block.&lt;/p&gt;

&lt;p&gt;That&amp;#8217;s about it. Hell of an update, huh? Well, work&amp;#8217;s really started to become &lt;em&gt;work&lt;/em&gt;, and is quite enjoyable. I&amp;#8217;ve got a good flow going and don&amp;#8217;t feel I have as much need (nor place) to be an advocate or crank. As I&amp;#8217;ve mentioned before, we&amp;#8217;ve gotten incredible levels of code re-use by building our internal libraries and applications on top of Zope 3, and we&amp;#8217;ve been able to grow them so much that they&amp;#8217;re really the first level of framework. It was such a struggle to do this in Zope 2, but in Zope 3 it does fall (fairly) neatly into place. Nothing else in the Python web-framework-whatsit world comes close.&lt;/p&gt;

&lt;p&gt;The only toolkit that&amp;#8217;s even better? &lt;a href="http://sqlalchemy.org/"&gt;SQLAlchemy&lt;/a&gt;. It&amp;#8217;s pretty much the only way I&amp;#8217;ll interact with RDBMS systems in Python from this point out. And I don&amp;#8217;t mean I&amp;#8217;ll be writing every RDBMS interaction as an object-relational mapping. SQLAlchemy is great because it provides a good connection / pooling infrastructure; a good Pythonic query building infrastructure; and then a good ORM infrastructure that is capable of complex queries and mappings (as well as some pretty stone-simple ones).&lt;/p&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/13463691-8783158614436935637?l=griddlenoise.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/13463691/posts/default/8783158614436935637'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/13463691/posts/default/8783158614436935637'/><link rel='alternate' type='text/html' href='http://griddlenoise.blogspot.com/2007/10/catching-up.html' title='Catching Up'/><author><name>Jeff Shell</name><uri>http://www.blogger.com/profile/08875953026022510741</uri><email>noreply@blogger.com</email><gd:extendedProperty xmlns:gd='http://schemas.google.com/g/2005' name='OpenSocialUserId' value='03384692759758802531'/></author></entry><entry><id>tag:blogger.com,1999:blog-13463691.post-1428092880014750406</id><published>2007-08-16T07:18:00.000-06:00</published><updated>2007-08-16T08:23:15.289-06:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='iwork'/><category scheme='http://www.blogger.com/atom/ns#' term='spreadsheets'/><category scheme='http://www.blogger.com/atom/ns#' term='numbers'/><category scheme='http://www.blogger.com/atom/ns#' term='applications'/><category scheme='http://www.blogger.com/atom/ns#' term='apple'/><title type='text'>Numbers</title><content type='html'>&lt;p&gt;I don&amp;#8217;t know when I last used a spreadsheet for its actual spreadsheet capabilities, on a sheet I designed myself. I think it may go back to AppleWorks (on the Apple II)! Sure, I&amp;#8217;ve used sheets like time cards and travel requests that others had made where I just had to fill in the holes. And I&amp;#8217;ve received more than my fair share of spreadsheets used like an outliner / lightweight database / structured note list. But I don&amp;#8217;t remember how long it&amp;#8217;s been since I used a spreadsheet to figure out a budget, to track expenses, or any other dumb mundane thing like that. Until last night.&lt;/p&gt;

&lt;p&gt;I was getting ready to pay my mid-month bills, and I was trying to figure out how much I could pay towards one of my credit cards and still have enough cash to cover the expenses remaining in the month. I also realized that I&amp;#8217;ve been spending quite a bit at the iTunes Music Store and hadn&amp;#8217;t been tracking any of it. I decided that this would be an excellent time to try out Apple&amp;#8217;s new spreadsheet application, &lt;a href="http://www.apple.com/iwork/numbers/"&gt;Numbers&lt;/a&gt;. I found a downloadable time trial of Apple&amp;#8217;s &lt;a href="http://www.apple.com/iwork/"&gt;iWork &amp;#8216;08&lt;/a&gt; suite, and immediately got to work.&lt;/p&gt;

&lt;p&gt;Numbers is pretty damn cool. I don&amp;#8217;t know if there are other spreadsheets that behave like this, but in modern times, it seems so obvious: instead of having the big set of cells in one large table, you work in small floating spreadsheets / tables. This is a big deal for so many reasons, with the most obvious being layout. Another great reason is that each table/spreadsheet can be more focused on its job. Already, Numbers felt a lot more intuitive than anything I had used in a long time.&lt;/p&gt;

&lt;p&gt;When doing my simple rest-of-the-month budget, my main question was &amp;#8220;how much can I pay on this card and still have enough cash on hand for the rest of the month?&amp;#8221; Numbers made it easy with its slider option. For just this one cell, I was able to quickly configure it to give me a slider with a range of -700 to -500. When I got the rest of the budget entered, I could then play with the slider and watch its impact on the total-leftover cell. In previous months, I&amp;#8217;ve generally done this calculation in my head, or compared where I stood the prior month after paying this particular bill. It was much nicer to whip up a simple spreadsheet where I could make this one particular number interactive and see the results immediately.&lt;/p&gt;

&lt;p&gt;So I was able to get a couple of simple but nice looking spreadsheets together quickly that gave me actual data. I could easily play with this data, or just be embarrassed by it (I have spent quite a bit on the iTunes Music Store).&lt;/p&gt;

&lt;p&gt;There are still a lot of old-style spreadsheet rules in play, at least in formulas and the like. That&amp;#8217;s made a bit easier by being able to use header names (ie, &lt;code&gt;=SUM(Total)&lt;/code&gt; or &lt;code&gt;=MINA(Date Purchased)&lt;/code&gt;). I think it was Lotus&amp;#8217; Improv, which first appeared on NeXTStep, that worked this way. In fact, I think with Improv, it was the only way you could work: there were no A/B/C/D columns or rows. This was part of a cool feature of Improv wherein you could drag and drop header representations and regroup the data visually without impact on the calculations. I still think that was one of the most forward-thinking spreadsheet applications. But, it&amp;#8217;s gone. I believe there&amp;#8217;s some open source variation on the idea, possibly written just for GNUStep&amp;#8230;?&lt;/p&gt;

&lt;p&gt;Still, &lt;a href="http://www.apple.com/iwork/numbers/"&gt;Numbers&lt;/a&gt; is pretty decent. I love the free-floating tables. It does make it much easier to compose complex spreadsheet pages out of multiple tables and data types. It&amp;#8217;s pretty easy to refer to other tables as well. And it&amp;#8217;s nice to have non-tabular data (text, graphics, etc) floating free from those numbers, making it easier to adjust layouts without impacting cells.&lt;/p&gt;

&lt;p&gt;I&amp;#8217;m impressed enough that I&amp;#8217;m quite likely to buy &lt;a href="http://www.apple.com/iwork/"&gt;iWork &amp;#8216;08&lt;/a&gt;, just for Numbers alone. I have a small need for &lt;a href="http://www.apple.com/iwork/pages/"&gt;Pages&lt;/a&gt; and almost no need for Keynote, but I do find myself needing to get on top of my finances and similar data. Numbers is the first tool I&amp;#8217;ve encountered that I think will let me handle my odd needs without requiring a degree or summer course in spreadsheets.&lt;/p&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/13463691-1428092880014750406?l=griddlenoise.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/13463691/posts/default/1428092880014750406'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/13463691/posts/default/1428092880014750406'/><link rel='alternate' type='text/html' href='http://griddlenoise.blogspot.com/2007/08/numbers.html' title='Numbers'/><author><name>Jeff Shell</name><uri>http://www.blogger.com/profile/08875953026022510741</uri><email>noreply@blogger.com</email><gd:extendedProperty xmlns:gd='http://schemas.google.com/g/2005' name='OpenSocialUserId' value='03384692759758802531'/></author></entry><entry><id>tag:blogger.com,1999:blog-13463691.post-3007085774174010572</id><published>2007-07-18T20:26:00.000-06:00</published><updated>2007-07-18T20:31:13.109-06:00</updated><title type='text'>Yahoo TV Is Now Useless</title><content type='html'>&lt;p&gt;So, I used to use &amp;#8220;My Excite&amp;#8221; as my little personal portal. It had good TV listings, which is always important. But many years ago, as Excite was was burying its content under more and more ads, I switched to &amp;#8220;My Yahoo!&amp;#8221;. Which was even better. Great TV listings. So even now, when I don&amp;#8217;t have cable or satellite, I found it valuable.&lt;/p&gt;

&lt;p&gt;But then they changed. They upgraded to super fancy TV listings full of AJAX-y action.&lt;/p&gt;

&lt;p&gt;But do you know what sucks?&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;THEY CAN&amp;#8217;T GET TIMEZONES RIGHT!&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;It&amp;#8217;s been quite a few months now, &lt;strong&gt;and they still can&amp;#8217;t get my timezone right&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;For seven or eight years, I had no problem with localized listings. Although for a few of those years I was in the blessed Eastern Time Zone. But even when I moved out west - no problem.&lt;/p&gt;

&lt;p&gt;But now, apparently Yahoo! has invested all of their resources into flashy features but they can&amp;#8217;t tell me &lt;strong&gt;when a tv show is on according to the time in my area&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;Absolutely &lt;strong&gt;useless&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;For a while, I&amp;#8217;ve gotten by with using the TV listings on the &amp;#8220;My Yahoo!&amp;#8221; page. It didn&amp;#8217;t have all of the fancy features, &lt;strong&gt;so somehow it managed to get the times right&lt;/strong&gt;. But as of today, I&amp;#8217;m told that I have to use the new fancy-ass &amp;#8220;My Yahoo! Beta&amp;#8221;.&lt;/p&gt;

&lt;p&gt;First thing that happens when I visit the My Yahoo! beta?&lt;/p&gt;

&lt;p&gt;&amp;#8220;&lt;strong&gt;We don&amp;#8217;t support Safari&lt;/strong&gt;&amp;#8230;.&amp;#8221;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Goddammit&lt;/strong&gt;. Many of their other upgraded YUI based sites &lt;strong&gt;work fine in Safari&lt;/strong&gt;. I can understand them saying this months ago, which was the last time I looked at the new beta. But to still be having an issue? While trying to be a shiny partner of the lovely iPhone? What&amp;#8217;s up?&lt;/p&gt;

&lt;p&gt;Anyways, I clicked the &amp;#8220;live on the edge&amp;#8221; button to see the new page. There were the TV listings. &lt;strong&gt;In the wrong time zone!&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;I submitted an email months ago about this and got the &amp;#8220;yeah, we know, we&amp;#8217;re working on this&amp;#8221; response.&lt;/p&gt;

&lt;p&gt;I know that time zones are a bitch to work with, but come on: this shit has worked for years. And now it&amp;#8217;s been how long since the launch of the fancy new Yahoo TV section? Six months? Seven? Surely someone could have worked this out by now.&lt;/p&gt;

&lt;p&gt;I&amp;#8217;m so disappointed. Yahoo! was always one of the most reliable web sites. And I appreciate what they&amp;#8217;ve given to the developer community with YUI! and other tools. But this little TV listing issue just takes the cake. It makes it absolutely useless, and now &amp;#8220;My Yahoo!&amp;#8221;, which has been my &amp;#8216;home page&amp;#8217; for years, is all but useless as this became such a valued resource as their other sources stopped working.&lt;/p&gt;

&lt;p&gt;Very frustrating.&lt;/p&gt;

&lt;p&gt;And I&amp;#8217;m still looking for a good TV listing site. But all I&amp;#8217;ve come up with, so far, is pretty much bullshit. Wrong channels, inability to properly remember channels, too many ads, hard to access listings, slow display&amp;#8230;. Augh.&lt;/p&gt;

&lt;p&gt;Pissed.&lt;/p&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/13463691-3007085774174010572?l=griddlenoise.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/13463691/posts/default/3007085774174010572'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/13463691/posts/default/3007085774174010572'/><link rel='alternate' type='text/html' href='http://griddlenoise.blogspot.com/2007/07/yahoo-tv-is-now-useless.html' title='Yahoo TV Is Now Useless'/><author><name>Jeff Shell</name><uri>http://www.blogger.com/profile/08875953026022510741</uri><email>noreply@blogger.com</email><gd:extendedProperty xmlns:gd='http://schemas.google.com/g/2005' name='OpenSocialUserId' value='03384692759758802531'/></author></entry><entry><id>tag:blogger.com,1999:blog-13463691.post-1230647787449358105</id><published>2007-05-08T14:29:00.000-06:00</published><updated>2007-05-08T14:43:17.051-06:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='python3000'/><category scheme='http://www.blogger.com/atom/ns#' term='python'/><category scheme='http://www.blogger.com/atom/ns#' term='interfaces'/><title type='text'>Traits / Roles as Alternative to Abstract Base Classes</title><content type='html'>&lt;p&gt;While digging through the Python-3000 development list archives, trying to figure out the state of thought circling PEP&amp;#8217;s &lt;a href="http://www.python.org/dev/peps/pep-3119/"&gt;3119&lt;/a&gt; and &lt;a href="http://www.python.org/dev/peps/pep-3124/"&gt;3124&lt;/a&gt;, I came across this gem:&lt;/p&gt;

&lt;p&gt;&lt;a href="http://mail.python.org/pipermail/python-3000/2007-April/007026.html"&gt;&amp;#8220;Traits/roles instead of ABCs&amp;#8221;&lt;/a&gt;,  by Collin Winter.&lt;/p&gt;

&lt;p&gt;With ABCs refererring to Abstract Base Classes (pep 3119).&lt;/p&gt;

&lt;p&gt;Winter&amp;#8217;s proposal is similar to my &lt;a href="http://griddlenoise.blogspot.com/2007/05/abc-may-be-easy-as-123-but-it-cant-beat.html"&gt;recent post&lt;/a&gt;, which is that this sort of &amp;#8220;capability inference&amp;#8221; should be dynamic, and not bound to the rigid nature of the class hierarchy. In my post on this subject, I showed a number of different implementations of a single interface (specification, role, whatever) - only one implementation followed the basic class-instance scenario. All others provided the exact same outward appearance, while internally they were implemented as module-level functions, class or static methods, or a dynamically composed single-use object (a brainless instance was made and had methods dynamically attached).&lt;/p&gt;

&lt;p&gt;Winter&amp;#8217;s roles/traits system, which refers to roles in Perl 6 and traits in Squeak, is along the same lines. I hope to hell it gains traction.&lt;/p&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/13463691-1230647787449358105?l=griddlenoise.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/13463691/posts/default/1230647787449358105'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/13463691/posts/default/1230647787449358105'/><link rel='alternate' type='text/html' href='http://griddlenoise.blogspot.com/2007/05/traits-roles-as-alternative-to-abstract.html' title='Traits / Roles as Alternative to Abstract Base Classes'/><author><name>Jeff Shell</name><uri>http://www.blogger.com/profile/08875953026022510741</uri><email>noreply@blogger.com</email><gd:extendedProperty xmlns:gd='http://schemas.google.com/g/2005' name='OpenSocialUserId' value='03384692759758802531'/></author></entry><entry><id>tag:blogger.com,1999:blog-13463691.post-2864027387328317986</id><published>2007-05-04T10:45:00.000-06:00</published><updated>2007-05-04T14:04:32.362-06:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='python3000'/><category scheme='http://www.blogger.com/atom/ns#' term='zope3'/><category scheme='http://www.blogger.com/atom/ns#' term='python'/><category scheme='http://www.blogger.com/atom/ns#' term='interfaces'/><title type='text'>ABC may be easy as 123, but it can't beat zope.interface</title><content type='html'>&lt;p&gt;I guess the deadline may have come and gone for getting in &lt;a href="http://www.python.org/dev/peps/"&gt;PEPs&lt;/a&gt; for &lt;a href="http://www.python.org/dev/peps/pep-3000/"&gt;Python 3000&lt;/a&gt;. Guido&amp;#8217;s already written up a &lt;a href="http://mail.python.org/pipermail/python-3000/2007-May/007178.html"&gt;PEP Parade&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Of particular interest to me has been the appearance of PEPs for &lt;a href="http://www.python.org/dev/peps/pep-3119/"&gt;Abstract Base Classes&lt;/a&gt; (PEP 3119) and the more exhaustive &lt;a href="http://www.python.org/dev/peps/pep-3124/"&gt;PEP 3124&lt;/a&gt; which covers &amp;#8220;Overloading, Generic Functions, Interfaces, and Adaptation.&amp;#8221;&lt;/p&gt;

&lt;p&gt;Both of these aim to provide ways of saying &amp;#8220;this is file-ish&amp;#8221;, &amp;#8220;this is string-ish,&amp;#8221; without requiring subclassing from a concrete &amp;#8220;built-in&amp;#8221; type/class. But I think they both fall short a little bit, while &lt;code&gt;zope.interface&lt;/code&gt; (from the Zope 3 family) provides the best solution.&lt;/p&gt;

&lt;p&gt;PEP 3119 (Abstract Base Classes) has a section covering &lt;a href="http://www.python.org/dev/peps/pep-3119/#abcs-vs-alternatives"&gt;comparisons to alternative techniques&lt;/a&gt;, and it specifically mentions &amp;#8220;For now, I&amp;#8217;ll leave it to proponents of Interfaces to explain why Interfaces are better.&amp;#8221; So this is my &lt;del&gt;brief&lt;/del&gt; attempt at explaining why.&lt;/p&gt;

&lt;p&gt;A quote from PEP 3119 that I particularly like is &amp;#8220;Like all other things in Python, these promises are in the nature of a gentlemen&amp;#8217;s agreement&amp;#8230;&amp;#8221; The Interfaces as specified and used in Zope 3 and some other systems are the same way. They are not &amp;#8220;bondange and discipline&amp;#8221; Interfaces. They are not the ultra-rigid Eiffel contracts, nor are they the rigid and limited Interfaces as used by Java. They are basically a specification, and they can be used (as mentioned in PEP 3119) to provide additional metadata about a specification. There are some simple tools in &lt;code&gt;zope.interface.verify&lt;/code&gt; to check an implementation against a specification, but those are often used in test suites; they&amp;#8217;re not enforced hard by any system. The agreement might be &amp;#8220;I need a seekable file&amp;#8221;, which might mean it expects the methods/messages &amp;#8216;read&amp;#8217;, &amp;#8216;seek&amp;#8217;, and &amp;#8216;tell&amp;#8217;. If you only provide &amp;#8216;read&amp;#8217; and &amp;#8216;seek&amp;#8217;, then it&amp;#8217;s your fault for not living up to the agreement. That&amp;#8217;s no different than the Python of today. What Interfaces and Abstract Base Classes aim to provide is a better clarification of what&amp;#8217;s expected. Sometimes &amp;#8220;file-like&amp;#8221; in Python (today) means it just needs a &amp;#8216;read&amp;#8217; method. Sometimes it means the full suite of file methods (read, readlines, seek, tell). Same thing with sequences: sometimes it just means &amp;#8220;something iterable&amp;#8221;. Other times it means &amp;#8220;support append and extend and pop&amp;#8221;.&lt;/p&gt;

&lt;p&gt;Another side benefit of Interfaces as specification is that they provide a common language for, well, specifications. Many &lt;a href="http://www.python.org/dev/peps/"&gt;PEPs&lt;/a&gt; propose some sort of API, especially informational PEPs like &lt;a href="http://www.python.org/dev/peps/pep-0333/"&gt;WSGI (PEP 333)&lt;/a&gt; or &lt;a href="http://www.python.org/dev/peps/pep-0247/"&gt;API for Cryptographic Hash Functions (PEP 247)&lt;/a&gt;. I&amp;#8217;ll use PEP 247 as an example for &lt;em&gt;my attempt at explaining why Zope 3&amp;#8217;s Interfaces are Better&lt;/em&gt;.&lt;/p&gt;

&lt;p&gt;A problem with Abstract Base Classes is this: they&amp;#8217;re limited to classes. Even when PEP 3119 mentions Interfaces, it does so like this:&lt;/p&gt;

&lt;blockquote&gt;
  &lt;p&gt;&amp;#8220;Interfaces&amp;#8221; in this context refers to a set of proposals for additional metadata elements attached to a class which are not part of the regular class hierarchy&amp;#8230;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;It then goes on to mention that such specifications (in some proposals and implementations) may be mutable; and then says that&amp;#8217;s a problem since classes are shared state and one could mutate/violate intent. That&amp;#8217;s a separate discussion that I&amp;#8217;m not going to go into here.&lt;/p&gt;

&lt;p&gt;What is important is this &lt;strong&gt;severely limited focus on classes&lt;/strong&gt;. &lt;code&gt;zope.interface&lt;/code&gt; works on objects as well, and not just normal &amp;#8216;instances of a class&amp;#8217; object, but on classes themselves, &lt;strong&gt;and also modules&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;There are two important verbs in &lt;code&gt;zope.interface&lt;/code&gt;: &lt;em&gt;implements&lt;/em&gt; and &lt;em&gt;provides&lt;/em&gt;. &lt;em&gt;provides&lt;/em&gt; is the most important one - it means that this Object, whatever that object may be, provides the specified interface directly.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;implements&lt;/em&gt; is often used in class definitions. It means &amp;#8220;instances of this class will provide the specified interface&amp;#8221;. It can also be thought of in terms of Factories and/or Adaptation - &amp;#8220;calling this object will give you something that provides the desired interface.&amp;#8221;&lt;/p&gt;

&lt;p&gt;&amp;#8220;What does that matter?&amp;#8221; you might ask. Well, there are all sorts of ways to compose objects in Python. A module is an object. It has members. A class is an object. An instance of a class is, of course, an object. Functions and methods are also objects in Python, but for the most part what we care about here are Modules, Classes, and Instances.&lt;/p&gt;

&lt;p&gt;Because when it comes down to actual usage in code, it doesn&amp;#8217;t particularly matter what an object is. In &lt;a href="http://www.python.org/dev/peps/pep-3124/"&gt;PEP 3124&lt;/a&gt;, the author (Phillip J Eby) shows the following interface:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;class IStack(Interface):
    @abstract
    def push(self, ob)
        """Push 'ob' onto the stack"""

    @abstract
    def pop(self):
        """Pop a value and return it"""
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Ignore the &lt;code&gt;@abstract&lt;/code&gt; decorators, as they&amp;#8217;re artifacts of the rest of his PEP and/or related to &lt;a href="http://www.python.org/dev/peps/pep-3119/"&gt;PEP 3119&lt;/a&gt;. What is important is the use of &lt;strong&gt;self&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;&amp;#8220;self&amp;#8221; is an artifact of implementation that is invisible to use&lt;/strong&gt;. Sure, you can write a Stack implementation like this. (Note: I&amp;#8217;m going to use &lt;code&gt;zope.interface&lt;/code&gt; terminology and style from here on out):&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;import zope.interface

class Stack(object):
    zope.interface.implements(IStack)

    def __init__(self):
        self._stack = []

    def push(self, ob):
        self._stack.append(ob)

    def pop(self):
        return self._stack.pop()
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;But when it&amp;#8217;s being used, it&amp;#8217;s used like this:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;def do_something_with_a_stack(stack):
    stack.push(1)
    stack.push(2)
    # ...
    top = stack.pop()

stack_instance = Stack()
IStack.providedBy(stack_instance)
# True
IStack.providedBy(Stack)
# False

do_something_with_a_stack(stack_instance)
# works fine
do_something_with_a_stack(Stack)
# raises an exception because `Stack.push(1)` is passing `1` 
# to `self`.. unbound method, bla bla bla.
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Notice that &lt;strong&gt;there is no &amp;#8216;self&amp;#8217; reference visibly used when dealing with the IStack implementation&lt;/strong&gt;. This is an extremely important detail. What are some other ways that we may provide the IStack interface.&lt;/p&gt;

&lt;p&gt;One way is to do it with class methods and properties, effectively making a singleton. (This isn&amp;#8217;t a good way to do it, and is just here as an example).&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;import zope.interface

class StackedClass(object):
    zope.interface.classProvides(IStack)

    _stack = []

    @classmethod
    def push(class_, ob):
        class_._stack.append(obj)

    @classmethod
    def pop(class_):
        return class_._stack.pop()

IStack.providedBy(StackedClass)
# True

do_something_with_a_stack(StackedClass)
# this time it works, because `StackedClass.push(1)` is a class method,
# and is passing `StackedClass` to the `class_` parameter, and `1` 
# to `ob`.
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Another variation of the above is using Static Methods:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;import zope.interface

class StaticStack(object):
    zope.interface.classProvides(IStack)

    _stack = []

    @staticmethod
    def push(ob):
        StaticStack._stack.append(ob)

    @staticmethod
    def pop():
        return StaticStack._stack.pop()
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Again, &lt;code&gt;StaticStack.push(1)&lt;/code&gt; and &lt;code&gt;StaticStack.pop()&lt;/code&gt; work fine. Now lets try a third way - in a module! Let&amp;#8217;s call this module &lt;code&gt;mstack&lt;/code&gt; (file - &lt;code&gt;mstack.py&lt;/code&gt;)&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;import zope.interface

zope.interface.moduleProvides(IStack)

_stack = []

def push(ob):
    _stack.push(ob)

def pop():
    return _stack.pop()
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Then in other code:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;import mstack

IStack.providedBy(mstack)
# True
mstack.push(1)
mstack.push(2)

print mstack.pop()
# 2
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;So whether we&amp;#8217;re dealing with the instance in the first example (&lt;code&gt;stack_instance&lt;/code&gt;), the classes in the second two examples (&lt;code&gt;StackedClass&lt;/code&gt; and &lt;code&gt;StaticStack&lt;/code&gt;), or the module in the last example (&lt;code&gt;mstack&lt;/code&gt;), they&amp;#8217;re all objects that live up to the &lt;code&gt;IStack&lt;/code&gt; agreement. So having &lt;code&gt;self&lt;/code&gt; in the Interface is pointless. &lt;strong&gt;self is a binding detail.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Jim Fulton, the main author of &lt;code&gt;zope.interface&lt;/code&gt;, taught me this a long time ago. Because in Zope 2, you could also make an &lt;code&gt;IStack&lt;/code&gt; implementation using a Folder and a pair of Python scripts. Well, those Python scripts (as used in Zope 2 &amp;#8220;through-the-web&amp;#8221; development) have at least &lt;strong&gt;4 binding arguments&lt;/strong&gt;. Instead of &amp;#8216;self&amp;#8217;, the initial arguments are &lt;code&gt;context, container, script, traverse_subpath&lt;/code&gt;. Just like &lt;code&gt;self&lt;/code&gt; is automatically taken care of by the class-instance binding machinery, the four Zope Python Script binding arguments are automatically taken care of by Zope 2&amp;#8217;s internal machinery. You never pass those arguments in directly, you just use it like &lt;code&gt;push(ob)&lt;/code&gt; and &lt;code&gt;pop()&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;So there it is - many ways to provide this simple &amp;#8220;Stack&amp;#8221; Interface. And I believe that both [PEP 3119] and [PEP 3124] are short sighted by focusing on the class-instance relationship exclusively (or so it appears).&lt;/p&gt;

&lt;p&gt;And since many objects, particularly instances, are mutable, one could compose an IStack implementation on the fly.&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;class Prototype(object):
    """ Can be anything... """

pstack = Prototype()
pstack._stack = []

def pstack_push(ob):
    pstack._stack.append(ob)

def pstack_pop():
    return pstack._stack.pop()
pstack.push = pstack_push
pstack.pop = pstack_pop

# Now we can say that this particular instance provides the IStack
# interface directly - has no impact on the `Prototype` class
zope.interface.directlyProvides(pstack, IStack)

pstack.push(1)
pstack.push(2)
print pstack.pop()
2

# We can remove support as well
del pstack.push
zope.interface.noLongerProvides(pstack, IStack)
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Examples of dynamically constructed objects in the real world - a network services client, particularly one that&amp;#8217;s in an overwraught distributed object system (CORBA, SOAP, and other things that make you cry in the night). Dynamic local &amp;#8216;stub&amp;#8217; objects may be created at run time, but those could still be said to provide a certain interface.&lt;/p&gt;

&lt;p&gt;So now let&amp;#8217;s look at whether it matters that you&amp;#8217;re dealing with a class or not:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;@implementer(IStack)
def PStack():
    pstack = Prototype()
    pstack._stack = []

    def pstack_push(ob):
        pstack._stack.append(ob)

    def pstack_pop():
        return pstack._stack.pop()

    pstack.push = pstack_push
    pstack.pop = pstack_pop
    zope.interface.directlyProvides(pstack, IStack)

    return pstack

@implementer(IStack)
def StackFactory():
    # Returns a new `Stack` instance from the earlier example
    return Stack()

import mstack
import random

@implementer(IStack)
def RandomStatic():
    # chooses between the two class based versions and module
    return random.choice([StackedClass, StaticStack, mstack])
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;All three are factories that will return an object that provides an IStack implementation, which is exactly the same as the &lt;code&gt;Stack&lt;/code&gt; class in the first example. That also claimed that it &lt;code&gt;implements(IStack)&lt;/code&gt;. When the class is instantiated / called, a new object is made that provides the IStack interface. In Python, another thing that doesn&amp;#8217;t really matter is whether something is a class or function. All of the following lines of code yield a result that is the same to the consumer. The internal details of what is returned may vary, but the IStack interface works on all of them:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;Stack()         # class
PStack()        # 'Prototype' dynamically constructed object
StackFactory()  # Wrapper around basic class
RandomStatic()  # Chooses one of the class/static method implementations.
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;And whether we&amp;#8217;re looking at the class implementation, or any of the factory based implementations, the result should be the same:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;IStack.implementedBy(Stack) # class
# True
IStack.providedBy(Stack)
# False
IStack.providedBy(Stack())
# True

IStack.implementedBy(PStack)    # Factory
# True
IStack.providedBy(PStack)
# False
IStack.providedBy(PStack())
# True
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;No matter which method of instantiation is used, they should all pass the &lt;code&gt;verifyObject&lt;/code&gt; check, which checks to see whether all of the specified members are provided and that the method/function signatures match the specification&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;from zope.interface import verifyObject
verify_stack = partial(verifyObject, IStack)

all(verify_stack, [Stack(), PStack(), StackFactory(), RandomStatic()])
# True
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Now the class-based options will fail on the &lt;code&gt;implementedBy&lt;/code&gt; check, because it&amp;#8217;s the Class that provides the implementation, not an instance like with &lt;code&gt;Stack&lt;/code&gt;&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;IStack.implementedBy(StackedClass)
# False
IStack.providedBy(StackedClass)
# True
IStack.providedBy(StackedClass())
# False
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;&amp;#8220;OK&amp;#8221;, you might say, &amp;#8220;but still, why does it matter? Why might we really care about whether these abstract specifications work only with classes? It seems smaller, simpler.&amp;#8221;&lt;/p&gt;

&lt;p&gt;The main advantage is that &lt;strong&gt;specification should (generally) make no assumptions about implementation&lt;/strong&gt;. If the specification, aka &amp;#8220;gentlemen&amp;#8217;s agreement&amp;#8221; is generally met, it shouldn&amp;#8217;t matter whether it&amp;#8217;s provided by a Class, an instance, a module, an extension module, or some dynamically constructed object. &lt;strong&gt;The specification language should be the same&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Going back to &lt;a href="http://www.python.org/dev/peps/pep-0247/"&gt;PEP 247&lt;/a&gt;, the &amp;#8220;cryptographic hash API&amp;#8221;: there is a specification in that module about what the &amp;#8216;module&amp;#8217; must provide, and for what the hash objects must provide. Consider also the WSGI spec, the DB-API specs, and all of the other formal and informal specs that are floating around just in the PEPs. Using &lt;code&gt;zope.interface&lt;/code&gt;, those specifications can be spelled out in the same fashion. WSGI just cares about a particular function name signature. It can be provided by a single function in a simple module, or as a method from an object put together by a large system like the full Zope 3 application framework and server. It just wants a callable. This is a little bit ugly in &lt;code&gt;zope.interface&lt;/code&gt;&amp;#8230; but in reality, actually, I think it works. Here&amp;#8217;s how it could be specified:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;class IWSGIApplication(Interface):
    def __call__(environ, start_response):
        """ Document the function """
    # and/or use tagged values to set additional metadata
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;This just means that a WSGIApplication must be a callable object taking &lt;code&gt;environ&lt;/code&gt; and &lt;code&gt;start_response&lt;/code&gt; arguments. A callable object may be a function (taken from &lt;a href="http://www.python.org/dev/peps/pep-0333/"&gt;PEP 333&lt;/a&gt;):&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;def simple_app(environ, start_response):
    """Simplest possible application object"""
    status = '200 OK'
    response_headers = [('Content-type','text/plain')]
    start_response(status, response_headers)
    return ['Hello world!\n']
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Or a class (the &lt;code&gt;__init__&lt;/code&gt; is what is callable here). Maybe the WSGI spec might also state that the result &amp;#8220;should be iterable (support &lt;code&gt;__iter__&lt;/code&gt;)&amp;#8221; Maybe that&amp;#8217;s loosely enforced, but the following example shows how the class can make separate declarations about what the class directly provides, and what its instances implement. Instead of using any decorators or magic-ish &amp;#8220;class decorators&amp;#8221; (the &lt;code&gt;implements&lt;/code&gt;, &lt;code&gt;classProvides&lt;/code&gt; calls above), we&amp;#8217;ll make the declarations for both &lt;code&gt;AppClass&lt;/code&gt; and &lt;code&gt;simple_app&lt;/code&gt; in the same manner, which matches the style in &lt;a href="http://www.python.org/dev/peps/pep-3124/"&gt;PEP 3124&lt;/a&gt;.&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;class AppClass(object):
    def __init__(self, environ, start_response):
        self.environ = environ
        self.start = start_response

    def __iter__(self):
        status = '200 OK'
        response_headers = [('Content-type','text/plain')]
        self.start(status, response_headers)
        yield "Hello world!\n"

from zope.interface import directlyProvides, classImplements

# Both 'simple_app' and 'AppClass' are callable with the same arguments,
# so they both *provide* the IWSGIApplication interface

directlyProvides(simple_app, IWSGIApplication)
directlyProvides(AppClass, IWSGIApplication)

# And we can state that AppClass instances are iterable by supporting
# some phantom IIterable interface
classImplements(AppClass, IIterable)
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;What are the benefits of this, beyond just having a common way of spelling specifications? Instead of, or in addition to, abstract base classes, the core Python libraries can include all of these specs, even if they don&amp;#8217;t provide any concrete implementation. Then I could have a unit test in my code that uses &lt;code&gt;verifyClass&lt;/code&gt; or &lt;code&gt;verifyObject&lt;/code&gt; to ensure I stay inline with the specification.&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;def test_verifySpec(self):
    verifyClass(ICryptoHash, MyHashClass)
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Then, if the specification changes in a new version of Python or in a new version of someone elses library or framework, I can be notified.&lt;/p&gt;

&lt;p&gt;Of if the specification undergoes a big change, a new spec could be written, such as &lt;code&gt;IWSGI2Application&lt;/code&gt;. Then by process of adaptation (not covered in this post) or interface querying, a WSGI Server could respond appropriately to implementations of the earlier spec:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;if IWSGI2Application.providedBy(app):
    # Yay! We don't have to do anything extra!
    # ... do wsgi 2 work
elif IWSGIApplication.providedBy(app):
    # We have to set up the old `start_response` object
    # ... do wsgi 1 work
else:
    raise UnsupportedOrUndeclaredImplementation(app)
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Adaptation could provide a means of doing the above&amp;#8230; (still, not going into the details.. trying not to!)&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;@implementer(IWSGI2Application)
@adapts(IWSGIApplication)
def wsgi1_to_wsgi2(app):
    return wsgi2wrapper(app)

# And then, replacing the `if, else` above:
wsgi_app = IWSGI2Application(app, None)
if app is None:
    raise UnsupportedOrUndeclaredImplementation(app)
# ... do wsgi2 work
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;When you have both specification and adaptation, then you can write your code against the spec. In the above example, the main code does &lt;code&gt;IWSGI2Application(app, None)&lt;/code&gt; which means &amp;#8220;for the object &lt;code&gt;app&lt;/code&gt;, give me an object that provides IWSGI2Application, or None if there is no means of providing that interface.&amp;#8221;&lt;/p&gt;

&lt;p&gt;If &lt;code&gt;app&lt;/code&gt; provides that interface directly, then &lt;code&gt;app&lt;/code&gt; is returned directly. Otherwise an adaptation registry is found, and it&amp;#8217;s queried for a callable object (an adapter) that will take &amp;#8216;app&amp;#8217; as its argument and return an object that provides IWSGI2Application.&lt;/p&gt;

&lt;p&gt;Another example: knowing that Python 3000 is going to change a lot of core specifications and implementations, such as the attributes for functions (&lt;code&gt;func_code&lt;/code&gt;, &lt;code&gt;func_defaults&lt;/code&gt;, etc). If an &lt;code&gt;IPy2Function&lt;/code&gt; interface were made (and &lt;code&gt;zope.interface&lt;/code&gt; or something like it was added to Python 2.x), then code that works with function object internals could program against their preferred spec by adding a line of code:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;func = IPy2Function(func)
if my_sniffer(func.func_code):
    raise Unsafe(func)
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;On Python 2, you&amp;#8217;d get the regular function straight through. In Python 3000 / 3.0, an adapter would translate &lt;code&gt;__code__&lt;/code&gt; into &lt;code&gt;func_code&lt;/code&gt;, for example. I don&amp;#8217;t expect this to happen in reality, but it&amp;#8217;s an example of how migration paths &lt;em&gt;could&lt;/em&gt; be made between two major software versions, allowing code to run in both.&lt;/p&gt;

&lt;p&gt;By taking advantage of this system, my company &lt;a href="http://griddlenoise.blogspot.com/2007/04/reuse-and-non-use.html"&gt;has seen more re-use with Zope 3&lt;/a&gt; than at any time in our company history. And because (most of) Zope 3 is programmed against specification, we&amp;#8217;ve been able to plug in or completely make over the whole system by providing alternative implementations of core specs. This is very hard to do in native Zope 2 (the CMF, on which &lt;a href="http://plone.org"&gt;Plone&lt;/a&gt; is based, was probably the first Zope system that started these concepts, which Plone and others were able to take advantage of by providing new tools that matched the provided spec).&lt;/p&gt;

&lt;p&gt;At the heart of it, again, is the gentlemen&amp;#8217;s agreement, but brought out in full: it doesn&amp;#8217;t matter who you are or where you came from (ie, it doesn&amp;#8217;t matter what classes are in your family tree or if you are a simple module), as long as you get the job done. There&amp;#8217;s a simple contract, and as long as the contract is fulfilled, then everybody is happy.&lt;/p&gt;

&lt;p&gt;But if the gentlemen involved can only come from the class system, then there&amp;#8217;s still a nasty aristocracy that excludes a large chunk of the populace, all of whom can potentially fulfill the contract. Let&amp;#8217;s not cause an uprising, OK?&lt;/p&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/13463691-2864027387328317986?l=griddlenoise.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/13463691/posts/default/2864027387328317986'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/13463691/posts/default/2864027387328317986'/><link rel='alternate' type='text/html' href='http://griddlenoise.blogspot.com/2007/05/abc-may-be-easy-as-123-but-it-cant-beat.html' title='ABC may be easy as 123, but it can&apos;t beat zope.interface'/><author><name>Jeff Shell</name><uri>http://www.blogger.com/profile/08875953026022510741</uri><email>noreply@blogger.com</email><gd:extendedProperty xmlns:gd='http://schemas.google.com/g/2005' name='OpenSocialUserId' value='03384692759758802531'/></author></entry><entry><id>tag:blogger.com,1999:blog-13463691.post-9208107548001112313</id><published>2007-04-30T11:32:00.000-06:00</published><updated>2007-04-30T11:34:03.170-06:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='python'/><title type='text'>plispy</title><content type='html'>&lt;p&gt;Sometimes, it just happens...&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;&gt;&gt;&gt; pprint(
...     sorted(
...         map(
...             linecount,
...             path('.').walkfiles('*.py')
... )))&lt;/code&gt;&lt;/pre&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/13463691-9208107548001112313?l=griddlenoise.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/13463691/posts/default/9208107548001112313'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/13463691/posts/default/9208107548001112313'/><link rel='alternate' type='text/html' href='http://griddlenoise.blogspot.com/2007/04/plispy.html' title='plispy'/><author><name>Jeff Shell</name><uri>http://www.blogger.com/profile/08875953026022510741</uri><email>noreply@blogger.com</email><gd:extendedProperty xmlns:gd='http://schemas.google.com/g/2005' name='OpenSocialUserId' value='03384692759758802531'/></author></entry><entry><id>tag:blogger.com,1999:blog-13463691.post-7243230097062498826</id><published>2007-04-24T23:33:00.000-06:00</published><updated>2007-04-27T08:26:58.113-06:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='ruby'/><category scheme='http://www.blogger.com/atom/ns#' term='scons'/><category scheme='http://www.blogger.com/atom/ns#' term='buildout'/><category scheme='http://www.blogger.com/atom/ns#' term='python'/><category scheme='http://www.blogger.com/atom/ns#' term='setuptools'/><category scheme='http://www.blogger.com/atom/ns#' term='rake'/><category scheme='http://www.blogger.com/atom/ns#' term='make'/><category scheme='http://www.blogger.com/atom/ns#' term='distutils'/><title type='text'>Python's Make Rake and Bake, another and again</title><content type='html'>&lt;p&gt;Ian Bicking wrote a post recently titled &lt;a href="http://blog.ianbicking.org/pythons-makefile.html"&gt;&amp;#8220;Python&amp;#8217;s Makefile&amp;#8221;&lt;/a&gt;. He advocates using / re-using &lt;a href="http://docs.python.org/lib/module-distutils.html"&gt;distutils&lt;/a&gt;&amp;#8230; er&amp;#8230; &lt;a href="http://peak.telecommunity.com/DevCenter/setuptools#creating-distutils-extensions"&gt;setuptools&lt;/a&gt;. (I can&amp;#8217;t keep them straight - they&amp;#8217;ve both become absolute nightmares in my opinion). He then goes off about entry points, separate &lt;code&gt;setup.cfg&lt;/code&gt; files, and other things that still go way over my head. The example he shows is convoluted, and I&amp;#8217;m ultimately not entirely sure what he&amp;#8217;s really advocating (besides the idea - which isn&amp;#8217;t bad - of using the near-standard &lt;code&gt;setup.py&lt;/code&gt; file/system instead of re-inventing).&lt;/p&gt;

&lt;p&gt;But he mentions, earlier:&lt;/p&gt;

&lt;blockquote&gt;
  &lt;p&gt;Because really people are talking about something more like &lt;a href="http://rake.rubyforge.org/"&gt;rake&lt;/a&gt; &amp;#8212; something where you can put together a bunch of code management tools. These aren&amp;#8217;t commands provided by the code, these are commands used on the code.&lt;/p&gt;
  
  &lt;p&gt;We do have the infrastructure for this in Python, but no one is really using it. So I&amp;#8217;m writing this to suggest people use it more: the setup.py file. So where in another environment someone does &lt;code&gt;rake COMMAND&lt;/code&gt;, we can do &lt;code&gt;python setup.py COMMAND&lt;/code&gt;.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;For me, having an easy way to say &lt;code&gt;bla bla COMMAND&lt;/code&gt; isn&amp;#8217;t as important as having a good system for automating common tasks that I and/or my colleagues do frequently. As we started to depend on more and more code from internal and external repositories, due to our &lt;a href="http://griddlenoise.blogspot.com/2007/04/reuse-and-non-use.html"&gt;increased re-use when building on Zope 3&lt;/a&gt;, I really needed to automate checkouts and exports. Not everything was neatly packaged as an egg, or the released egg didn&amp;#8217;t have a bugfix applied, and I still don&amp;#8217;t understand how to make eggs work well with Zope 3 in a manner that I&amp;#8217;m comfortable with.&lt;/p&gt;

&lt;p&gt;I was initially excited about &lt;a href="http://cheeseshop.python.org/pypi/zc.buildout"&gt;zc.buildout&lt;/a&gt; as a way to automate the monotonous but important tasks that revolve around setting up both deployment and development environments. But I didn&amp;#8217;t like how &lt;code&gt;zc.buildout&lt;/code&gt; specified its tasks/commands in INI format. It was relatively easy to write new &amp;#8216;recipes&amp;#8217;, so I wrote some recipes to do Subversion and CVS checkouts/exports.&lt;/p&gt;

&lt;p&gt;But the INI format just pissed me off. It didn&amp;#8217;t fit my needs, basically, wherein I needed more conditional control. More code control. And managing complex sets of parameters required making new top-level sections instead of nesting. Before long I was staring at a very long and very narrow file. And in the end, it was building Zope in a way that wouldn&amp;#8217;t work for us. So I abandoned it.&lt;/p&gt;

&lt;p&gt;I briefly looked at some tools that let you write these task files in &amp;#8220;pure&amp;#8221; Python. In this way, &lt;a href="http://www.scons.org/"&gt;Scons&lt;/a&gt; appeared to be the closest thing in Python to &lt;a href="http://rake.rubyforge.org/"&gt;Rake&lt;/a&gt;, which uses Ruby. But &lt;em&gt;Scons&lt;/em&gt; seemed far more focused on general compilation issues (compiling C, Java, etc), but that&amp;#8217;s never a problem that crosses my path.&lt;/p&gt;

&lt;p&gt;I just wanted something like &lt;a href="http://rake.rubyforge.org/"&gt;rake&lt;/a&gt;. What I liked about &lt;em&gt;every&lt;/em&gt; Rakefile that I&amp;#8217;ve seen is that it&amp;#8217;s been quite readable. Rake makes common file / path commands readily available as Ruby methods, classes, and objects. Rake takes advantage of Ruby&amp;#8217;s syntax, particularly blocks (and optional parenthesis) in a way that makes it not seem like, well, Ruby. It looks like something makefile-ish, something shell-scripting-ish, etc. That&amp;#8217;s what I wanted; but, of course, in Python.&lt;/p&gt;

&lt;p&gt;So I came up with a system. It&amp;#8217;s not yet released to the world - far from finished, and there are many competing ideas out there that I don&amp;#8217;t feel like competing with - but it&amp;#8217;s already proven to be very useful internally. Generally, it&amp;#8217;s been used to automate what I mentioned above: retrieving software from multiple repositories, both Subversion and CVS, and placing them in the proper directories. In particular, we try to stick with certain revisions for third party dependencies, and I got tired of trying to capture this information in READMEs and other files that we could refer to when installing certain configurations. It&amp;#8217;s even been useful for downloading such software and applying internal patches::&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;patch = Command('patch')

@task('mysqldbda')
def mysqldbda():
    """ Installs mysqldbda from subversion and applies patch """
    svn = Subversion('svn://svn.zope.org/repos/main')
    svn.co('mysqldbda/tags/mysqldbda-1.0.0', target='mysqldbda')

    # patch mysqldbda
    log.info("patching mysqldbda")
    patchfile = path('fixes/mysqlda.1-5-07.patch')
    if patchfile.exists():
        print patch.read('-p1', '-i', patchfile)

@task('formencode')
def formencode():
    svn = Subversion('http://svn.colorstudy.com/FormEncode')
    svn.co('tags/0.6/formencode')

task('install', ['mysqldbda', 'formencode'])
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;It&amp;#8217;s also been useful for tasks like getting &lt;a href="http://mochikit.com/"&gt;MochiKit&lt;/a&gt; and generating all sorts of packed versions. A lot of what makes this possible is the &lt;a href="http://www.jorendorff.com/articles/python/path/"&gt;path.py&lt;/a&gt; module, which provides a more object-oriented interface over &lt;code&gt;os&lt;/code&gt;, &lt;code&gt;os.path&lt;/code&gt;, and other Python file utilities.&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;ROCKFILEPATH = globals().get('ROCKFILEPATH', path('.'))
MOCHIKIT_LIB = ROCKFILEPATH/'libs'/'mochikit'
MOCHIKIT_DL = ROCKFILEPATH/'mochikit_dl'
MOCHIKIT_SRC = MOCHIKIT_DL/'MochiKit'
SCRATCH = MOCHIKIT_LIB/'_scratch.js'
mochikit = namespace('mochikit')

@mochikit.task('get')
def getmochikit():
    if MOCHIKIT_DL.exists() and bool(MOCHIKIT_DL.listdir()):
        return
    svn = Subversion('http://svn.mochikit.com/mochikit')
    svn.co('trunk', target=MOCHIKIT_DL)

@mochikit.task('clearmochilib')
def clearmochilib():
    for jscript in MOCHIKIT_LIB.files('*.js'):
        jscript.remove()

@mochikit.task('make-noexport')
def makenoexport():
    info = Subversion().info(MOCHIKIT_DL)
    src = NOEXPORT.safe_substitute(**info)
    file(MOCHIKIT_LIB/'NoExport.js','w').write(src)

@mochikit.task('build', ['get', 'clearmochilib', 'make-noexport'])
def mochi_install():
    for source in MOCHIKIT_SRC.files('*.js'):
        log.info('copy %s -&amp;gt; %s' % (source, MOCHIKIT_LIB))
        source.copy(MOCHIKIT_LIB)

# Javascript Packing tools (JSPack not shown - essentially it's a wrapper
# around combining and piping Javascript through Dojo's custom_rhino.jar
# to use its compression system)
def packmodules(sourcedir, modules, target):
    mods = [ (sourcedir/mod) for mod in modules ]
    log.info('Packing %s modules', path(target).name)
    JSPack(mods, target).run()

    if SCRATCH.exists():
        SCRATCH.remove()

def jsmin(sources, target):
    packmodules(MOCHIKIT_LIB, sources, MOCHIKIT_LIB/'min'/target)

@mochikit.task('minimize')
def mochiMinimize():
    """
    Generates packed versions of most individual MochiKit files, while
    combining a few core ones together.
    """
    mindir = MOCHIKIT_LIB/'min'
    for jscript in mindir.files('*.js'):
        jscript.remove()
    jsmin(['NoExport.js', 'Base.js', 'Iter.js', 'DOM.js'], 'base-iter-dom.js')
    jsmin(['Style.js', 'Signal.js'], 'style-signal.js')
    jsmin(['Async.js'], 'async.js')
    jsmin(['Color.js'], 'color.js')
    # ...

mochikit.task('install', ['build', 'minimize']).comment('INSTALL!')
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;I don&amp;#8217;t think this falls under the jurisdiction of &lt;code&gt;setup.py&lt;/code&gt; (distutils/setuptools). Nor would I want to specify these as &lt;code&gt;zc.buildout&lt;/code&gt; recipes and have a separate configuration file to then name all of the files and directories. And, being Python, I don&amp;#8217;t really have to deal with compilation steps so I don&amp;#8217;t need wrappers around &lt;code&gt;gcc&lt;/code&gt; and friends. I&amp;#8217;m not (yet) specifying how to build large deployment scenarios. I just need to automate some development tasks, and I need to be able to write them easily. I want to write them in Python, but I want to ensure that they don&amp;#8217;t accidentally get imported into normal projects (hence, the files above don&amp;#8217;t have a &lt;code&gt;.py&lt;/code&gt; extension). And as this is a specialized task, I&amp;#8217;ll allow myself to get away with Python shortcuts that I would never touch in normal development, such as &lt;code&gt;import *&lt;/code&gt;. In fact, it&amp;#8217;s the &lt;code&gt;import *&lt;/code&gt; that gives me a lot of the common commands/tools, such as the classes for interacting with Subversion and CVS, managing working directories, etc.&lt;/p&gt;

&lt;p&gt;This really stemmed from reading &lt;a href="http://martinfowler.com/bliki/JRake.html"&gt;this article by Martin Fowler&lt;/a&gt; about people wanting to replace &lt;a href="http://ant.apache.org/"&gt;ant&lt;/a&gt; with Rake with the advent of JRuby. In the post, Martin states:&lt;/p&gt;

&lt;blockquote&gt;
  &lt;p&gt;The thing with build scripts is that you need both declarative and procedural qualities. The heart of a build file is defining tasks and the dependencies between them. This is the declarative part, and is where tools like ant and make excel. The trouble is that as builds get more complex these structures aren&amp;#8217;t enough. You begin to need conditional logic; in particular you need the ability to define your own abstractions. (See &lt;a href="http://www.martinfowler.com/articles/rake.html"&gt;my rake article&lt;/a&gt; for examples.)&lt;/p&gt;
  
  &lt;p&gt;Rake&amp;#8217;s strength is that it gives you both of these. It provides a simple declarative syntax to define tasks and dependencies, but because this syntax is an internal DomainSpecificLanguage, you can seamlessly weave in the full power of Ruby.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;At that point, I decided that this was the way to go: use Python decorators to wrap &amp;#8216;task&amp;#8217; functions. The wrapper maintains dependency links, comments, and other things of interest to the internal system; and the wrapper allows the task name to be independent of the function name, allowing easier-to-type tasks for use from the file system. But the &amp;#8216;task&amp;#8217; function is plain Python. Or, like some of the examples above show, &lt;code&gt;task&lt;/code&gt; can be called without the &lt;code&gt;@&lt;/code&gt; symbol that makes it a decorator. Multiple callable actions can be added to a task, potentially allowing for more &amp;#8216;declarative&amp;#8217; style:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;mochikit.task('minimize').using_action(
  JSMinMap(
    {'style-signal.js': ['Style.js', 'Signal.js']},
    {'async.js': ['Async.js']},
  ))
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Useful, I imagine, for very common patterns. Er. &amp;#8220;Recipes&amp;#8221;. In any case, it&amp;#8217;s a very useful kind of tool. Beats &lt;code&gt;setup.py&lt;/code&gt;, &lt;code&gt;INI&lt;/code&gt;, or XML based automation language any day.&lt;/p&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/13463691-7243230097062498826?l=griddlenoise.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/13463691/posts/default/7243230097062498826'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/13463691/posts/default/7243230097062498826'/><link rel='alternate' type='text/html' href='http://griddlenoise.blogspot.com/2007/04/pythons-make-rake-and-bake-another-and.html' title='Python&apos;s Make Rake and Bake, another and again'/><author><name>Jeff Shell</name><uri>http://www.blogger.com/profile/08875953026022510741</uri><email>noreply@blogger.com</email><gd:extendedProperty xmlns:gd='http://schemas.google.com/g/2005' name='OpenSocialUserId' value='03384692759758802531'/></author></entry><entry><id>tag:blogger.com,1999:blog-13463691.post-2146239670088514101</id><published>2007-04-18T11:41:00.000-06:00</published><updated>2007-04-18T12:12:37.208-06:00</updated><title type='text'>Cock Radio</title><content type='html'>&lt;p&gt;This whole &lt;em&gt;Don Imus&lt;/em&gt; issue has confused the shit out of me. Talk radio is full of that kind of, um, talk. Anyways, it all feels like the &lt;a href="http://www.southparkstudios.com/show/display_episode.php?season=11&amp;amp;id1=1101&amp;amp;id2=158"&gt;first episode of the latest season of South Park&lt;/a&gt;. Sometimes, South Park can crank out a new episode in response to a very recent event, but that didn&amp;#8217;t happen here. This episode aired weeks earlier.&lt;/p&gt;

&lt;p&gt;As for how or why this Don Imus issue exploded in the way that it did - I just don&amp;#8217;t understand (and now I feel like Stan Marsh at the end of that South Park episode). There are so many similar things said all the time by many radio &amp;#8220;personalities.&amp;#8221;&lt;/p&gt;

&lt;p&gt;&lt;a href="http://mediamatters.org/"&gt;Media Matters&lt;/a&gt; has an excellent post up chronicling the many slurs of Glenn Beck, O&amp;#8217;Reilly, and more: &lt;a href="http://mediamatters.org/items/200704120010"&gt;It&amp;#8217;s not just Imus&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;The response to the whole Imus situation just seems wrong: a cause celeb on which everyone can jump. The latest distraction. How the hell did it get so out of hand? Who did it &lt;em&gt;really&lt;/em&gt; offend? Why this &amp;#8220;nappy headed ho&amp;#8217;s&amp;#8221; statement? Why not &amp;#8220;ghetto slut&amp;#8221; (Boortz)? &amp;#8220;Turbanned hoodlums&amp;#8221; (Savage)?&lt;/p&gt;

&lt;p&gt;Imus is probably far less offensive than many of these other radio people, and neither his firing nor all of this special attention is going to make anything better. Nor did it solve anything. It just provided everybody with some bullshit theater.&lt;/p&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/13463691-2146239670088514101?l=griddlenoise.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/13463691/posts/default/2146239670088514101'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/13463691/posts/default/2146239670088514101'/><link rel='alternate' type='text/html' href='http://griddlenoise.blogspot.com/2007/04/cock-radio.html' title='Cock Radio'/><author><name>Jeff Shell</name><uri>http://www.blogger.com/profile/08875953026022510741</uri><email>noreply@blogger.com</email><gd:extendedProperty xmlns:gd='http://schemas.google.com/g/2005' name='OpenSocialUserId' value='03384692759758802531'/></author></entry><entry><id>tag:blogger.com,1999:blog-13463691.post-1678945150042190166</id><published>2007-04-17T16:06:00.000-06:00</published><updated>2007-04-17T16:08:27.489-06:00</updated><title type='text'>What about search?</title><content type='html'>&lt;p&gt;From my tumblog: &lt;a href="http://dirtymodern.tumblr.com/post/1006448"&gt;but I don't want my search engine to be a slide show!&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;Google - remember that search engine of yours? How about making it better by offering some options like result filtering ("I don't feel like shopping right now, I'm trying to research")?&lt;/p&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/13463691-1678945150042190166?l=griddlenoise.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/13463691/posts/default/1678945150042190166'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/13463691/posts/default/1678945150042190166'/><link rel='alternate' type='text/html' href='http://griddlenoise.blogspot.com/2007/04/what-about-search.html' title='What about search?'/><author><name>Jeff Shell</name><uri>http://www.blogger.com/profile/08875953026022510741</uri><email>noreply@blogger.com</email><gd:extendedProperty xmlns:gd='http://schemas.google.com/g/2005' name='OpenSocialUserId' value='03384692759758802531'/></author></entry><entry><id>tag:blogger.com,1999:blog-13463691.post-114195265668189680</id><published>2007-04-17T11:55:00.000-06:00</published><updated>2007-04-17T14:50:53.593-06:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='zope3'/><title type='text'>Reuse and non use</title><content type='html'>&lt;p&gt;We&amp;#8217;ve been using &lt;a href="http://wiki.zope.org/zope3/FrontPage"&gt;Zope 3&lt;/a&gt; in earnest for just over a year and a half now. I would like to report that in that year and a half &lt;strong&gt;our little company has achieved more re-use than at any time in our history&lt;/strong&gt;. This is real re-use too: libraries of tools and objects that are easily shared among both horizontal and vertical markets, yet customized for each customer as needed. Benefits for one are fairly easily shared with all.&lt;/p&gt;

&lt;p&gt;In the &lt;a href="http://www.zope.org/Products/"&gt;Zope 2&lt;/a&gt; days, we tried hard to achieve this. But we were constantly having to re-invent the kind of architecture that I believe really makes this work: adaptation, which also brings dynamic view binding, dynamic UI generation (ie - registering a &amp;#8216;tab&amp;#8217; for a particular object / interface and having it show up in the UI as necessary, etc. We had to spend a lot of time making the frameworks that would let us make frameworks.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;&amp;#8220;Frameworks for making frameworks?&amp;#8221;&lt;/em&gt; - you heard right. Let&amp;#8217;s face it: most web work is custom development. Sometimes custom development is best served by tools like &lt;a href="http://www.rubyonrails.org/"&gt;Ruby on Rails&lt;/a&gt; or &lt;a href="http://pylonshq.com/"&gt;Pylons&lt;/a&gt;, or even by plain old PHP. But sometimes you know you&amp;#8217;re going to have at least five customers all needing variations on the same thing in the coming months; and potentially more after that. You&amp;#8217;re going to need to at least make a library or two.&lt;/p&gt;

&lt;p&gt;See, &lt;strong&gt;Model-View-Controller&lt;/strong&gt; isn&amp;#8217;t just about &amp;#8220;separating business logic from presentation&amp;#8221;. It&amp;#8217;s about separating it in a way that you can take business objects and logic (the &amp;#8216;model&amp;#8217; layer; or models and services) and put more than one view on them. And by &amp;#8220;more than one view&amp;#8221;, I don&amp;#8217;t mean &amp;#8220;more than one template.&amp;#8221; I mean putting wholly different user interfaces on it. I mean being able to take a base library and override a few select options (or many select options) as they appeal to a customer.&lt;/p&gt;

&lt;p&gt;We tried to achieve this on some of our Zope 2 products, but it was hard to extract frameworks. We did OK, however, but I think that the most re-use we ever got was about three or four customers on one toolkit. That was over a three or four year span. We re-used patterns and snippets quite often, but it took a lot of work to extract an e-commerce toolkit from a particular customer&amp;#8217;s site, and more work still to make it adaptable and workable for different customer requirements. &lt;/p&gt;

&lt;p&gt;In the year and a half since using &lt;strong&gt;Zope 3&lt;/strong&gt; full time, we&amp;#8217;ve had double that - and with far greater results. It&amp;#8217;s not an easy system to just start using from scratch, but it can be quite worth it.&lt;/p&gt;

&lt;p&gt;Being back at work on some legacy &lt;strong&gt;Zope 2&lt;/strong&gt; projects has made me all the more appreciative.&lt;/p&gt;

&lt;p&gt;By the way: for a simpler Zope 3 development experience, check out &lt;a href="http://grok.zope.org/"&gt;Grok&lt;/a&gt;.&lt;/p&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/13463691-114195265668189680?l=griddlenoise.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/13463691/posts/default/114195265668189680'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/13463691/posts/default/114195265668189680'/><link rel='alternate' type='text/html' href='http://griddlenoise.blogspot.com/2007/04/reuse-and-non-use.html' title='Reuse and non use'/><author><name>Jeff Shell</name><uri>http://www.blogger.com/profile/08875953026022510741</uri><email>noreply@blogger.com</email><gd:extendedProperty xmlns:gd='http://schemas.google.com/g/2005' name='OpenSocialUserId' value='03384692759758802531'/></author></entry></feed>