Wednesday, December 29, 2010

Why I Love(d) Wave

Note: I originally wrote this post in August, but decided not to publish it until now. I've left the text as it was then.

As recently announced on the Google blog, Google has decided to discontinue Wave as a standalone project. As many of you know, I worked on Wave for the last year, as an advocate and support engineer for the APIs, and well, as you can imagine, I'm quite disappointed right now.

I know that one of our failings in growing Wave usership was the inability to properly articulate what Wave is good for, and I think part of the reason is that Wave can't be simply compared to any existing service. Wave is a flexible and generic platform, one that can be used for groups discussion, for diary entries, for event commentary, for surveys. Of course, there are existing solutions for doing each of those things - but there is not one solution that does all of them. The thing I loved about Wave is that I could start a wave about a topic, and that wave could evolve from a survey to a discussion to a photo album (like when I asked folks what color I should dye my hair next), or be a combination of all three at once. I didn't have to know at the beginning what it would be, I didn't have to carefully weigh all the different options, I could just start a wave and see what it became. There are of course reasons for using specialized tools, like when you absolutely must have pristine formatting in a Word Document, but when you're collaborating with your group of colleagues or community of developers, I've found it's better 99% of the time to have the flexibility of Wave than the specialized features of 10 different services at once. That's why I will find it hard to stop using Wave (and I hope I don't have to), because I would have to replace it with myriad different tools.

Because Wave is this flexible, we realized from the beginning that it should also be extendible, so that users could customize Wave for their own particular needs, and combine its conversational features with their own processes. Sure, you can do event planning with just text, but throw in a date picker gadget, RSVP gadgets and maps, and you've made planning that much more compelling. You can write your blog post drafts with just the native features of Wave, but after you throw in an approval gadget and blog post publishing robot, you've got a full blog post workflow in Wave, one that can be easily shared with your colleagues.

On the Wave engineering team, we had started to build extensions to streamline our own internal processes. For example, we have a system on the team where a different group of people are on-call each week, and it is their job to respond to the pages and alerts about server issues, and escalate them to other folks if they can't handle them. To supplement this system, we would create an on-call wave each week, and the on-call engineers could paste the alerts into that wave, ask questions about them, and anyone following the wave could discuss the alerts with them. To enhance this system, one of my colleagues wrote a robot that 1) created the new on-call wave each week on a chron job, adding the relevant people based on calendar entries, 2) added links to all the current server admin pages, and 3) pulled the alerts directly into the wave. So, now, we have what amounts to a semi-automated system, where a piece of software does what it's good at (bringing in structured data), and humans do what they're good at (conversing on top of that data). It really shows off the power of Wave to combine structure plus free-form conversation; to combine data plus humans.

In Wave developer relations, we built multiple extensions to enhance our interactions with external developers. For example, we have a gallery of third-party extensions in Wave, and since we wanted that gallery to contain only user-friendly extensions, we created an App Engine app for developers to submit their extensions to the gallery. The app worked okay for storing the structured data about the pending submissions, but it was not conducive to having lengthy discussions about various aspects of an extension. As soon as I got the chance, I moved the process to Wave. Now, developers create a new submission wave, a robot fills it in with questions and fields, they answer the questions and click a button to share it with the review team. We add our own comments, and then click a button that physically puts it into the gallery. With the new wave-based process, we can get into inline discussions about their answers, I can start up private replies with my colleagues to ask for their unfiltered opinion, and we can attach images to show what we see or would like to see in the UI. We ended up with much better extensions, because we were able to have such fast and meaningful conversations -- and we didn't lose any of the structured data along the way.

My job is all about communication and collaboration, and that is what Wave excels in. The more I used Wave, the more I saw how Wave could make my job better, and the more I fell in love with the power and potential of Wave. I hope that the ideas of Wave keep going, whether through other Google products or the ever-growing Wave open-source community, because I don't want to live in a world without them.

Tuesday, December 28, 2010

Triaging Issues: The Wave-y Way

Note: This blog post was originally written to be posted on the Google Wave blog, but did not make it out before the cancellation of Wave. I am posting it here in case it is useful to Wave open-source developers in the future.

