I joined Airbnb a little over a year ago, and I found the Search team in the early stages of a project to rewrite the search interface on airbnb.com. The effort was aimed to solve several problems that our Insights team had identified with the existing search results page through user research. I became the main engineer on the project, and over the next eight months worked on some of the most impactful code of my life.
In this post I’ll explain why we felt we had to rebuild the whole search experience, how we set up and executed the project, and what the impact was. I’ll also touch on what went well and what didn’t.
What was the problem?
The old search results page had a number of well known usability problems. One issue was something we called pogosticking: the way users had to go back and forth between the results page and the listing pages because there wasn’t enough information on the results page to make a well-informed decision. Another issue was that many users completely missed important filters that would help them narrow down their search, since they were tucked away in the left sidebar. Lastly, users consistently reported location as a central factor in choosing a listing; yet our map was tiny and difficult to use.
On a deeper level, the code hadn’t been pruned, cleaned, or purged for a few years—a time that the company had gone through many changes. Cruft and unused features had added up, making the code hard to work with.
What had been done so far?
The Search team had begun an effort solve these problems before I joined. They had decided to redesign and rewrite the page: no small task! The vast majority of our bookings go through the search page, and many features across the platform hook into it. Any rewrite would have to maintain feature parity, perform well, and not break other parts of the site.
The team had built a prototype; however, it was problematic. Its solutions didn’t work well together and given that it was just a prototype, it was never built to be performant. We debated whether to continue working with the prototype, but in the end we decided to scrap it and start over. Lesson learned: a prototype can only take you so far—there’s a point at which shippable code is necessary to move forward.
The team started over, lessons in hand. We made some low-fidelity prototypes and mocks, but as soon as we started writing real code, it had to be performant and production-quality.
Our designers struck out in a new direction, taking cues from our award-winning mobile app: users would be able to scroll through photos right from the search results, listings would appear in cards that contained all of their relevant information, and the map would be larger and a primary method of interaction.
We also leaned heavily on user research from the very beginning, putting nearly anything designed in front of volunteers, friends, and co-workers unaffiliated with the project to get a qualitative sense for what their reactions were.
Finally, we stopped worrying about incorporating and matching every legacy feature that the old search interface had. Maintaining feature parity can often stand in the way of finding a conceptually simple approach. Instead, we started with the very core feature set and added legacy features back in one by one later—or sometimes, if we could get away with it, not at all.
The project setup
The project setup was unique in my experience. The team varied in the early stages, but soon it settled on a lead designer (Kyle Pickering), a lead engineer (myself), and only a few other engineers and designers to provide assistance and feedback.
The tininess of the team (despite the relative largeness of the project) allowed us to move very quickly. Kyle and I could both make large changes with little process. Especially for an evolving project and codebase, this was key to keep things clean and understandable. Refactors and large changes happened often, but they were relatively simple because I knew the project inside and out.
The project was very collaborative: Kyle and I both have basic experience in our counterpart’s field (frontend engineering and design, respectively), which allowed us to bounce ideas off each other and keep a tight feedback loop. Daily standups and frequent reviews helped us keep an awareness of the other half of the process.
Finally, we aggressively combated feature creep by creating a detailed spreadsheet to track every feature proposed for the new page. We sorted them by priority and how core they were to the concept—tangential features didn’t make the cut.
We made a few interesting decisions for the technical stack. On the client side, we decided to use Flight.js, a framework developed by Twitter. It has several features that were attractive to us. First, it’s relatively easy to understand for anyone who has worked with the DOM and jQuery. Next, its event-driven framework allowed our complex and interaction-heavy page to stay loosely coupled and avoid collapsing into spaghetti code.
We also switched to Mustache templates from erb. We find them simpler to read, organize, and write; the enforced separation of markup from logic makes it easy for engineers to write clean, understandable code.
Because the new page had to work within our existing airbnb.com stack, we only changed the pieces that made sense. We stuck with Ruby on Rails on the server-side, our existing search service for the backend, and SCSS to render stylesheets.
The team worked on the new search page for most of summer and fall of 2013. We used it internally to book our own trips and allowed the rest of the company to opt themselves in as well. Walking by co-workers’ desks and seeing the alpha version’s interface on monitors made the project tangibly real to us—our friends were depending on us! We were newly motivated to fix bugs and polish down to the last detail.
Eventually we launched a beta version to 10% of users. We fixed lots of bugs and made many tweaks until we felt comfortable launching to 50% of users. Once there, we held steady for several weeks to collect data and watch metrics. We sliced the numbers by browser type, device, country, and language to catch any breakages. Finally, we all started to gradually feel like we might have a product ready to ship. After a final push of bug fixes and optimizations, we launched the new page to all users worldwide.
Was it worth it? Here’s what we got: modern, non-spaghetti, well-commented code. The page sports an updated, responsive design. Best of all, we have a platform to build more features on top of, for both design and engineering. Oh yeah, and a full 2% lift in the number of people that book from searching—a level of improvement we hadn’t seen for a while.
So what do we do now? Just a few weeks ago, I had the pleasure of shipping a branch that deleted nearly 18,000 lines of code: all legacy files from the old search interface and prototype. We haven’t scrubbed everything, though. One of the challenges to constantly iterating is that the remnants of previous versions can stick around for a while—we’re still working on cleaning and polishing the new interface.
We’re also constantly improving performance everywhere we can. We recently changed our backend caching scheme to better suit the emerging usage patterns of the new design. We also spent significant effort on frontend performance: render time, image loading, scrolling, CSS selectors, and more.
We learned a ton about rewriting major interface components through this project, and I’m particularly excited to bring these lessons to our listing page and other features across the site.