Javascript

Using Flow to Write More Confident React Apps

Writing your first React app is simple with tools such as Create React App, but as your application and your team grow, it becomes more difficult to write scalable, confident code efficiently. Think about the number of times you pass props around a React application and expect them to look a certain way or be of a certain type, or the times when you’ve passed the wrong type of argument into a function and rendered a page useless. Fortunately, there are many solutions for these preventable problems, and one of the tools we’ve found helpful here at Rent The Runway is Flow.

What Is Flow?

According to Flow’s official website, Flow is a static type checker for JavaScript. After you install Flow, start the Flow background process, and annotate your code, Flow checks for errors while you code and gently alerts you to them. There are even Flow packages available for many popular text editors, which can highlight potential problems and provide explanatory text right beside the code itself.

Many times, Flow can infer how you want your code to work, so you don’t always need to do extra work, but it helps to be certain by actually using the static type annotations. In short, Flow checks how data moves through your app, ensuring that you’re using the types of data that you expect and forcing you to think twice before you reassign a variable to a different type, or try to access a non-existent property of an object.

Basic Example

Here’s a basic example of how to add Flow type checking to a file.

This is a simple component to display and edit data for a customer’s account.

Telling Flow that it should check this file is as simple as including the `// @flow` flag at the top of the file. Almost immediately, Flow will begin checking the file, and you’ll notice red dots in the text editor (Sublime) warning about potential problems. When we hover over those lines, we see additional information about the error at the bottom of the text editor.

After tackling the highlighted lines one by one, we’re left with a nicely annotated file:

Here, we’re doing the bare minimum to silence the red dots, telling Flow that the `constructor` method accepts a `props` argument that should be an object. (Flow allows you to be more specific, which we’ll show in a bit, but this suffices for now). In addition, we’ve explicitly declared the properties and types of each property for the class, which is part of Flow’s Class type checking capabilities. Now, the shape of state and the types of its properties are guaranteed, and we only had to do a bit of annotation for Flow to get started.

To be more explicit, we can also declare the types of properties that an object when supplied as an argument to a function must have. Below, on line 15 of the CustomerAccountProfile component (right), we specify that the props must have a customer property.

In that component’s parent, CustomerTabAccount (left), on line 75, you can see that when we try to pass in ‘null’ as a prop, Flow gives us a warning that ‘This type is incompatible with (object type)’.

To go one step farther, you could even declare the types of all the properties within props for the component. Now, if you try to reference a property that isn’t declared with the props, Flow will let you know that the property is not found.

Although this is just a sample of the many type checks Flow is capable of, the Flow documentation goes pretty deep into all the possibilities.

Advantages

What’s great about Flow is that it can catch errors early and help development teams communicate better about how components work together within an application. And although React’s PropTypes serve a similar purpose and are arguably simpler to use, they only throw errors at runtime rather than while you’re coding. Plus, since they’re declared below the component, they seem more like an afterthought.

Beyond the basics, adding Flow to your codebase is fairly painless, since it’s opt-in. You tell Flow to analyze a file by including a `// @flow` flag at the top of a file. This will mark it as a Flow file, and the Flow background process will monitor all Flow files. Files without the flag will be ignored, so you get to control which files you check and you can integrate it into a new or existing codebase over time.

It also plays nicely with ES6 and Babel, which strips out all the annotations for production.

Disadvantages

On the other hand, that same opt-in policy leaves room for neglect. Less diligent programmers can opt to forgo Flow altogether. In addition, there is a learning curve for type annotations, especially for new developers who aren’t used to type checking their code. What I find to be a bigger challenge is not getting started, but using Flow well. Basic type checking is useful, but Flow offers the ability to write very use-case specific type checks such as “Maybe” types, which check optional values and “Class” types, which allow you to use a class as a type. It’s easy to begin using Flow, but difficult to master all of its capabilities.

We began adopting Flow slowly in one of our retail applications, and as we continue building new features, we continue to convert older components to use Flow. Overall, it has helped us identify bugs sooner rather than later and has enabled easier refactoring because we can be more confident about the arguments functions accept and how different function invocations change a component’s state.

For more information on Flow and getting started, consult the official Flow documentation.

Resources

Official Flow Documentation

React PropTypes Versus Flow


@RTR_tech

As I write this, today is beach day @RenttheRunway (July 31, 2014).

What does that mean? It means our CEO Jenn Hyman (@Jenn_RTR), decided that the whole team deserved a day of “Mandatory Fun” at an awesome beach with tennis courts and a pool and the whole nine yards, on the company's dime.

