Frontend

A Rubyist's View of Modern Java

An Unpleasant Introduction

When I was in college (back in 2007), "learning Java" meant "forging Java applets in the dark heart of Mount Eclipse." As you would imagine, this involved a lot of import java.awt.* and public class SelfLoathing extends Applet and lava and blood and Uruk-hai. (Some of this is certainly my own failing; my boss, who knows much more about Java than I do, loves Eclipse.) I don't think anyone died as a direct result of writing old-school Java or attempting to use Eclipse, but I witnessed at least one grown man reduced to tears. I finished the semester and swore I would never write Java again.

The Language (Java 8, or "The Ocho")

Java has come a long way in seven years. A more comprehensive guide to those changes is available in this excellent series of posts over on the Parallel Universe blog; for the points most salient to Rubyists, Pythonistas, JavaScriveners, PHPeons, and others of more dynamically-typed persuasions, I've made a short list of the delightful bits of modern Java we're using here at Rent the Runway (TL;DR at the bottom).

To reverse each string in a list in Java 7 and earlier, you used to have to pull a stunt like this (assuming you weren't in an interview and were allowed to use Java's built-in String methods):

To a Rubyist, this is something of a cross between waiting in line at the DMV and burning a hecatomb: quite a bit of rigmarole to obtain a simple result (a driver's license, a favorable wind toward Ithaka). Now, you could write truly Javatastic Ruby:

However, you'd be much more likely to write:

Or, if you're feeling fancy:

To quote Eddie Izzard: et voilà. Truly, Ruby is an elegant language for a more civilized age. Could Java ever look like this? Surprisingly, the answer is yes! In Java 8—a.k.a. The Ocho™—you can now write:

Is this as wond'rous as the one-line Ruby version in mine eyes? No. But it's leaps and bounds above the imperative/procedural style to which Java, the quintessential object-oriented language of the 20th (and now 21st) century, has been shackled for the better part of two decades. And this is really only scratching the surface of what's available in The Ocho™ (I'm gonna make this a thing, I swear): better type inference, method parameter reflection, and fibers (sort of) are just a few of the additions that are turning Java into modern Java (and making modern Java a really pleasant language to write).

The Ecosystem (Frameworks and Tooling)

I've found that even more important than the features of the language you write is the ecosystem in which it lives; one of the reasons I quit Haskell was because its package manager, Cabal, was dreadful. (It probably still is, though I haven't checked recently.) Java's package management systems are well-known and mature (I'm a fan of Maven myself), but the same can't be said for the myriad Java web frameworks out there.

First, I'm going to straight up skip J2EE: partly because I'm not old enough to remember it, but mostly because anyone who is probably doesn't want to.

Some people will tell you about "modern" web frameworks like Spring Web MVC or Play. Spring is (near as I can tell) not much more than a wrapper around all the things nobody likes about Java EE, and I haven't been able to discern any core philosophy with regard to best practices or patterns for solving common web service problems. And if this were the worst of these frameworks—if the design were confusing but the underlying technology sound—that would be one thing. I've actually witnessed Play, via some JNI-based Unforgivable Curse, segfault when you added a route. Which is, I suppose, what you get for wanting to do something insane like that.

Enter Dropwizard, which is not only sane, but absolutely delightful. Despite my limited Java superpowers, I got the "Hello, world!" service up and running in about fifteen minutes. Everything worked as expected. It made sense. Though it's a young project (started in 2011 and recently released version 0.7), there's excellent documentation and a helpful (though still somewhat small) community. I'm really pleased it's our framework of choice at Rent the Runway, and I've actually started going out of my way to read Java pull requests to learn more about it and how we use it.

Finally, I'd be remiss in my short survey of modern Java without a brief discussion of IDEs. As mentioned, I despise Eclipse and wouldn't mind seeing it blotted out of all human memory, but I strongly believe in knowing (and, ideally, liking) your tools, so I think anyone productive with Eclipse should continue to use it. That said, I picked IntelliJ when I came back to Java earlier this year, and it's excellent: on-the-fly warnings (which I generate liberally), code completion, automatic refactoring, and (best of all) immediate and smooth integration with Java 8. IntelliJ's certainly not a new tool, but its newest version (13) is, in my humble opinion, the editor of choice for modern Java.