In developer relations, one of our core roles is to respond to the bugs and feature requests for our APIs, and we do it both because hearing what developers want helps us shape our APIs, and because understanding the bugs that developers encounter is one of the best ways to deeply understand an API. As a general rule, we try to respond to all new issues within a week of their filing, and we usually accomplish this by holding a weekly triage meeting with colleagues to review new issues. Back when I worked on the Maps APIs, we were all in the same office, so we'd just crowd around a table with our laptops and mash through the bugs. But, now, on the Wave APIs team, my colleagues are spread entirely across the world, with me in Australia and them in both coasts of the United States. So, we needed a new way to triage, and being on the Wave team, we went the obvious route: use Wave!

For our first weekly meeting, we simply met in a wave and pasted the untriaged issues ("Status-New") from our Google code issue tracker into the wave. Then we'd look at the issues and reply beneath the ones we were checking out to lay dibs on them, so we worked on whatever bugs were most up our technical alleys. While we were researching a particular bug and had questions about it, we could start an inline conversation beneath the bug, so in the end, we could both work in parallel and in collaboration. This way, we were able to both triage many bugs and feel confident in our triaging, since we could bounce ideas off colleagues easily during the process.

After the first meeting, I started thinking that I could probably whip something together with our APIs that would streamline the triage process even more, and maybe make it possible for other teams to follow the same process. Around the same time, the project hosting team announced an Issue Tracker data API - perfect timing!

So, with the powers of the Wave Robots API and Issue Tracker API Python client libraries combined, I wrote the Bug Triagey robot. When you add Triagey to a wave, the bot titles the wave with the current date and inserts a configuration gadget. That gadget lets you pick a triage template, or create a new one. In a template, you just need to specify the Google code project, the Status label, and optionally, a label to sort by. For example, my Wave APIs template specifies "google-wave-resources", "New", and "ApiType", as we try to categorize our issues by sub-APIs, and each of us specialize in different APIs.

After you're happy with the template, the bot loads the sorted issues into the wave, and puts dibs buttons under each one, so you can indicate if you're "Looking at" or if you've "Responded to" an issue. After clicking a button, Triagey changes the button to show your username, and after clicking the "respond" button, Triagey strikes the issue out. That way, it's easy for you to review the issues in the wave and immediately see which issues haven't been triaged yet, and who's working on what. And just like before, you can start inline conversations to discuss the bugs you're working on.

Triagey is one of my favorite examples of how you can use Wave to combine automation and conversation to make collaboration easier and more efficient, and of how you can hold multiple structured conversations in a wave. To try it out yourself, install it from this wave. To modify it for your own use (like to triage other items) or to see how it was built, grab the code from the samples gallery.

Using App Engine to Turn Emails into waves

Note: This blog post was originally written to be posted on the Google Wave blog, but did not make it out before the cancellation of Wave. I am posting it here in case it is useful to Wave open-source developers in the future.

When I first discovered Google Wave and started working on its APIs, I realized that Wave had the potential to be a universal inbox one day, using the robots API to collect notifications from all the different inboxes and services that I use. I've since realized that many legacy services don't provide notification APIs but many of them do provide a common integration point - email - letting you specify an email address, and then sending new information to that address. Well, as it turns out, it's very easy to create an app in App Engine that can receive email at particular addresses, and then process that email. Using this technique, I can realize my dream of a universal inbox, by simply forwarding all my services to an AppEngine-powered email address, and appending the email content to a wave in my account.

So, I created the Mail Digester bot to do just that, and open-sourced the code for all of you to base your own mail-receiving robots on. The app starts with a handler for all inbound emails, so it receives emails sent to any [address] It then creates or finds the digest wave for the particular address, and appends a blip with the content of the email, converting any HTML emails to text. For example, if I send an email to "", and the app can't find any digest associated with "myemailupdates", it will create a new digest wave and add my wave address. The next time that I send an email to that address, it will find the wave in the datastore, and append a blip to it with the converted email. I wrote it this way so that I could easily create different addresses for different purposes and subscribe to a few different waves.

Once I created the robot, I set to work seeing how many services I could bring into Wave via email notifications. First, I set an address as the issue notification email for the google-wave-resources Google code project, so I could have a digest wave for all the issue updates. Next, I added another address as a member of the Google-Wave-API google group, so I could have another digest wave for new group messages. Finally, I set another address as a Gmail forwarding address, piping all my inboxed emails into a third digest wave. I still need to pop out to Gmail or other services when I need to reply, but in fact, now that I do all my team and community collaboration inside Wave, I find I only need to respond once a day or so.

