natevw proudly presents:

a glob of nerd­ish­ness

powered by work over time.

48 hours in Portland

Colors out the train window

I rode the train in and the bus back, visiting Portland from 10am on Tuesday to 10am Thursday. The weeks before had been busy too: I didn't even get a chance to join the local Tri-Cities co-working group, being heads down in client work and conference calls. Taking public transportation down the river to a very public town was a good reminder of how community matters — both the tech community and the wide world it should serve.

I was struck by how lovely life can be in a town like Portland — warm coffee shops everywhere, so much fine food and drink in every district, and such useful book and tech and music shops scattered all over, all bustling with interesting and amiable people. And how empty a city can still be — the streets are littered with people who have so blantantly lost or tossed every benefit of society except the worthlessness of its loose change.

So I'm grateful to the many people who helped Portland feel not-too-far from home during my time there:

Portland's a great place to get offline but stay connected. Though it's good to be back home, I was blessed to visit again.

comments

Time zone "picker" interfaces

Time zones pose an occasional software localization challenge. Assuming your software needs to include this as a configurable setting (more on that below), what's the best way to help a user choose a time zone?

The problem is, there are a lot of time zones. A lot of time zones, most without a naturally elegant identity or universally understood name. Time zones were designed be mostly unthought-of: invented so most people wouldn't have to worry about the effect of longitude on time. Within a time zone's geopolitical boundary, there's little need to think or talk about time zones.

As we'll soon see, timezones are very closely tied to location. People may not know the official name or relative offset or exact boundaries of a particular time zone, but they understand that there is one for any particular place.

Collected examples

To see how a user might expect us to solve this interaction problem, I've gathered a variety of "time zone chooser" examples.

Original Mac — circa 1984

Screenshot via http://macfloppy.net/post/18502052008/susan-kare-designed-the-original-macintosh-control:

Susan Kare's original Control Panel design, includes basic time setting

This is the Control Panel in the original Macintosh operating system. Note how the user sets the time zone: they don't! A personal computer was more of an island back then; a user set "the" time (their time) and that was that.

Windows 3.1 — circa 1992

For Windows 3.1 applications — remember Netscape Navigator 2.0? — a user would set their timezone configuration via a variable in AUTOEXEC.BAT:

SET TZ=aaahhbbb

For interfaces of the "Application Programming" sort, this general approach is still reasonable. Identifiers referencing rules in the Olson database are preferable to the ambiguous local three letter abbreviations and manually-configured offset values needed here.

Windows NT 3.1 — circa 1993

Screenshot via http://www.guidebookgallery.org/screenshots/winnt31:

Early Windows NT time settings dialog

While I haven't been able to find a screenshot of this dropdown when expanded, from the looks of things it was sorted by GMT offset (see how there's multiple cities listed in the chosen option?).

Newton OS — circa 1993

Screenshot via http://cs.gmu.edu/~sean/stuff/n800/:

Newton OS city-based timezone map

The Newton — a PDA that goes wherever people need to communicate — needed to know about timezones. Already we see a map, and an interface based on locations (major cities) rather than the underlying timezones. Since it's somewhat natural to associate time zones with a list of "nearby" major cities, why not use a map to narrow down that list? Tapping the map pulls up a short list of cities near the stylus.

Windows 9x — circa 1995

Screenshot (s) via http://www.petri.co.il/summer_clock_in_israel_for_2006.htm:

Windows 9x dropdown showing time zones ordered by offset

Windows 9x time zone map

These screenshots confirm my theory of how Windows NT's dropdown worked. There is a map, presumably clickable, but it doesn't actually seem to show the selected timezone. Apparently, there's a reason for that.

Mac OS 9 — circa 1999

Screenshot via http://www.guidebookgallery.org/screenshots/macos90:

Mac OS 9 list of cities