TL;DR

  • Java 8 is a serious improvement on the core language, and I think programmers everywhere (particularly those writing Ruby, Python, JavaScript, and PHP) owe it another look;
  • Dropwizard is a first-class web service framework and the first Java web framework I'm really excited to dig into;
  • IntelliJ makes developing in Java (particularly Java 8) a breeze, and I wholeheartedly recommend it. (This is from a guy who spends 90% of his day in Vim.)

Am I going to switch to only writing Java tomorrow? Of course not. But with Java 8, Dropwizard, and IntelliJ, I'm interested in learning more about the language, its platform, and its tools, and I'm excited to build something great with them.


Deploying Daily

Six Months Ago

“I’m not seeing the new tooltip on the grid application. Did you deploy that one yet?” “Yeah, just now.” “Did you remember to sync the submodules?” “Yes.” “Did you flush Memcached and the CDN?” “Crap. No, I forgot. Which order do we flush those in again?” “Memcached, then CDN. Then make sure to deploy to both Heroku and Engine Yard.”

These were dark times.

When I started at Rent the Runway nine months ago, our storefront was divided into seven swimlanes: independent Sinatra applications that, in theory, allowed us to handle high traffic through fine-grained control over different parts of renttherunway.com. If we suddenly got a burst of traffic from a news story or celebrity tweet, we could independently scale the home page from the rest of the application to handle it. We also gained fault isolation and tolerance, since one part of the application going down meant we both knew where the problem was and could prevent it from spreading.

We soon discovered, however, that while swimlanes were a good idea, we’d applied them at the wrong level of granularity: 99% of the time, our changes to the codebase affected multiple swimlanes. Even when we were working on just one, we ended up writing a lot of duplicate code because all the underlying data providers were identical. Fault tolerance and isolation were nice, but we were dead in the water if users could hit the home page but not transact, or vice-versa. We didn’t even have full isolation: since all the data providers were the same, a service disruption to one swimlane would likely affect several. All this meant that deploying our storefront had rapidly become an enterprise of lunar mission proportions.

Game face

The author. Or Ed Harris in

Apollo 13

Deploying all seven swimlanes entailed syncing two submodules (one for views, another for assets), possibly bumping the version on two gems (one for the base application from which each swimlane inherited, another for our API clients), updating code for all seven swimlanes (each its own Git repo), then deploying each one to both Heroku and Engine Yard (in the event of problems with one, we’d fail over to the other). The dependency graph looked like a drunk John Madden telestrator instant replay diagram.

Oh yeah: and each swimlane had its own CDN and Memcached instance, each of which had to be flushed separately and in the right order.

Oh! And this was just to deploy to stage. Once we were on stage and confirmed everything looked good, we had to do the whole thing again for production. It took two developers six hours, start to finish, to deploy renttherunway.com. We deployed once a week on Thursdays, and if for some reason we couldn’t get a release out the door (which, as you can imagine, wasn’t uncommon), site traffic and weekend on-call concerns forced us to wait until the following Tuesday for another window of opportunity. Like I said, it was like a lunar mission.

Present Day

We knew we had to do better. Camille, our head of engineering, charged us with putting together a task force to get us from our wobbly weekly deploys to a system of smooth, daily ones. Since many of Rent the Runway’s back end services are named after animals, the task force became the TuskForce™, with our unit of progress the stampede (rather than the sprint). We determined we needed to do three things:

  • Consolidate our seven swimlanes into one application, which included eliminating the submodules;
  • Develop a feature flagging system to allow us to toggle features on and off without deploying the application;
  • Move the application to a single host (rather than Heroku and Engine Yard) and automate the deploy process.

Smashing the swimlanes together was arduous and a lot of things broke, but within a couple of weeks we had a functioning, single “swimming pool” comprising the original seven Sinatra applications. At some point, “Seven [rings] for the Dwarf-lords in their halls of stone” came up. Many Lord of the Rings jokes followed.