Using the same principle of using a robot to respond to emails, several of my colleagues have built robots to respond to specific types of notifications. For example, one Wave engineer wrote an on-call robot that parses incoming pages from email and appends them to our weekly on-call wave, so that it's easy for us to discuss the contents of the page. Another food-loving colleague wrote a bot that turns the daily menus into waves, adding images of the food and rating widgets.

Though it at first feels odd to be using email as an integral part of a wave robot, responding to email is actually a great way to integrate Wave with existing services in your organization and even add a collaboration layer on top of them.

Issue Tracking in Wave

Note: This blog post was originally written to be posted on the Google Wave blog, but did not make it out before the cancellation of Wave. I am posting it here in case it is useful to Wave open-source developers in the future.

Like most folks in the software development field, we spend a fair bit of our time on the Google Wave team tracking bugs and feature requests. At Google, we use an internal tool for tracking issues, and that tool lets us set some initial info about the bug, choose its status from a set of options, set its priority level, and assign it to a colleague. From there on out, we can append comments to the issue to discuss it further. The tool works well as a way of tracking the status of bugs across many projects and people, but it doesn't work as well for working through bugs quickly, or for having more complex conversations on requests. On the other hand, Google Wave, works really well for collaborative debugging, since you can easily paste code in, attach files, and comment on each other's code, and of course, it works great have for having conversations that diverge into multiple threads. I really wanted a way to have the best of both worlds: the structured input of our tool, plus the collaborative conversations of a wave. So, we worked with a team to create the Issue Tracky extension to do just that.

When you install Issue Tracky, you'll see both a new item in your "New Wave" drop down and an icon on your toolbar. You can use the former to create a new issue report from scratch, or you can select text in a wave and click the toolbar icon to turn it into an issue. In either case, a robot will fill the wave in with a title and info gadget, where you can pick the issue type, priority level, and assign the issue to a colleague. From there, you can add a description using all the Wave editing tools you're used to, attaching files or pasting formatted code, and then add your colleagues to the wave to discuss the issue.

The robot will automatically tag the wave based on the information in the gadget, so that you can create saved searches for all of the bugs assigned to you (e.g. "type-bug assignee-pamelafox") or all of the high priority requests ("type-request priority-1"), and easily browse through them in weekly reviews or triage meetings.

We've created a generic version of the Issue Tracky tool that anyone can play with, but we've also open-sourced the code, because we think that this is the kind of extension that companies will want to both use and customize for their own use, perhaps by integrating it with existing systems or changing the gadget to collect different pieces of information. To get started with your own version of it, download the code and follow the instructions in the readme. If you have any questions or want to share how you've extended the codebase, stop by the forum.

We hope this helps you have more productive discussions on the issues in your projects, and better collaboration with your teams. Enjoy!

Google Shared Spaces: How We Made It

In my last post, I talked about why we made Google Shared Spaces. Now I want to talk about how we made it, as I think it may surprise a few folks. Much of the press about Shared Spaces claims that it is built off "Wave technology", when in fact, the only piece of Wave technology that Shared Spaces utilizes is the Javascript Wave Gadgets API. Since what we set out to make was really pretty simple, we decided to start from scratch and use a combination of open-source frameworks and publicly available APIs.