By Mac OS 9 we again see a list of cities as the interface to the underlying time zone database. The key takeaway is that a user is only expected to know and find a nearby major city in their timezone — there may be more than one city listed per timezone. This reduces the geopolitical knowledge (and guesswork) necessary to find a suitable setting. Just because I share the same time zone rules as Los Angeles doesn't mean it would come to mind as representative of my locale.

Windows CE — circa 2000

Screenshot via http://h20000.www2.hp.com/bizsupport/TechSupport/Document.jsp?lang=en&cc=us&taskId=115&prodSeriesId=322914&prodTypeId=215348&objectID=c00009393:

Windows CE time settings

Windows CE provided a similar dropdown interface as Microsoft's early desktop interfaces (although certain cities were grouped differently). Note the easy affordance made for switching to a temporary timezone while traveling.

Garmin eTrex/Foretrex — circa 2004

Screenshot via http://www8.garmin.com/manuals/Foretrex201_OwnersManual.pdf, p.44:

A simple timezone dropdown in Garmin Foretrex menu

An "embedded operating system" for an older device with limited screen space, limited processing power, and limited input surface has a limited solution to the problem: a listing of perhaps two dozen or so world cities (…Samoa, Sydney, Tehran, Tokyo…) followed by the named US time zones. There's also an "Other" option enabling the user to set a custom ±hour/minute offset from UTC.

