Monday, November 29, 2010

Mendocino Matsutakes


Immediately after sleeping off my Thanksgiving food baby, I awoke to drive off to Mendocino to participate in David Arora's Thanksgiving Mushroom Foray weekend. It was an awesome gathering of 60 or so folks all focused on learning more about, and of course picking and eating wild mushrooms. I spent a lot of the weekend chatting with Dr. Ryane Snow, my foraging mentor - and if you ever want to learn more about the art of being an outsider, it would behoove you to spend some time with this great individual.

Anyway, as a follow up to my post last year at this same time - My Most Memorable Mushroom Hunt - I present to you a photo of my weekend gems, found in exactly the same area as my find last year. These are all #1 Matsutakes, with their partial veil still fully formed. In Japan matsutake are apparently given as new year's gifts as symbols of freshness and growth and good luck. These are on top of an amazing screen print by Ashley Veselka commemorating the season. May it live on!

Sunday, October 31, 2010

Catching the DeadlineExceeded error on App Engine

One of the neat features of App Engine's db interface is the way it allows you to request multiple items by key from memcache or the datastore, in an effort to improve performance of RPCs. This can have an unintended consequence though if you don't think about failures during iteration. In Browserscope's code base we were previously doing the following:

  stats = memcache.get_multi(browsers, **memcache_params)
  for browser in browsers:
    if browser not in stats: 
      # If we didn't find this key in memcache do some datastore call
      medians, num_scores = test_set.GetMediansAndNumScores(browser)
  # Update memcache with any new key/value pairs in the data structure
  memcache.set_multi(stats, **memcache_params)

The problem is that we were encountering DeadlineExceeded errors walking through the list of browsers when getting large result sets back from datastore calls to GetMediansAndNumScores(). Worse than a DeadlineExceeded error is doing nothing to prevent another one. Conveniently you can catch this in a try/except block on App Engine and then do something smart - store the state of things in memcache so that the next call doesn't start from scratch on a mission it will never complete. The updated code looks like this:

    from google.appengine.runtime import DeadlineExceededError
    dirty = False
    stats = memcache.get_multi(browsers, **memcache_params)
    try:
      for browser in browsers:
        if browser not in stats:
          dirty = True
          medians, num_scores = test_set.GetMediansAndNumScores(browser)
    except DeadlineExceededError:
      # Try to get what we've got so far at least in memcache.
      memcache.set_multi(stats, **memcache_params)
      logging.info('Whew, made it.')

    if dirty:
      memcache.set_multi(stats, **memcache_params)

This is just a cool pattern of defensive programming, and thankfully it works because the DeadlineExceededError allows for a short time secondary deadline where you get a little time to do a little work (like write something to memcache, as opposed to the datastore).

The end result of this is that test result tables in Browserscope should be delivering more consistently and more quickly - and if we respond with a 500 once, we at least might not have to on the next request. One thing I'm wondering about is adding a redirect to this process to try to run the process again - it will eventually succeed.

Tuesday, August 31, 2010

HTML, CSS, and JavaScript from the Ground Up

One of the efforts I've had the most fun working on at Google was a class that Greg Veen, Ryan Carver, Sean McBride, and  Dustin Diaz put together for Googlers to learn more about HTML, CSS, and JavaScript from the UX perspective. That class has, at long last, had its contents made public (at least the screencasts anyhow). I'll be having a Manhattan tonight in celebration of all our hard work paying off =)

Check it out here: http://code.google.com/edu/submissions/html-css-javascript/

Sunday, August 8, 2010

Detecting IE Platform Preview (and User Agent detection) on Browserscope

On Browserscope we've recently encountered the conundrum of wanting to detect the IE Platform Preview branches and the fact that that information is not in the UA string. Right now, just using the new and improved IE 9 UA string offers no way to detect that someone is using a Platform Preview and also no way to tell which of the 4 previews they are using. Fortunately one can detect this stuff using Javascript, but this forced a rewrite of how we handle UA parsing in Browserscope such that we now can send in overrides for each of the fields we care about for a browser at present - the family, v1, v2, and v3 bits. The code is checked in here in case you have a better way of doing it to share. Thankfully, the IE team is doing such a great job documenting the improvements from release to release that it isn't too painful to get this detection right..

You can also check out this code in action on our UA parser test page too and if for some reason your browser isn't being correctly detected, let us know and we should be able to figure out how to get that right.