A few days before that Jenn spontaneously ordered an ice cream truck to come to the office and give everyone free ice cream. We're not talking 10 people here - we’re talking about the whole, enough-to-fill-multiple-busses, RTR office.

A few days before that there was a Hawaiian style BBQ/Luau at our Dream Fulfillment Center in Jersey (where your dresses are shipped from).

You get the idea.

But lots of startups have occasional crazy fun surprises like that (right?). What's really telling about a company is the day-to-day. This blog is about life @RTR_tech, not RTR in general. Make no mistake: this is a tech organization and it’s an awesome one.

Let me tell you a story. It's going to be a bit scattered, and probably long-winded, but I think you'll like it.

I promise I'll mention some tech along the way.

A little more than a year ago, I was living with my family in Ann Arbor, MI where I had worked for about 13 years. Ann Arbor is an awesome little college town, but my wife wanted to move back to NY where she grew up. As a prerequisite, I wanted to make sure I found a job in NYC where I could truly be happy. This was more difficult than you might imagine.

I was looking for a small-ish, startup-ish, flexible, open-minded tech company with outstanding people.

I eventually discovered a large list of NYC companies of this ilk. Cruising down the list in alphabetical order, I eventually came to Rent the Runway.

"A fashion/e-commerce company?," I thought, "meh."  I passed right over it.

Fortunately, it didn't end there. The CTO of another company (whose selfless kindness I should have repaid long ago) reconnected me with RTR_tech via CTO Camille Fournier (@skamille) I had a phone call with her and was extremely impressed. The rest is history. I also spoke to Vijay (@vjsubr), head of Analytics, Jenn Hyman and various awesome members of the tech team and I was convinced.

One year later, I can tell you that this company is far from just a "fashion/e-commerce company" and is anything but "meh."

These people are awesome and humble. They learn from their mistakes and they learn fast. They actively seek feedback. They listen deeply. They really, honestly care about their teammates. They have created a culture of openness, idea sharing, risk-taking, fun, friendliness, honesty, continuous improvement, teaching and in-the-end, success. And they pay me to hang out with them all day!

What follows is just some of the awesome stuff I’ve had the pleasure of living with @RTR_tech.

First off, we use modern technology tempered with a good bit of wisdom that the “Shiny New Thing” is not always as awesome as it seems. The grass is not always greener on the other side. We’ve adopted a lean-and-mean, modern Java web service framework called Dropwizard. Not Node. Not Scala. Not Python. They're all cool, don't get me wrong, but Java is tried and true and way cooler than you might think if you just take the time to get to know it. :) Plus: Java 8! And cool stuff like @AutoValue. We're working hard to move our front end code to Backbone. There's some Ruby in the mix for good measure. Plus, have you seen what renttherunway.com looks like? It's freaking beautiful! We work with awesome designers and we really care about making it not just work right, but also look great.

We have regular, weekly one-on-one meetings with managers, team leads and peers. These are not perfunctory tech status updates. In these meetings we talk openly about what's bugging us. We refine our goals and take steps towards achieving them. We work to carve out time for people to work on that open source contribution they've had in mind (making @AutoValue work with Hibernate perhaps). As a manager, one of my personal rules of thumb is that performance reviews should not contain any negative surprises (or only good surprises). I've learned to use this one-on-one time to make sure that's the case and that I'm guiding/teaching (and learning from!) my reports to avoid those negative surprises. Just a few days ago I was writing a performance review. When I really got into the meat of it, I realized that I had some new suggestions around goals the person could set, but that we hadn't talked about yet. Before I wrote those things into the review, I grabbed the person and talked through the suggestions. The next day, we had the Important Official Mid-Year Review meeting. I delivered my write-up, and watched the pride swell up in the individual. This is not to say there was no constructive feedback, but that that feedback had already been well established and internalized. That's how you do performance reviews. We do that here @RTR_tech. If you're on my team, you'll get a performance review like that. I really care - we really care - about our teammates as people. In the end, that's all we have. Java code is easy. People are hard. Help them refine and follow their goals. Help them thrive. Help them learn. Help us learn.

@RTR_tech we are a learning organization from top to bottom. As such we’re encouraged (by @skamille and others) to attend technical conferences. RTR_tech will send you to speak or just attend. And of course, @skamille, @markwunsch, and @OMGannaks held a panel discussion @RTR_teach - oops, @RTR_tech - about how to write successful conference presentation proposals, because… they're awesome.

