Wednesday, January 19, 2005

Choose Python.

A little doodle I came up with whilst waiting for my C++ debugger to sync up with my target device. I think I'm going to have it made into a T-shirt:

Tuesday, January 18, 2005

PyWebOff: a Desperately-Needed Event

From the site:
PyWebOff is a compare-and-contrast exercise to evaluate the strengths and weaknesses of some of the major Python web application frameworks.
Thank you! This is something that we Pythonistas really need.

So far, the answer to "how does Python support web programming?" has been "well, there's Zope, Webkit, CherryPy, Quixote, Woven..." There hasn't been much "If you want X, then you probably want Y." advice.

XML support in Python has the same issues. Maybe some disinterested party can do a similar analysis there.

Friday, January 07, 2005

Apologies to PlanetPython

Ack. Apologies to the PlanetPython folks, who caught a bunch of ugly garbage from my blogspot feed. Blogspot creates some pretty ugly XHTML when you syndicate full content.

Thursday, January 06, 2005

Leaky Abstractions and UI Toolkits

Late last night, I was digging around in the bowels of ATL for some work-related research and got distracted into doing some wxPython digging, after which I got distracted into doing some Wax digging. (Long night).

I like the clean and idiomatic Wax design. But when you commit to Wax, you're committing to a lot. For example, on Windows, your dependency chain looks like this:

YourApp -> Wax -> wxPython -> wxWidgets -> Win32

Each of those arrows is an abstraction (or for those who like big words, a "paradigm boundary transition"). And each abstraction leaks. This is true for all abstractions, because an abstraction is just a bridge between two different sets of assumptions.

One good example of abstraction leaks occurs when you're a procedural process like Win32 window creation in an object framework (I'll use C++ for this example). To create a window from C, you first create and register a window class structure, which includes a pointer to a window procedure (a callback function that handles all messages for windows of that class). Then you call CreateWindowEx(), specifying your window class. This creates the window and returns a unique identifier for the window (called a window handle, or HWND). Simple, right?

Object-oriented folks would want to create a C++ class for each "window class" and one instance of that C++ class for each window. So you implement the window procedure as a static class method, because Windows expects callbacks to have C linkage. Your window procedure needs to dispatch messages to the appropriate object, so you need a map of HWNDs to instances, which you populate in your object's constructor with the HWND returned by CreateWindowEx.

But there's a subtle gotcha: when CreateWindowEx creates the window it immediately sends several messages to the window procedure and processes the results before returning. When your static window procedure receives these messages, CreateWindowEx hasn't returned yet, so your object hasn't updated the mapping table yet, which means your window procedure doesn't know which object should handle the message!

Object toolkits solve this with different, but equally egregious hacks. MFC and wxWidgets abuse a little-known but documented Windows feature called a CBT hook to get a notification at the moment a window is created (before messages are processed). ATL is more evil--it injects a hand-written assembly language thunk into the beginning of your window procedure to replace the HWND parameter with the address of the C++ object (of course, this means they have to hand-write assembly code for each CPU they support, but as far as Microsoft cares, "portability is for canoes").

The point is that abstractions have to do some interesting gymnastics to jump to the next paradigm. Gymnastics means code and data, and code and data mean additional performance cost. A Wax application has four levels of abstraction about the "native" environment. That's why (on my machine) a Wax version of "Hello World" has a memory footprint of many megabytes and takes about five seconds to start, while a bare-metal Win32 version written in C eats less than 50KB and starts in under a second.

wxWidgets was written over a decade ago as a cross-platform toolkit for C++ programmers, so it implements what C++ programmers in the 1990s needed (like a string class, cross-platform sockets, and the Windows CBT hook hack). wxPython is a Python binding for wxWidgets, which means it can rely on some well-used and well-tested code, but it brings along parts of wxWidgets that Python programmers don't need. And Wax is a more idiomatic API on top of wxPython, but it, in turn, has to bring along parts of wxPython that it doesn't need.

I'm not knocking any of the libraries (or their authors). Each decision to adapt the previous library was a good one, in its own context. But it adds up to a tall library stack with a big footprint.

On the other hand, if someone got the itch to take something like the Wax API, and implement it more directly (say, with ctypes interfacing to the native toolkit)... that would be cool.

Wednesday, January 05, 2005

Joel on College

I have a love-hate relationship with Joel Spolsky. I disagree with him as often as not, but his most recent essay, Advice for Computer Science College Students, is better than most.

As usual, the essay is a mixed bag, but on his last point (getting a good internship), I agree completely. After my third year, I interned with a small startup company. This was way before the Internet bubble, so working for a small company wasn't the "in" thing to do--people favored either research internships at the university or else internships with big companies like Andersen or IBM. I didn't even find their product that interesting at the time--I was looking toward UNIX system administration as a career, and they were developing the first software-based video editor for Windows.

But it broadened my worldview. I found out why source control is important (they didn't have any). I found out why microecomics is important (hint: make sure your company can make payroll). I found out that compilers don't give partial credit, and that real quality matters, because released software has a longer lifespan than homework assignments, and customers and magazine reviewers grade a hell of a lot harder than bored TAs.

In other words, the real world isn't your BSCS program, and I learned that a lot faster in a small company than I would have at a cushy Fortune 500 internship.

It was also the best career move I've ever made. The three-programmer and two-intern company turned into a one-programmer and one-intern company by the end of the summer (the other programmers left for greener pa$ture$). The president asked me to stay on for a year, and after we presented in the Microsoft booth at Comdex that fall, Paul Allen bought the little company, and me along with it.

So I'd add to Joel's advice: get an internship, but make sure it's one where you're not insulated from reality. Lots of companies put their interns in the corporate equivalent of a padded cell. They let interns write some low-impact code, do some random-monkey testing, or handle some scut-work that isn't cost-effective to have a more senior programmer do. But an internship at a small company that's just scraping by will expose you to the real world, and the insight and bruised knuckles you get there will give you a real advantage over your blue-suited entry-level colleagues.

Web games and Tsunami Relief

Web games seem to be the last bastion of the days where "one designer working in a garage" could create something great. Content and marketing budgets are miniscule, you don't need ten thousand players to break even, and the technological and licensing barriers to entry are low enough that one guy with a good idea and a lot of energy can create a great game.

I've been playing the web game Carnage Blender for about a year and a half. It's got a small but very loyal player base, and in-game items sell for hard currency as well as they do in the big boys. But the real secret to CB's success seems to be the game community. CB is the only web game I've seen that incorporates live in-game chat. That leads to real ties between players, and a real sense of community. The strong community sense lets them get away with pretty strong community behavior guidelines (even chat is kept to PG standards). There's no artificial reputation metric, but all player behavior is transparent--not only is everything logged, but every player can see what every other player is doing, so reputation really matters.

After the recent tsunami disaster, the CB community pulled together in a big way. In-game cash and items were donated, and then sold for real currency to donate to disaster aid. In less than a week, over $24,000,000 in-game dollars were converted to almost $200 US, which will be sent to OxFam for disaster relief.

This is even more amazing considering that the game world in which the donations were taken is being wound down in favor of "Carnage Blender 2", which launched at the beginning of the year. CB1's exchange rate, usually steady at US$10 to CB$1M, dropped to about US$4 to the million the previous week, but people stepped right up to buy game cash at higher exchange rates because it was going to charity.

Danielle Bunten Berry once told me that online games have to have two things in order to be legitimate: the game itself has to be solid, honest, and fun, and the community around the game has to gel.

Carnage Blender has both. In spades.