All of this though brings me back to the fact that there's really not a great, bleeding-edge accurate, user agent parsing library available today that I'm aware of. The best ones out there at present that I know of are browscap.ini and useragentstring.com, but neither of these offer the detection library itself nor are they community maintained and bleeding-edge up to date. There's also WURFL, though it's more about offering a database of capabilities than a universal browser detection tool. Is there something else out there that you know of that's good?

I still have this fantasy of a client library, written to use and cache an ordered list of regexes and patterns for detecting browsers - it would be so cool if this list could be distributed by pubsubhubbub and then any one could host their own, augment the format, or just contribute their changes back to an open source project. Do you know of anyone looking for a fun, meaningful 20% project?

Thursday, June 24, 2010

Velocity 2010 Browserscope Talk Slides

It's a great time for web performance folks here at O'Reilly's Velocity conference in Santa Clara, CA. With talks that correlate performance to dollars and efficiency, it's easier that ever to value website performance.

The slides I'll be presenting for Browserscope are here below.

Thursday, May 20, 2010

XmlHttpRequest.getAllResponseHeaders and Content-Encoding in IE7 & IE8

A couple of weeks ago we tried to change how our Browserscope Network test for GZIP works and the other night we ran into something peculiar and unexpected - IE7 and IE8 strip the Content-Encoding header for GZIP responses if/when the browser has decoded the response (which it should have). Reading the spec for getAllResponseHeaders, it looks like the only headers which ought to potentially be stripped are Set-Cookie and Set-Cookie2.

The reason this was interesting/annoying is that we were trying to do something other than simply test whether the browser says it can handle GZIP responses (via the Accept-Encoding header) -  we wanted to see if Google App Engine was actually returning a GZIP compressed response, in this case for a static CSS file. Looking at the headers from a packet sniffer it was clear that the Content-Encoding header was coming down the wire, but then in JavaScript - it had disappeared. Amusingly, IE6 showed the Content-Encoding header as being present.

When a user-agent decodes a GZIP response do you think it should strip Content-Encoding header from getAllResponseHeaders()?

Tuesday, May 18, 2010

Ubuntu Lucid Lynx w/ Gnome on the Lenovo T410

Maybe it's happened. I've been using Gnome without dying to switch back to fluxbox for like 3 weeks now. The degree to which I can get Gnome out of my way, combined with the fact that some of its niceties no longer seem janky, unpredictable, or brittle... Dare I say I may be converted?
Also, Lenovo's T410 - this may be by far and away the best laptop I've ever used. The peripherals are in good locations - they moved the stereo jack over to the side (where it belongs, it was very peculiarly in front on the T400), moved the phone jack to the back (what's a modem?!), added a powered USB jack, 4+ hours of full screen battery life, and most importantly - I can actually use this thing on my lap!
Ubuntu has made some serious strides with Lucid Lynx. My typical gripes about gnu/linux (audio, suspend, wireless, etc..) are all fading and the configuration and usability of the system seems recommendable to your average consumer - I never thought I'd see it. Wow. Ok, so let's see how I feel in three weeks ;)

Sunday, April 18, 2010

User Tests in Browserscope

It seems like nearly every week we read about an interesting new hosted test for people to visit and run their browsers through (recent examples include html5test.com and findmebyip.com). Developers really love to poke at the black boxes they code for - and the matrix of browsers, OS, and networks is enormous. One thing I, and I presume other developers, would love to see are the aggregated results for these tests by user agent. Considering this is exactly what we built Browser to accomplish for our test categories, and that a user-hosted test feature has been on our Roadmap, the Browserscope team is happy to announce that we're opening up an alpha of our User Tests feature.

Conveniently, this past week a User Tests use case came up for me at work and so it's been a driver for building this feature. We began working on a UI component that we wanted to test for speed of task completion. After building up a test page with a timer and some deltas it dawned on me just how cool it would be to open up this test to the world, and aggregate the results. The test is kind of strange in that the the UI component is out of its context, and you can argue about the mechanics of the test itself, but I still feel like the results may be informative. Interestingly too, this test is exactly the kind of thing we would *not* want to feature on the homepage of Browserscope (it's more of a performance test than a spec/binary test). And yet, the backend system with its median aggregation, scalability, and user-agent parsing library is a perfect fit. So check it out - and see how other people are doing on the test (courtesy of Browserscope).