Similarly, we do Drinks and Demos every Friday. This is our chance to share essentially whatever we want as engineers. Maybe it's @timx showing off the new RTR Unlimited product/feature his team just released or @ericqweinstein teaching us some new stuff about "The Rubies." It could be @CarloBarbara doing a case study of how to systematically debug a tough OutOfMemoryError, because, as @skamille says, "don't flail."

Speaking of "don't flail:" you can learn that and so much more by going to @skamille's weekly office hours and having a great discussion with her. I'm not exaggerating that every time you sit down to talk with her, you'll walk away having learned something or with a new perspective on something. She maintains these office hours as a way to remain accessible and keep the communication lines open despite the fact that our tech team is quite large and growing rapidly. How accessible? Our awesome intern Maude (@QcMaude - A Post Internship Look at RTR) has mentioned to me how great it is that she is able to openly talk to Camille as she would any other peer.

There are lots of big brains out there in the world though, and we can't send the entire tech team to the next “Edgy Tech Conference.” In order to fill that gap we bring in guest speakers from time to time. We’ve invited people like the creator of Backbone (@jashkenas) and (@mrb_bk), an engineer from Code Climate (which we use for JS/Ruby static analysis).

"What if," you say, "I get a crazy idea that I just want to try and I never have time to build it?" You'll have your chance! In the year I've been here, we've had a hack day, a (3-day) hack “week” and a full, five-day hack week the last week of August. On hack week you get to work on (more or less) whatever you want as long as it’s vaguely related to making RTR more awesome. Best of all, these hack week projects often turn into real, even huge, projects that alter the roadmap of the company! For example, on renttherunway.com we have a feature where users can upload their own photos. Unfortunately, the quality of these photos varies wildly. What if we had a way to automatically give each photo a quality score so that we could show the higher quality photos more prominently? I happen to have a background in machine vision. For my first hack day project, I built a first cut of such an image quality metric. It was simple, but actually showed visible improvements. (In a nutshell, the metric gave preference to images with 1 or 2 faces and images that are overall brighter.) Another example? Our huge new feature, a whole new subscription-based rental model called RTR Unlimited, started life as a hack week project.

But wait! There's more! A recent new hire asked me if RTR_tech does anything with open source. Indeed, we do! For starters, we are committers and some of the main promoters of the aforementioned Dropwizard. We also have more than one OSS project that we produced internally: Alchemy for A/B testing and Conduit for simplifying the use of message queues. I'm certain these projects are just the beginning. In fact, it's worth noting that our internal software development process is modeled to a degree on open source development. We use pull requests for everything, no matter how small, and naturally, have awesome unit test coverage. This is a great way to develop and combines the best of OSS development with the benefits of being in an office right next to your teammates. For one thing, I have found pervasive code reviews to be an excellent way to spin up new people on company standards or languages that are entirely new to them. It really works and has allowed me to remove one worry from my list of "oh man, new person, so much to cover."

All of this sounds fantastic, but we’re a startup so we must be working like dogs, right?

Well...

We have unlimited vacation. Now I admit to being a bit (a lot) cynical. On joining RTR_tech, I assumed that "unlimited vacation" was code for "guilt-based vacation." I was wrong. This is simply not the case. People take lots of time off, myself included, and I haven't seen any guilt-tripping at all. Remember, we're talking about real people here. Awesome people. It turns out, we respect each others’ need for time off. When @MichelleWernick goes to Paris, we all get excited for her and people step up to help fill the gap in QA. When @skamille goes to Hawaii, we don't flood her inbox; we step up and exercise our latent CTO superpowers. When she gets back, there's Hawaiian candy on the kitchen counter and funny stories about emergency room visits.

