April 13th, 2008

  • evan

google app engine limitations

It's weird to see people talk about Google App Engine online because I think many people focus on minor details. Like, to make apps scale horizontally you do need a "shared-nothing" infrastructure, so that's not really novel. The BigTable aspects are sorta interesting except there's nothing there (in terms of application design) that you couldn't have gotten out of the paper, and the App Engine API is so high-level it's not that close to BigTable. It's more like any other high-level flat-address object database, like maybe CouchDB. The Python thing is also pretty irrelevant; they just picked a language they have experience with (having Guido around helped), and it's easier to launch supporting one API than n languages' worth. A good engineer just solves the problem with the tools available, and Python is a pretty good tool to start with.

As for evil plans to steal ideas or code, that's between you and your skepticism. Big companies are surprisingly good at doing shitty things, and Google is definitely big, but it's also true that within Google people really try to do the right thing. I was touched to see a privacy-concerned friend of mine start using Gmail after he was hired, saying that only after he saw how seriously they take privacy inside the company could he feel confident about using it. But I can't tell you anything that will change your mind about this subject.

I developed an internal application using Google App Engine on and off over a period of months (during its development I kept trying it out) and then finally rewriting a few weeks before launch (after the APIs had all settled).

Here are some real problems I've encountered:

1) All code runs only in response to HTTP fetches. So that means no cron jobs, and no persistent server-side processes. I know I just wrote above that you can't really have persistent jobs if you want to scale, but ultimately real apps do occasionally need these. For example, imagine a timed test app that needs a consistent view of time no matter which server (or datacenter!) the user hits. A time server becomes a single point of failure but when it's critical for your app it can be engineered around.

2) No long connections means no "comet" (server-push messaging).
My first thought on hearing about App Engine was to port lmnopuz but I can't.

3) Playing around with your data is hard. Since there's no way to perform operations on your data except by uploading code to the server, you're often left creating a new URL per operation you want to perform. Hacks like the shell helps with this, but a lot of the time I want to be able to just run a local script and see the output. (For my project I found a decent workaround: make a URL that accepts Python code as a POST and runs it. Then your scripts just need to know to serialize themselves into strings and send them over the wire.) But see the next point.

4) Slow table scans. My app had ~1200 rows that it performs various analyses on and produces graphs. I can appreciate that such a query is labor-intensive, and so I had written it to cache the results of the graph generation (the rows only change once a day). But I can't even seed the cache once because fetching 1200 rows is too slow to happen within a single query.

5) Bulk operations are hard. Say you want to delete all objects in a table (or class, I forget the App Engine term). The "delete" operation requires you fetch the object first, and then you're back into slow table scans land. The best you can do is batch up your processing into multiple smaller stages, each of which write their intermediate output into the data store: either make a page that auto-refreshes itself with Javascript and leave a browser pointed at it, or make a command-line script that repeatedly hits a URL on your app.

6) No arbitrary queries. (If you haven't read the docs in detail, you wouldn't know this, but any query that involves multiple attributes [columns, if you're still thinking SQL] of an object must have an index exactly matching the query. They make index creation and maintenance trivial, and even automatic in most cases.)
Though everyone's repeatedly shoehorned SQL underneath object-relational mappers, App Engine (and others) demonstrate that you can provide an object storage API and gain performance by not using SQL underneath. I argue the real utility of SQL is that it lets you quickly (in terms of programmer time, not machine time) perform queries that you haven't done before and won't do again. Say I learn about a bug where I built all of March's data with the word "none" in place of where a column should really be null (None in Python terms) -- that's a line of SQL to fix but it's a world of pain with App Engine due to the bulk operations thing.

With all that said, it's still pretty good. When I was looking to switch projects about a year ago, it came down to basically three projects and App Engine was one of them, because the guys who work on it are some of the best hackers I know at the company. All of the above bullet points (and minor stuff like the languages thing) aren't fundamental limitations of the design, they're temporary flaws that can be solved by good engineering and are surely being prioritized by the team. I'm pretty confident it'll improve rapidly.