This is definitely a release early/often feature, and we want to be explicit that things may change or break in the API while we're in alpha mode. We may have to take the service offline briefly to fix things. But if you write tests for browsers and want to aggregate your results, sign in to Browserscope, register your test page and then read the HOWTO to start saving your results in the system. Please send any feedback to me or to our mailing list. We really hope to make this an easy system to use for the tests you're already hosting.

Friday, April 16, 2010

Production versus local development w/ App Engine - pychecker to the rescue!

This has been a furious week of coding, staying up til 3am, and banging my head on the keyboard. I wish I could say that in the end I feel like I was extremely productive, but there is the voice of rationality in the back of my mind saying I could have done much better.

I've been working on the Browserscope code base to add a feature to make it possible for users to run browser tests on their own servers and then make use of the Browserscope to store their results, download their results, and display their results with ease. We've worked really hard to build a system that should scale and maintain runtime medians (thanks to slamm). It seems like every week I see two or three new browser tests online and yet I don't see people collecting and aggregating the results in meaningful ways. It's hard! Hopefully we'll have this live for people to bang on in the next couple of weeks.

Meanwhile, I want to braindump a few lessons learned the hard way. After four days of intense development using dev_appserver.py I decided to deploy my code to a test app_id and see how it ran in production. I was rather miffed to see that my code was not working, and/or intermittently failing. That is pain.

My debugging experience led me to cut and paste Tracebacks (when I got them!) into Google to look for errors with django's urlresolvers.py file, and a seeming inability to load my custom_filters. But that didn't make much sense to me, and I could find nothing to fix in that regard. So then I started seeing errors about importing modules. And I couldn't reproduce them locally. Pain.

My officemate slamm suggested that I try using the built-in django with App Engine instead of appengine_django. This led me to start rewriting our main.py file. Fortunately, Guido's rietveld app is online on Google Code and contains a, in his own words, battle-worn main.py file which loads Django 1.1. After a fair amount of refactoring and generally feeling like I was making progress (I stopped seeing the errors about my custom_filters not loading after moving the add_to_builtins call into my main.py file), alas, I still kept getting errors loading some module that I could not explain.

So then I found a post in the Google Group mentioning that it can be troublesome to name your modules the same as any of the python system modules. Sure enough, I'd just created a new directory module named "users" (a pretty common directory one might have in a webapp). I got into a python console, and bingo - import users - loaded! Wow, so I then tried to import every directory and filename in my application. What a headache, but in the end, the only one I had named the same as a system module was users. Ok, so refactor and search/replace, not too big a deal. But it didn't fix my problem. Incidentally, Guido explained to me that the reason it is bad to name your modules the same as python system modules is that the sys.path in production puts your application directory at the END of the sys.path, while on dev_appserver it is on the front of the path. So that at least would explain why code that works in dev_appserver would not work in production if indeed you make this mistake. Apparently the fix is non-trivial, but at least it's in the "known-issues" list.

So I decided I had to have a circular import problem. I could come up with nothing else. And finding a circular import is pretty hard, following every import down a tree is very mind-challenging at 3 in the morning (as your app spews 500s). Searching for tools to help uncover recursive imports, I came across a mention of a tool called pychecker online (although it sounds like it has generally been deprecated by most in favor of pylint). Anyhow, I added a bunch of directories to my PYTHONPATH environment variable and ran "pychecker main.py myhandler.py" and bingo! "Error importing module foo". I could reproduce a problem! And it only took about 5 seconds for pychecker to run.. which is significant since my prior debugging path included making guesslike changes to my code, and redeploying (which takes more like 25 seconds) and praying and then banging my head. I found my recursive import, fixed the issue, and wow - no more 500s (well, except for the dynamic request limit ones).

Anyway, I just wanted to post this in case anyone starts searching and finds this post useful. Happy coding!

Tuesday, March 9, 2010

Browserscope in External Bugs

Annie Sullivan, of our colleagues who wrote the Browserscope Rich Text test suite, let us know today that there are now two issues filed in Webkit and Firefox to track progress in rich text editing by using her Browserscope tests. In webkit: https://bugs.webkit.org/show_bug.cgi?id=35904, and in Firefox: https://bugzilla.mozilla.org/show_bug.cgi?id=550569. Steve Souders' Network test suite is also mentioned in a few different bugs for both Firefox and Webkit. This is *exactly* the kind of effect we'd hoped to have when building Browserscope and it is a testament to the depth and value of these two test categories that they are to be found in issue trackers for the browser vendors themselves.