We use Python App Engine as the hosting platform, and Django 1.0 for the templates & request handling. We embed the gadgets in the pages using the iGoogle Gadget Renderer (a deployed version of the open-source Shindig server), the gadgets communicate with the page using the Wave Gadgets JavaScript API (now open-sourced), and the page communicates with the server using the Channel API (App Engine's approach to COMET). For AJAX processing and UI features, We use the Google-hosted jQuery. For authentication, we use the Twitter API, Yahoo API, and Google Buzz API. For the comments and ratings in the gadgets gallery, we use Disqus threads.

By starting from scratch while reusing the relevant technologies out there, we were able to build the first version pretty quickly (within a few weeks), and we're also able to iterate quickly now (new releases every couple days). While the open-sourced codebase for Wave is around 250,000 lines of code, the codebase for Shared Spaces is now about 5,000. Wave is a complex technology encompassing multiple algorithms, backends, and interfaces, while Shared Spaces is a user-facing app that uses just one small part of that technology and is developed by a small team. If you pick the right tools for the right job, you can do a lot with a little. :)

Google Shared Spaces: Why We Made It

Last week, just in time for the holidays, we released a Google Labs project called Google Shared Spaces. "We" is actually just a few people working in our 20% time: Douwe Osinga - former Wave API tech lead, Jon Tirsen - former Wave contacts tech lead, Vadim Gerasimov - former Gadgets API engineer, and myself - former Wave API developer advocate. As you can see, we all came from the Wave team, where we saw firsthand the ways that users used Wave and the ways that developers used the Wave APIs. Wave was a lot of things to many people, and there are a lot of directions that you could take the ideas in it. After Wave was cancelled by Google, a small team has been working on open-sourcing it for the past 5 months, so developers can start building off the Wave technology stack, as a whole or as bits & pieces, to take it in the direction of their vision.

The four of us were personally interested in seeing what we could make with just the gadgets part of the stack. The Wave Gadgets API is a simple but powerful API -- it combines the open-source gadgets API with a basic JavaScript API for modifying a shared state (hash map) & retrieving participants information. With just a shared hash map, developers were able to make an astonishing array of gadgets - multi-player games, collaborative diagramming apps, date-picking utilities, even a Flash-like animation tool. In fact, developers made gadgets that were basically full-featured webapps, and they would take up the entirety of the Wave interface when you were using them. Developers weren't using Wave for its conversational abilities at that point -- they were just using it for the collaborative space that it enabled. Some of the developers even added a chat feature to their gadget, as users didn't want to have to scroll down past the gadget to converse with the other participants.

The Diagram Editor gadget:

When we saw this happening while Wave was still an ongoing project, we thought of various ways we could improve the Wave UI for these app experiences: full-screen modes, split scrollbars, chat mode. But with Wave cancelled, we thought about how we could start from scratch to create an experience that centered around these collaborative gadgets. At the same time, we wanted to experiment with other aspects of the Wave experience, like the sharing & permissions model. And thus, Shared Spaces was born.

Shared Spaces is entirely centered on the gadgets. The landing page is a list of featured gadgets, and each of them offers a button to "Create a space". Once you click that, you're prompted to login with either your Google, Yahoo!, or Twitter account. (We didn't see any reason to limit authentication to just Google, particularly since people might want to use Shared Spaces to collaborative with communities outside their Google sphere). You're then taken to a "space" with a list of participants (just you, to start), the selected gadget, a chat area, and a bunch of share buttons. Once you share the URL with other folks, whether via email, IM, or microblogging, you'll see the other participants show up in the list, and all of you can collaborate on the gadget together - whether that's a game of Sudoku, an RSVP gadget, or a drawing board. Much of the experience is similar to the Etherpad experience, where you can create a collaborative pad with one click, chat on the side, and share that pad by URL; I sometimes think of it as "Etherpad for gadgets."

The Yes/No/Maybe gadget:

We've launched Shared Spaces with what we deemed the minimal features necessary because this is very much an experiment; we want to see how users use this, what they want out of it, and what direction it may go in. Perhaps it will become a full product, or perhaps it will be integrated into existing Google products. And hey, maybe it will inspire non-Google companies to use similar technology in their products. The web is increasingly about collaboration, and I think it is always a good thing to experiment in how all of us can make collaboration easier. :)

Sunday, December 26, 2010

The Costa Rica Surf Camp Experience

I was born in California, but after an unfortunate decision from my dad, I ended up growing up in the cold confines of Syracuse, New York. I huddled for warmth in the glow of our many computers and eventually became a computer geek like my dad, but I often wondered what I would have become had I grown up in southern California instead -- and because it just looks so awesome in the movies, I always imagined myself as a surfer chick. I'm pretty happy as a computer geek these days, but I like to keep my options open, so I figured I should eventually take the first step to surfer chickdom: learning to surf.

Even though I've lived in California multiple times in my life, and lived in the surf kingdom of Sydney for the last two years, I somehow have never managed to get my ass on a surfboard. At one point, I figured it was just one of those things that I swore I'd always try and never actually do. (You gotta have a few of those). But in November, I serendipitously discovered that my colleague had the same wish -- and the same amount of vacation days -- and within a matter of weeks, we had arranged a weeklong trip to the Green Iguana Surf Camp in Costa Rica. We were deciding between Mexico, Australia, and Costa Rica, but eventually picked the latter because a friend recommended it, and because I've been to Costa Rica twice before & have something of a massive crush on that country. (Plus, I miss speaking Spanish - it's a beautiful language and there aren't many opportunities to practice it in Sydney).