Note generally that trying to tackle the "time zone" problem with only this last option (forcing the user to manually specify their local time offset) would be broken in at least two ways: it expects the user to know this offset which is usually not the case, and it requires many users to manually change the setting twice a year. (It's broken in three ways if you assume that every time zone is offset from the meridian by whole hour values. Only most, not all, are.)

Web 2.0 — circa 2005

Screenshot of http://www.fogcreek.com/fogbugz/:

Windows-like dropdown

Here's an example of a web app making use of an offset-sorted dropdown in the Microsoft style.

Mac OS X Leopard — circa 2007

Screenshot via http://rubenerd.com/p2370-2/:

OS X Leopard's clickable timezone map

Mac OS X also let the user select their approximate location via a world map, as we saw early on in the Newton OS. Again, the advantage is: rather than having to think of a major city to search for, the interface shows the options near me — I just have to pick the one I feel is most appropriate of the three or four nearby options.

Garmin nüvi — circa 2007

Screenshot via http://www.gpsmagazine.com/2007/06/garmin_nuvi_250w_review.php?page=7

Early nüvi time settings

To be honest, I'm not sure what happens when you press the time zone button. The manuals for many nüvi models say "select a time zone or nearby city from the list", so I think it's safe to assume that this updated hardware still relies on the same limited interface as Garmin's older outdoor GPS units above.

World Wide Web — circa 2009

Screenshot via http://dribbble.com/shots/89371-Me-com-Time-Zone-Picker:

Me.com time zone map

Web apps can show maps too. Here's one (kind of rough perhaps? I'm not sure what's going on with the two different highlights…) from one of Apple's ill-fated Me.com web apps.

Garmin nüvi — circa 2011

Screenshot via http://www.pocketgpsworld.com/Garmin-nuvi-2360-reviewed-37558.php:

Newer nüvi model showing "automatic" time setting

GPS receivers know the exact time in UTC and the users' very precise location — the device can use this information to simply set the local time automatically. Many cell phones offer a similar user experience — the phone simply displays the local time of the (nearby) tower it is currently connected to.

America-Wide Web — circa 2010

Simple dropdown from a client's US-only web app

Sometimes you're only localizing for a limited geographic area. In this case, a web app was built for a service only offered in the United States. It was possible to list common names for the small handful of time zones the app needed to support.

Mac OS X Lion — circa 2012

Lion's map in fully automatic mode

Recent versions of OS X compare the signal strengths of WiFi routers in range to a database of wireless base station locations to get a fairly precise location fix. Like the nüvi example above, this allows a fully automatic time zone setting. If necessary, the user can still override the setting as in previous versions, by clicking the map or typing the name of a nearby city. In fact, since the preference pane now uses an Internet API to look up the city, it offers a fairly comprehensive list including even some smaller cities.

This interface offers a great deal of flexibility, all centered around the helpful perspective of time zone ("local time") being strongly related to location.

General and perhaps Timely advice

Of course, the best interface is no interface. In a few cases — be careful to make sure yours is really one of them — you can ignore time zones altogether and just deal with local times. In many other cases, you can rely on time and calendar–handling facilities built in to your software's underlying platform. If the user's operating system is already configured to display their local time, it's best to use those APIs whenever possible. Store precise moments of time in a timezone-neutral format like Unix timestamps or alongside their original offset as possible with ISO 8601/RFC 3339 time strings, and convert to local time only when displayed. This often works for web apps, too; you can set a JavaScript Date object using a UTC timestamp and get the calendar values back in the user's local time.

Aside: As a general rule you should never, never attempt to handle applying the chosen time zone information yourself. (You shouldn't be implementing any calendar-based calculations yourself, for that matter.) If you would have to change your code or its configuration to handle a local legislative change to any sort of calendar or timekeeping system — and your work isn't part of a major operating system's platform — you're most likely doing it wrong.

Summary

There may occasionally be times (usually when a shared machine needs to interpret or localize times on behalf of a remote user) that your application must let the user configure a time zone.

If you need to stick with a simple dropdown, grouping regions with shared GMT offsets and DST rules and then ordering by the base offset (basically: longitude) can work. Many examples above do this. (However, avoid simply presenting the user with a list of every time zone in your platform's database. Even if you've managed to filter out the historical ones!)

If you can provide one, a clickable map is better. Include alongside a small database of major cities, or reference a more complete set of populated place names. Try to familiarize yourself with the nuances of the best interface examples above — situations where the user clicks near more than one time zone, other cases where the user would prefer to fine-tune the choice of city, and perhaps other aspects I've missed. Accessibility should also be a concern — how will the user choose a time zone if they aren't very good at seeing or clicking?

And finally, if you just want to convert between Every Time Zone, well…follow that link. Or if you like screenshots of old operating systems, you'll love the GUIdebook website.

Oh, and of course I'd love to hear about other unique and interesting solutions to this "time zone picking" problem if you have some!

comments

Metakaolin's GeoJSON editing interface for Polymaps

Late last year I designed and implemented another core piece of any GIS system: the geometry editing interface.

The core part of Metakaolin (a CouchApp for "map documents") is a GeoJSON editing layer for Polymaps which I wrote. This was an interesting design challenge, but I'm encouraged by how it's turning out.

Basic goals

Existing map editors weren't very inspiring. It seemed the most common interfaces were the most clunky. I wanted to build something that had the web at its heart, that was uncluttered but still learnable, non-modal but still powerful.

How could I edit a polygon (say) without having to keep switching between this tool and that tool, or trying to remember which modifier key changes what on whose operating system, or always forgetting to double-click when placing that last point to make it connect properly to the first?

Early sketches of multitouch-compatible vector editing experiments

I began imagining, sketching and prototyping some ideas for polygon editing — thinking about how they would translate between mouse and multitouch and trying to figure out how they would also work for unclosed lines and plain old points. The ideas I started with were fun to use, but I was having trouble wrapping my mind around where to stick every action you'd need just to edit a single polygon. Then, how would it make you choose between polygons and lines and points? And compose multiple related shapes into one geometry?

Secret sauce

The "a-ha!" moment came while re-reading the GeoJSON spec to get a handle on everything I'd need to support.

I was struck by how flexible the format is. Each feature in a collection can have a different kind of geometry than the next. There's even geometry type that can be used to nest any combination of point, line and polygon shapes. How would I support editing a complicated geometry collection like that? It basically means the user can just draw whatever they want!

Hmmm. Well, why not?

Why should we have to tell the computer "watch out, I'm gonna draw a polygon!" before just drawing our enclosed area? "Computer, now please switch to the mode where the next shape will have the 'type' set to 'MultiLineString' instead." No! No! No!

Maybe the GeoJSON format isn't so complicated as I thought. Maybe it's simply designed to be invisible.

Embracing this meant the only concepts which people (and most of the code, too!) really end up needing to worry about are just simple dots and dashes. (Called "nodes" and "connections" in the code.) I can move and merge the dots, disconnect or connect them with dashes. When I'm done, a simple invisible algorithm can worry about how to represent what I drew in the underlying GeoJSON format.

The result

Drawing Silly Ships in the Mighty Columbia

My solution is not 100% "intuitive"; with the right contextual tips, though, I think it will be easy enough to learn, fun enough to use, and hard enough to forget. You can try out a live demo — the main tricks are:

Interestingly, these instructions are still hard for me to explain, but they've always been easy to demonstrate. I'm not sure if that's good or bad. I'd prefer if it were completely self-explanatory, but perhaps there's something to be said for fun interfaces that trade a little learning curve for a lot of power.

Going forward

While I've mostly just drawn trucks for my kids and ships for demos, I'm delighted that a few others have already used pieces of Metakaolin for their own ideas. Max Ogden converted some of his geodrawings into a Valentine's card, and Brian Mount has applied it to a maptcha experiment and a civic collaboration app called CityEdit. I'm especially excited about CityEdit, as it's just the kind of thing I had hoped CouchDB, Polymaps and Metakaolin's editor would be useful for!

There's still plenty of work to be done. For Metakaolin-as-its-own-app itself, the ability to edit feature properties (and colors/style perhaps too) is probably important. For the reusable editor layer, the overall "look and feel" definitely still needs a little…je voudrais savoir.

Oh, and one more thing. I mentioned it briefly, but: multitouch support! It should be fairly easy to add, as I've architected for it, just haven't gotten to it. Imagine combining Metakaolin with PouchDB so it can run offline on a multitouch tablet with GPS. You could go to a state park, or out to a remote plot of land, or even into a disaster area and map whatever needed to be mapped.

See, the "document management" part of Metakaolin was actually yoinked from a simple text editor I had written earlier. I would love for jotting things down on a map, or putting together a complete geographic report, to become about as easy as sharing "typed up" files is today. I hope that this GeoJSON editor is a big step in that direction.

comments

Tracing the scenic route

Or: how following a silly little meme might involve digging through lots of source code, building out a new Linux server, reviewing several IETF/W3C standards, and filing multiple bug reports.

Such a simple idea

Within an hour or so of joining the Room to Think co-working group here in town, I was introduced to a strange Internet meme. I still don't know the first thing about the trend itself, but there are a bunch of animal-themed sites that show you some ads and tell you your public IP address: ipchicken.com, iprooster.com, ipgoat.com, ipcow.com…

Given that my own company has an animal in its name — and likes Internet Protocol! — why not see if IP Calf was still available for adoption? Yes. It was! What would I put there?

Back in its Mac/iPhone shareware days, Calf Trail Software, LLC had a kind of nostalgic brand — NOT showing ads for one, and building software that maybe wasn't shiny but designed to serve its purpose in a straightforward, user-friendly way. I don't always check my IP address, but when I do, I prefer this kind of experience. (Looks like the guy behind http://iphorse.com invented the same idea before I did. But Horse Trail Software doesn't have the same ring to it now does it??!) Anyway, just a simple What Is My Public IP Address? site, mostly "just because".

So it began…

Getting http://ipcalf.com/ into production

  1. The basic code took barely more than a minute to write. I added a new show function to whatever CouchDB project I was working on at the time, did one quick test to check that the client IP address is available, and then implemented it in the minimal way I had envisioned: function (doc, req) { return "Your IP address is: <h1>" + req.peer + "</h1> Have a nice day."; }

  2. My simple markup appeared as intended in my current web browsers, but I needed to take a quick look at the HTML5 spec to make sure I only omitted optional tags. My markup did appear to follow the rules. So let's get this thing into production! (Note below what I missed here, though...)

  3. If this thing's gonna be real, it needs to be a standalone project with its own code repository. That means setting up some quick boilerplate. For the old Python couchapp utility, this just means a .couchapprc file containing {} and an _id file with the design document's name. Now I can upload my JavaScript code from the new app's shows folder.

  4. I'll be using git for source control so I set that up too. Just a simple git init plus a local .gitignore so no one has to see those pesky .DS_Store files. Oh, and I'll be sharing the code on GitHub, so I should make a README explaining the project.

  5. As I type the documentation, I realize it would be cool to make the service a little more useful. Why not use content negotiation to serve a plaintext and a JSON version of the client's IP address? Then I could use this from shell scripts and node.js experiments! No worries, another quick few lines of code and now I can put a few interesting examples in the README.

  6. I should test the code examples, eh? Oh, I missed some braces when I typed up the JavaScript one. Oops. Still not working! Oh, right: I'm testing this in a browser, and it's a cross-origin request. No problem, I think there's just a little header I need to set.

  7. Skim through the W3C's Cross-Origin Resource Sharing spec and add an Access-Control-Allow-Origin: * header to my JSON response. Done!

  8. Hmm, still not working. Review the CORS and XHR2 specs more thoroughly. Aha! My Fermata REST client library is setting a superfluous Content-Type header on its GET requests. This header isn't whitelisted as a safe cross-origin header, which is why the browser is trying to obtain more extensive pre-flight permission before the actual fetch. After I publish a patch for Fermata, my README example now works great. Success! Ship it!

  9. I need a basic up-to-date, reliable public CouchDB server and that's exactly the kind of hosting IrisCouch provides. I've already set up a free account there, Hosting a CouchApp there is configuring a Virtual Host entry I register the domain and point its DNS records at my free account there.

  10. Oh no! IPCalf.com is live, but it's telling me my public address is 10 dot something something. The 10/8 prefix is reserved for private internets so this must be a load balancer or proxy inside of IrisCouch's hosting setup. I spend some time in CouchDB's source code to see if it handles the X-Forwarded-For header that's typically used in these kind of situations. It looks like it does, so I file a support ticket with Jason. He's on the case. But I'm on a roll here; I want to get this project wrapped up!

  11. I guess I'll use my own server for now. Lately I've been having trouble rebuilding CouchDB on my current barebones EC2 instance. It's running the default Amazon Linux, and I built it out before AWS opened new datacenters right down the Columbia from where I live. My devops ninja friend is embarrassed I'm messing with such a bad distro and I've been meaning to move my server closer anyway. So blah blah blah, I'll just spin up a new server. This time in the Oregon region with an Ubuntu-provided image. [gets it all set up, spares you the details]

  12. So now I have my own server, running the latest release version of CouchDB, and ipcalf.com is pointing to it. I try the examples in my documentation one more time, just to be sure. Hmmm, the JSON example is failing and in an odd sort of way. It works on my local machine, but not on the server. Am I doing something wrong? What's going on? It's getting late but I have to know!

  13. Trying this, trying that, finally trying to find how all the relevant underlying pieces in CouchDB are wired together. Getting closer, still not finding exactly what I'm looking for. Making mistakes, testing code changes without deploying them first, still looking for the answer.

  14. Finally, yes there's the code and that's the bug! Not my fault, but something I can work around. It's now past 3AM, over twelve hours after I decided I'd toss this quick little site idea online. Even if I can get it working correctly now, not many friends will be online to see it, so I guess I'll finish it up tomorrow.

  15. The next day I'm a little tired but ready for a fresh start. There's one other issue that's been on my mind, but I haven't finished dealing with yet. CouchDB has a nice built-in infrastructure that enables efficient validation of cached responses. The problem is, it's designed for more typical (stored data–based) use cases and can cause a user's browser to report a stale IP Address if they've visited the site earlier. As I worked on everything above, I'd started learning the ins and outs of caching in HTTP and experimenting with various header fields and redirect strategies that might help me avoid the situation. I continued to study how different browsers handle multiple ETag headers, noticing how only some browsers seem to cache redirect responses, and finally reached the conclusion that CouchDB needs modification before I can resolve this issue.

  16. So now I seem to have the site working as well as I can. I still need to follow up with some of the support tickets I've opened, bugs reports I've found or filed, and conversations I happened to spark while logging my progress on Twitter. By the end of the next day, I've finally got all relevant browser tabs closed and I have the project to a point where I can blog about it.

  17. That was yesterday. Writing up everything I did the last two days has been today's main project. I've been finding links and notes back, trying to describe what I did in a way that makes sense (or is at least moderately entertaining) to everyone who is interested in this experience but may have been learning about something completely different the last three days/decades.

  18. While boasting in step 2 above how much care I took to ensure my output was correct, I realized I should check to see what an HTML5 validator thinks of my markup. Whoops! I guess I still need to add something like "<!doctype html><title>IP Calf</title>" to specify the parsing mode and provide the required page title.

  19. Now I wonder: does the doctype really "specify the parsing mode" like I just claimed? Curious, I start looking into what this processing instruction meant in SGML, XML and what its practical implications are in HTML…

  20. I step away from writing for a bit. Realize this whole story would have been even more fun if it were presented as a branch's history log on github itself. Research the feasibility of an accurate retelling — can I override the commit timestamps to match what I would reconstruct from my browser history log? This idea grows on me. I dream of what wealth and fame the SHEER ARTISTRY of this idea could bring me. Wrestle with this new idea for much longer than it would take to just jump in and commit, weighing how much time it might take to do well against how fun it would be to pull off.

  21. Finally decide to just share this story as a regular old blog post, the same tired way everyone else shares their regular old stories. Spend a while brooding over how boring a person I must be and no wonder nothing I do ever stands out. Begin to feel guilty for wasting my time and yours with this silly little site that hardly made the world a better place and is not even much to look at.

The end of the matter

You might be thinking "wow, is programming always that hard?" or "that would have been SOOOO much easier if he'd just used _____".

No, and no.

Shipping product-grade code is never easy. You can spend minutes to make something work on your machine, hours making sure it should work in situations you may never have opportunity to test on, and days, sometimes, to figure out why it doesn't work in a situation you did test. But every time you do it, you beat a path behind you. It's a lot easier to build, analyze or debug something the second time.

And yes, in this case the tools I used were not the best fit for what I was trying to accomplish. Or were they?

Could something do everything this does in less (or better) code on a different (or better) platform? Sure! But I didn't choose CouchDB, I didn't first go to IrisCouch and I didn't end up using Ubuntu on an EC2 instance, because I was sure they were better than every other option for this silly little task. It might have been less time or less typing to accomplish the same thing in PHP or node.js. It might have been more. I might have had less to learn deploying on Heroku or Savvy Sally's "IP Address Website" Amazing Hosting Platform. I might have had more.

Every now and then, deploying three minutes of high-level code means I spend three days learning what's underneath holding things up. But more often than not, it takes me only three months to deliver something that might take three years in a typical enterprise. I'm okay with the former if it makes the latter possible.

In this case, the road wasn't as well travelled as I imagined at the start. I still don't regret taking it. Not only did I gain a lot of new experience for myself, but by discovering some pitfalls along the way I've made it easier for someone else to build better along that frontier. That "someone else" might even end up being me!

comments

New globs of bloggishness

Welp, here it is. It's pretty okay, I guess?

Have a pickup truck:

Map truck

comments


All posts

Subscribe