We'd love to see this trend continue, and we'd also love to see Browserscope integrated into the continuous builds and test systems employed by browser vendors. Conveniently, vendors can easily run their own private Browserscope instances just for this purpose, which speaks to the benefit of using App Engine for something like this. Recently I've been chatting with some folks on the W3C about porting some of their test suites over to Browserscope as well, and hope to have some interesting news in that department soon ;)

Thursday, February 18, 2010

Updates to the Browserscope Security Tests

Since the launch of the security test suite on Browserscope, the team who owns those tests have been busy taking in feedback and deciding what to change and what their criteria should be for those changes. Security is a loaded term, and Browserscope aims to be a particular sort of resource - part benchmark, part feature-checker, and part-resource. Collin Jackson has written a great explanation, titled What Makes A Good Browserscope Security Test? His post provides details about all the new changes to the security tests that went live with today's Browserscope push as well as provide some context for how the team made choices about what to change. 

From his post:

Our goal for the Browserscope security suite is to encourage openness and innovation in browser security. Here are some of the essential elements of a good Browserscope security test:
  1. The test should check for a behavior that makes the web a safer platform for developing web applications.
  2. The test needs to be able to run without user interaction.
  3. The behavior should not yet have universal adoption among popular browsers at the time it's added to Browserscope.
  4. The test should be applicable and realistically attainable for all major browser vendors.

With the exception of rule #1, the last three are right in line with the conversations that the Browserscope team has had about what sort of categories we want to have tests for. I think every category owner should be able to come up with their own rule #1 as the description and justification for their category.

Big congratulations go out to Collin Jackson, Adam Barth, Mustafa Acer, and David Lin-Shung Huang for translating their thoughtfulness into code which should help inform users and developers when making choices about which browsers to use and which browsers are more secure.

Friday, February 5, 2010

Re-Recreating the Button


This post owes its inspiration to Doug Bowman's excellent post from about 1 year ago, titled Recreating the Button.

What's changed since Doug's post?

  • -webkit-gradient and -moz-gradient(>= FF3.6) support for backgrounds. (IE has had the Gradient filter since 5.5)
  • -webkit-border-radius and -moz-border-radius work pretty much flawlessly, and degrading to square corners is currently in vogue.
  • I've seen several projects implement this div/span button implementation when a native control would be much more appropriate.

So using the spec that Doug and others came up with, I wanted to see how close I could get to it using un-nested anchors, spans, and divs, but much more notably - native inputs and buttons. JavaScript buttons are fine, but native buttons can degrade. There's few things as horrible as clicking a form submit button and having nothing happen due to a JavaScript error. The implementation has not been all that easy in the end. Many times I've thought I had it only to be thwarted seeing the result in some other browser and going back to the drawing board. For now I've got a CSS file and a unit test page which represents what I'd like to achieve and how close (and sometimes how far!) I am to getting there.

I'll continue to update the test page as I hear from folks about what is and isn't breaking, but in the meantime, I'm happy to report that the test is passing on all A-grade browsers (with the exception of Safari on Mac - hopefully some nice Mac folks can clue me in on what to change to get it working I am not sure about Mac, but Safari 4.04 on Windows passes all the tests now).

The test page shows off something I've found really helpful as a UI developer: unit testing of computed styles in different browsers (in this case, making use of closure-library's goog.testing.jsunit module). Having a page like this makes it much easier to discuss and document anomalies and provides a lot more assurance when making adjustments. We all tend to test our work in one browser and then go through the process of making tweaks for others, but it's crucial to be sure that a change for one doesn't botch something in another. Specifically, this page documents a few use cases that I didn't originally set out to solve, but which now seem like big wins - namely, the icon-buttons as well as the buttons in fixed width containers. Of course there's no way to unit test for everything. Many of the browser-specific tweaks to the padding are specifically for visual consistency inside the button, so testing the padding would be a joke. To that end, I have to plug the free Adobe BrowserLab, which I used constantly while developing this code.

This is still something of a work-in-progress, but you can look forward to seeing these buttons, and some correspondingly styled select elements, in the next App Engine Admin Console release and ultimately the closure-library.