While we were busy combining the swimlanes, I set to work forging a feature flagging service, dubbed “Flaggregator.” (Rejected names included “The Flaggro Crag” and “Spiro ‘Feature’ Flagnew”.) Flaggregator is a Sinatra application that keeps track of feature flag data through Git and GitHub, so in keeping with our LotR theme, we named Flaggregator’s GitHub user “Frodo Flaggins.”

Flaggregator

Flaggregator™

With the arrival of Flaggregator, we could modify features on the site without a deploy. Now, if we’d stopped here, we’d already have had some serious wins over the previous process: deploying one application weekly and changing features whenever we wanted was night and day compared to the stress of our old weekly, six-hour deploy marathons. But we knew we could do more, so Fellowship-style, we pressed on.

We moved the application off Heroku and Engine Yard and over to the private cloud, then automated the deploy process via Rake and Capistrano. (This is nothing groundbreaking, which is a Good Thing: you should save the experimentation for features and small, new projects, not core infrastructure.) We also spun up a Hubot instance named Fashionator to serve as our deploy concierge, telling us about pull requests, notifying us of deploys, and running integration tests.

Fashionator

Fashionator in her natural habitat (HipChat)

The result? It now takes one developer six minutes to deploy our storefront application, and we do it every day. And this wasn’t our only win: moving to a culture of continuous integration has resulted in more and better tests, better code quality and coverage, and improved code review processes (all of which I’ll cover in future posts).

TL;DR

TuskForce completed its work at the end of January of this year. In three months, we made the following changes to our storefront deploy process:

    • Went from deploying seven applications to just one;
    • Decreased our deploy time by 98%;
    • Increased our deploy velocity by 400%;
    • Added the ability to turn features on and off independently of daily deploys;
    • Made our business stakeholders, customers, and developers much, much happier.

We still have a ton of work to do: scaling, infrastructure development, configuration management, and continuous deployment (that is, multiple deploys per day) are just a few of the difficult problems we’re tackling in 2014. But with the huge cultural and technological successes we’ve seen in the last few months, I have no doubt we’ll find imaginative solutions for them. Rent the Runway’s future is very, very bright.

If you want to be part of it, come work with us.


RTR & the Clown Car Technique for Adaptive Images

<!--h1 { margin-top: 40px; } h3 { margin-top: 35px; margin-bottom: 0px; } -->

A recent conversation between Design & Tech at Rent the Runway:

Design: We want to let the user decide which size images they see.

Tech: Great, we will use percentage widths for the images and they will stretch with the page.

Design: Ok, so what size images do you need?

Tech: As big as the largest view you would like us to support.

...first implementation...

Design: The detail in this image is terrible when the browser is small.

Tech: Yeah, browsers are just ok at resizing images.

Design: We have all of these great photos, professionally edited, can we pick one depending on the browser dimensions?

...second iteration...

Tech: Clown Car Technique FTW!

Clown Car Technique

Why We Care...

Clown Car Technique
Clown Car Technique

We started using the Clown Car Technique (h/t Estelle Weyl) recently when our crack team of designers came up with a new design for “shortlists” -- RTR-speak for a user-defined collection of dresses.

The idea was to give users the choice of which image sizes they'd prefer, while maintaining flexibility with all browser dimensions, and resizing. The clown car technique allowed us to implement the pages to the designer’s liking, while keeping network traffic down and maintaining high quality images.

Why You Should Care...

Many of the best APIs we like to code against, return sets of images of many sizes and shapes. You should use them all to provide the best user experience possible!

What You Should Know

The Smashing Magazine article will do the technique far better justice than I ever could, but if you would like to see it in action:

  1. open this Shortlist
  2. open your browser's developer tools
  3. go to the Network Tab (filter on Images)
  4. change the image size using the "VIEW" icons and monitor your network traffic

The "VIEW" choice updates the width of the image (nothing more), and the SVG -- the essence of the technique -- determines which image to display.

Questions?  Comments?  Tweet at us: @rtr_tech