In fact, it doesn't end with unlimited vacation. We have stellar work/life balance in general. @RTR_tech we understand that the trick is to anticipate, plan, and course-correct a project early. We work hard to avoid feature creep and instead focus on quality. We work smarter, not harder. In this way, we deliver awesome software without people freaking out at the last minute, having to put out fires, and working 12-hour days. Sure, we're not perfect at it, but we've had major successes and we believe in it. We're continuously improving. (How about a Drinks and Demos presentation about what went right and what went wrong in that last big project release? OK!) We embody this in other ways too: Unlimited vacation begets unlimited maternity leave. (I've seen it more than once! It happens! It works! All companies should do it!) And after your maternity leave, maybe you want to have your newborn brought by the office every day so you can take time to feed it. Of course! Who wouldn't allow that? I have a son and a wife. I get to go home and eat dinner with them and when I return to the office the next day, renttherunway.com is still there and I get to do more cool work on it with my fantastic team! I'm more loyal for the stability it provides. I take the time to write a blog entry because of it, and I spend that much more energy recruiting the next awesome teammate because I love telling them about it! What if you don't have a family? What if you're young and unattached? RTR is in NYC! Go enjoy living in New York Effing City!

Did I mention we're encouraged to write articles for our tech blog? Perhaps you've seen said blog? These kind of things are literally listed in our quarterly tech team goals. "1) Ship feature X so we can rent some more dresses. 2) Post 6 tech blog entries."

OK, I promise I'm almost done gushing, but stick with me a bit longer. There's so many more cool things to tell you.

I had a new junior engineer start recently. I gave him a week or two to settle in before I gave him his first major task. Let me set the stage: we're nearing completion of some initial research that uses Python to do Markov Chain Monte Carlo simulation for parameter inference on a Bayesian Network. (To predict the future. NBD.) I asked New Guy to determine if it's viable for us to port that to Java for production use. (The answer, two weeks later, appears to be yes, if a bit inelegantly, via Yadas (Yada Yada Yadas). So that's a thing we do @RTR_tech. Rad, right?

Our interview process is an area we've recently been working to improve (because we're doing lots of it). So how are we doing? Yesterday, I got overwhelmingly positive feedback from a new hire. He thought that it was fantastic to have an RTR_tech engineer guiding him through the whole interview process, answering his questions, being open, honest and enthusiastic. Shortly thereafter, he took the gig. Sounds like it's working!

Did you notice that I used one or two (or forty-two) Twitter handles here? That's because I'd love for you to join our conversation! I want to hear from you! What are we missing? What more can we do? To my fellow RTR_tech-ers (is that a thing?): what is life @RTR_tech to you? Follow us on Twitter @RTR_tech! But don't stop there! Connect with these awesome people about awesome stuff: @skamille, @ericqweinstein, @markwunsch, @bhsdrew, @CarloBarbara, @timx, and many more (use transitive closure to find everyone!)….

This is life @RTR_tech.

P.S. - I really wanted to figure out how I could work in a joke about Talk Like A Pirate Day being a big deal at RTR, but, as any good engineer knows, sometimes you have to kill your little darlings.


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.


Release Notes With Jira and Google Docs FTW!

ColinM_1-thumb
ColinM_1-thumb

We are always releasing code and always trying to make improvements to our release process, and any work related to it. We use Git for SCM so figuring out code differences between prod and the next release is a piece of cake, but getting a nice, clean, and concise list of Jira issues (and some details) that have related code/fixes/improvements/features/stories/etc can be a time consuming pain in the butt. There must be a nice way to do this that doesn't waste half an hour (sometimes longer) when one of our release jockeys is trying to keep everyone in the loop. So I decided to have a stab at it, but didn't want to spend more than an hour or two on this. I like spreadsheets. They can be incredibly powerful and incredibly simple at the same time if used properly. I also like Google Docs (which we use here at RTR). We also use Jira (which I also happen to like, most of the time). Google Doc Spreadsheets have a pretty powerful scripting engine behind them. Jira has a nice, clean REST API. So I decided to spend some time trying to get them to play nice in a very basic, rudimentary way. Less than an hour later I actually had something to show for it, and used it when summing up our latest release.

You start out with a really simple Google Spreadsheet:

jira - after
jira - after

Then you add some Google Script awesome-sauce. We connect to the Jira REST API using basic auth, although OAuth is supported by both Jira and Google Scripts. We also created a read-only Jira user for hitting the API.

[gist id=4455097 bump=1]

In the Google Spreadsheet go to Tools -> Script Editor. Paste in the script, and fill in the [blanks]. Save. Reload the spreadsheet and the Jira Menu should appear after help (this may take a few seconds). Start adding in some Jira Issue Ids, then go to Jira -> Refresh Ticket Data. You should see tickets data populate like this:

jira - after
jira - after

This was just a fun experiment that proved it may be worth investing another hour or two. Jira has a pretty robust API, and Google Scripts give you the full power of JavaScript alongside some nice Google Apps API calls. This is just the beginning!

Some useful links:URLFetch (like making AJAX/CURL calls from a Google Script) HTTPReponse (The response object you get from a URL Fetch) Spreadsheet Services (All you need to master your spreadsheet from a script) Events and Triggers (You don't want your user to have to do too much) Jira REST API