We arrived in the surf camp in Costa Rica on December 12 and left on December 20th, and we had an amazing time in that week. We of course spent several hours each day learning to surf -- practicing the basics of the "pop-and-hop" -- and washing off in the local waterfalls after (they're as common as pubs are in Sydney). But we also spent a lot of time just enjoying the local culture, like:

  • The food: We'd usually start our meals with an appetizer of "patacones" (triple fried smashed plaintains) & guacomole, then continue on with a "casado" (rice, beans, and a protein) or a full fried red snapper. After surfing, we'd visit a street stand & pick up a ceviche -- raw fish that cooks itself from the acids in a cup of lemon juice. On "Tuna Tuesday" at the local pub, we had seared tuna in wasabi sauce, and it was the most delicious tuna that I've ever tasted - it melted in my mouth. Apparently Tuesday was the day they received the fresh tuna, and they wanted to sell it while it was fresh. It sure was! For snacks throughout the day, we'd walk up to our favorite fruit shop and have them cut up a pineapple (with sprinkled salt on it!) or a mango.

  • The wildlife: We saw lizards everywhere we went, including the largish "Ctenosaurs" which enjoy sunning themselves on hotel & restaurant roofs (and have an awesome dinosaur-sounding name). We also visited the local reptile park, Reptilandia, and wandered around it drinking Rum & Cokes from a can & marveling in a rather tipsy way at the rather large reptiles ("OMG ANACONDA!"). Thankfully, we didn't actually see much sealife during the surfing lessons, besides the crabs scuttling to-and-from all the holes in the beach. I was happy to imagine that I was surfing in a scary-animal-free zone. :) During one visit to a fruit stand, we found ourself feeding all our banana to a very adorable but aggressive Pizote (he showed us both his claws & his puppy dog face). On our last day there, we went horseback riding on a beach, and listened to the local birds calling in the trees (there's one that makes a sound like laughter, and it basically sounded like he was laughing at us the whole time.. as if I wasn't already lacking in confidence).

  • The nightlife: I was surprised to discover that our little town of Playa Dominical actually had a pretty thriving nightlife. Our first outing was to a Karaoke night, where the locals sang love ballad after love ballad (I say "love", but in fact most of the lyrics of the songs were much more about jealousy and rage), and we sang American classics, like "Total Eclipse of the Heart" and "I want to hold your hand". Our next outing was "Ladies Night," and the club was absolutely packed. The DJ, who we'd happened to befriend on our first day, played a mix of reggae, hiphop, house, reggaeton, and salsa. I loved dancing to that blend of genres, and I even had fun when a local led me in a salsa dance (I don't usually do partner dancing). We went out a few more times after that, and it was always a really fun atmosphere.
  • And most importantly...

  • The people: Before we embarked on this experience, we thought it would mostly just be us two, and that we'd do a lot of solitary reflection and all that deep stuff. But pretty much as soon as we arrived there, we met the crew that would occupy our days going forwards: our fellow surf campers - about 7 people our age and a family with highly entertaining 8-yr-old & 3 yr-old-boys, our surf instructors - 6 guys from ages 15 to 55, plus the family that runs the camp. We had a lot of fun learning to surf & experiencing the local culture with that crew, but in addition to them, we also met many friendly locals -- like the boy that cut up our fruit every day or the taxi driver that snacked with us after our horseback ride.

In short, I loved every minute of the surf camp experience, even the ones where I was battling the saltwater in my eyes & trying desperately to catch a wave, and I'm so thankful to the people of Playa Dominical that made it a warm & welcoming place.

And, oh, yeah, I found out that I'm not that great of a surfer. Back to geeking I go! :)

Sunday, December 5, 2010

Reuseable HTML & CSS Teaching Materials

When I decided to bring GDI to Australia and kickstart it with an HTML & CSS mini-course, I had a side goal: create reusable teaching materials. There are a huge number of online resources to help you learn web development, but there are few bundled sets of resources that can be used together to actually teach a topic to a class of students. (Or, atleast, few that I could find). I set out to make materials that I could CC-license and share with potential teachers, so that they could focus on customizing and delivering the materials instead of preparing them from scratch (which takes a surprising amount of time).

Since delivering the materials a few months back, I have cleaned them up and theyre now online here, at a nice friendly URL:

To see what's there, you can click through the various lesson links. To actually get started re-using the material yourself, you can download the linked zip file, or if you want an easy way to host it online for your class, you can even download the website files from github and deploy them to App Engine or your own server.

If you do end up delivering the course (or some version of it), I would love to hear about it. We need more HTML & CSS teaching in the world!