Refactoring Sass with Lists and Maps

At Rent the Runway, we have an internal tool to easily create emails for our customers. It’s a Rails/React system that turns .erb template files into SailThru-compatible layouts (SailThru is our software for sending customer emails).

In this repo we use Sass utility classes. If you’re unfamiliar with utility classes, they’re usually classes that contain a single CSS rule, like so:

.left { text-align: left; }

They’re useful for highly descriptive markup – in our case, creating inline styles for emails. For example, to align your text left in an email, you would use the above class like so:

<td class=”left”> Here is some left-aligned text. </td>

See this post on CSS tricks for a great summary of why inline design is commonly used for emails. Using utility classes allows us to more easily match inline styles to particular email elements.

However, creating stylesheets for utility classes can get messy. We quickly ended up having a number of stylesheet partial files that contained quite repetitive CSS blocks:

The padding partial had almost 200 lines of definitions like that! We had similar problems for heading definitions and background colors:

I could go on, but you get the idea – not very DRY and awkward to add to. What do you do if you quickly need another padding utility class? Just add it onto the end, and worry about duplication later. These stylesheets were getting unruly, unreadable, and impossible to maintain. It seemed like a great opportunity to refactor using two cool Sass features: lists and maps.

First up, we refactored the padding partial to use lists – similar to arrays in other languages. The padding classes were mixed up and mostly named after the padding pixel value specified (e.g. .padding-left-25px). However, a couple used comparative suffixes – e.g. padding-left-max. Our first job was to standardize all the classes to use pixel values in their class names. It’s easier to understand `.padding-left-25px` than `.padding-left-max`.

Next, we grouped all the classes by rules: whether they specified one particular padding (e.g. padding-left), two sides (e.g. top and bottom) or all padding.

Already it was easy to see that there were a couple of duplicate rules. Those could be deleted. The next step was to turn the necessary values into a list. Lists in Sass are incredibly easy to create: just take all values and separate them with commas:

$padding-left-values: 5px, 10px, 20px, 30px, 50px, 70px;

Then, we could use the @each function of Sass to loop through all the pixel values. Using interpolation with #{} , we could name the class appropriately and give the padding value:

@each $px in $padding-left-values {
  .padding-left-#{$px} {
    padding-left: $px;
  }
}

This produces all the classes I need without having to type them all out manually. Also, it makes the process of adding a new padding class far easier: just add the px value to the list.

The next challenge was to refactor the heading sizes. Again, there were a number of repeated classes detailing the various header sizes. However, this time they were named based on relative sizes (e.g. small, medium, large) rather than the absolute pixel value that was found in the style rule.

This called for a map – similar to objects in JavaScript or hashes in Ruby. The heading sizes map had keys that corresponded with the name, and values that corresponded with the pixel size of the text:

$heading-sizes: (
  smallest: 25px,
  small: 36px,
  medium: 40px,
  large: 80px,
  largest: 110px
);

As with lists, you can loop over a map using the @each function. As we’re using both the key and the value, you define both of those first.

@each $size, $px in $heading-sizes {
  .heading-#{$size} {
    @include times($px);
  }
}

Notice here that we’re already using a mixin – times() – that sets an appropriate font family, size, and calculates a line-height based on the font-size passed in.

We did a similar thing with colors, using a color map to loop through and create utility classes for background colors:

$colors: (
  // Primary copy
  midnight: #272c32,
  cotton: #fff,
  // Accent
  tan: #cd9365,
  fawn: #c79176,
  tangerine: #e85940,
  error: #eb5840,
);

// Background colors file

@each $color, $hex in $colors {
  .#{$color}-bg {
    background-color: $hex;
  }
}

Both of these compile to CSS similar to our bloated Sass stylesheets from before. However, it’s much easier to add, remove, or check for duplicate colors or header sizes in this system. Let’s say a new seasonal color needed to be added – rather than having to write out the whole class definition, just add the name and hex value to the colors map.

What’s more, it always feels so satisfying making a commit with more deletions than additions, don’t you think?


Evolving Our Style Guide to Better Unite Designers and Developers

Exactly two years ago Jess Brown wrote Bridging the Design-Development Divide. Her post summed up Rent the Runway’s efforts to create consistent styling, and then translate that styling into Sass variables and classes for easy reuse. This ultimately was embodied in a style guide that lived in GitHub Pages and was publicly accessible.

Jess Brown’s GitHub Pages style guide

Jess Brown’s GitHub Pages style guide

The style guide that Jess created greatly aided in developer-designer relations by ensuring designer mockups were consistent with the colors and Sass stylings powering the site. However, because it was separate from our site and we were rapidly evolving our brand identity, the GitHub Pages style guide quickly fell behind our storefront stylings. There was nothing forcing the guide to be kept up-to-date.

Since Jess’ creation of the first robust style guide for RtR, the company underwent a rebrand as well as a shift towards using React. This created a new opportunity for a more dynamic system of presenting, maintaining, and using our styles. React allows for the creation of reusable components of varying scales such as a button, product card, or even carousel of products. Components can be nested and reused for various purposes, allowing for flexible building blocks to be created for pages. By taking the elements of the styleguide and translating them into React components, we are able to ensure consistent stylings across the site’s elements.

In tandem with the translation of site elements into components, we moved the style guide into the same code base as the storefront. This means that the style guide is powered by the same Sass files that power the site’s front end. Change the font on a button in the style guide and it is instantly reflected site-wide!

The new React component based style guide.

The new React component based style guide.

We then categorize these components for easy discoverability according to Brad Frost’s Atomic Design principles. This means that small components such as buttons, links, etc. are labeled as “atoms.” Collections of atoms are categorized as molecules and so on. If you are interested in creating an atomic design style guide for your own use, checkout patternlab.io. It provides templates for creating style guides that are organized by atomic design principles and served as an inspiration for Rent the Runway’s guide.

So this all sounds great, but one of the biggest challenges is getting cross team collaboration and buy-in to ensure that the living style guide becomes an effective manner of generating consistent styles and fast paced development. For the engineering team, I presented to the Architecture Review Board (ARB) for the introduction of a new grid system in tandem with the style guide. At RtR, we use "ARBs" to screen changes to the way we work, such as using new libraries, or accepting new naming conventions. The ARB for the guide was accepted and the new grid and stylings are being used on Rent the Runway’s pages today. For the product and creative teams, I created Sketch and Photoshop templates of the elements and grid system for use by PMs and Designers, ensuring that the designs the engineering team receives can be built by the frameworks and components in the style guide. In theory, this combined toolkit means every design being passed from a UX designer to a front end engineer can be built by laying out React components from the style guide using the new grid system which in turn greatly reduces repetition of code and speeds up development times.

We will continue to advocate the use of this guide for cataloging, onboarding, and accessibility purposes. By centralizing our styles onto the same Sass codebase, we hope to ensure seamless translation of UX/UI designs into pages.

And one last thing: The new React Styleguide is publicly accessible right on renttherunway.com!


Tech Stack

Lately, RTR's engineering team has been doing a lot of recruiting and when we do anything we like to iterate, iterate, iterate to improve our process. We recently realized that candidates could benefit from a clear, concise picture of our tech stack. So here is that clear (always-work-in-progress) picture!

An image for sharing!

Some things to note:

  1. The groups of boxes correspond with typical engineering roles/responsibilities at RTR.
  2. Developers often think of "full stack" as JavaScript/HTML/CSS UI code on the client side plus Ruby (or Python or PHP or Node) on the server side. In our case, our use of Ruby is a bit atypical. We don't touch the database with Ruby. It's just a thin layer for templating/routing/sessions between JavaScript in the browser and Java REST services on the back end. In terms of engineering roles, Ruby tends to fall on the "frontend" side for us vs. our Java "backend".
  3. Additionally, we don't use Rails. Rather we have a home-grown setup built on Sinatra that we affectionately call Ruby on Rocks. :)
  4. We build a lot of stuff. Our main website, our retail point-of-sales system, the software that runs our fulfillment center, our iOS app, internal tools for customer service. They pretty much all fall into one of the two columns (JS or iOS) shown here.
  5. We have lots of Java services powering all this. Something like 43 Dropwizard microservices at last count. (Pricing, Reservations, Commerce, Membership, Referrals, Recos, Reviews...)
  6. We have some other odds and ends. Some Scala for instance. Some Redis. This picture shows our most common, widely vetted technologies.

And one last important thing: we're hiring!!!


RTR's Core Values

Core Value Award winners

Core Value Award winners

Lots of companies have Core Values, but at RTR we take them very seriously! We have at least two important ways that we keep ourselves focused on them to keep them real:

At our all-hands company meetings, we have the chance to get up in front of everyone and nominate someone for a Core Value Award - describing how that person did something that embodies a particular one of our Core Values!

On our Tech Team we have a software tool that allows us to award micro-bonuses to teammates, tagged with a particular Core Value (#cinderellaexperience)! These micro-bonuses are visible to the entire team, literally echoed in our team chat, and can be redeemed for cool things like gift cards and charitable donations!

So what are these awesome Core Values, you ask?!

An image for sharing!

Rent the Runway's Core Values:

  1. Everyone deserves a Cinderella Experience!
  2. Dream big and go after it!
  3. Make the most with what you have…scrappiness is a virtue!
  4. Debating, honest conversations and collaborating make the company stronger!
  5. Happiness and positivity is a choice!
  6. Embrace the RTR family and bring your authentic self into the office each day!
  7. Bring your best intentions to everything and trust that others do the same!
  8. Adapt and learn from everything you do!
  9. Roll up your sleeves and get involved! Everyone should be accessible and involved with the day to day elements of RTR!
  10. We are all founders of Rent The Runway!

Tell us what you think of these! #honestcollaboration

 


As seen On Apple TV: A HackWeek Memoir

Last week, to celebrate months of hard work, Rent the Runway hosted HackWeek, a week-long hackathon. This was an opportunity to work with new technologies, hardware, languages, as well as coworkers outside of our usual teams.

So on the Friday before HackWeek, we gathered in the kitchen to hear the pitches and decide what projects to work on. That same Friday, Rent the Runway received the AppleTV Developer Kit (Fun fact: we won it in the AppleTV lottery for just one dollar!) Naturally, the mobile team was itching for an opportunity to tinker with our new toy.

On Monday, our team was formed. Its group members? Billy Tobon - Lead iOS Developer, Sandy Woodruff - Product Designer, and Lea Marolt Sonnenschein - iOS Developer.

We spent the first day reading the Apple tvOS documentation, looking at Apple's human interface guidelines, and learning from their examples. We also spent some time thinking of a clever app name. We ended up with TVGunn (Hint: Project Runway). We realized that building applications for the TV relies heavily on a strong understanding of the user interface to create an application that is:

  1. Simple to use: The user should be able to go through the entire app with just a few taps and flicks of the finger.

  2. Actually usable: Asset placement is important in tvOS. If two assets that can be hovered over are too far from each other, the user won't be able make the transition from one to the other.

  3. Sensible: There's actual value in creating a tvOS app. It complements your existing apps and doesn't just exist for the sake of having your app on all available platforms.

 

With that in mind, we brainstormed, sketched, discussed, failed a lot, and learned from our failures. For example, For example, Apple gives developers two options of developing tvOS apps: native, or using their new Television Markup Language - TVML (along with TVJS and TVMLKit). We spent hours trying to figure out what the best template was for our use case, and trying to work with this new XML and JavaScript. At the end of the day, we decided to scrap the project, and start off fresh with a native implementation the next day.

 

FIRST LESSON LEARNED: If you actually want to build something usable, stick to your guns at a hackathon. If you don't care whether the final product works, feel free to explore.

 

On Tuesday, things got off to a good start. We had a plan. TVGunn would be an app placed in Rent the Runway stores that could help users browse through their shortlists in-store. There would be iBeacons placed in the store to detect the user's shortlists, and automatically pull them up on the screen when the user's credentials were verified. This would help streamline the process of interacting with the stylist.

 

Sandy created fantastic mockups, while Billy and I had a clear division of labor on the tvOS side. I was going to work on the app's frontend, while he would try to make our RTR Foundation Framework work with tvOS, so that TVGunn could easily talk to the backend. In the spirit of HackWeek, we decided to write the app in Swift - the RTR iOS app is completely written in Objective-C. Not only that, but we decided to use Storyboards, something many a mobile team dreads like the plague.

 

SECOND LESSON LEARNED: Betas will be betas - things will break and there's nothing you can do about it.

 

In order to develop for tvOS, we had to download the latest Xcode Beta - 7.1. We quickly learned that the Beta is called a Beta for a reason. For example, using Storyboards resulted in a crash every time I tried to drag a new View Controller on the board. I ended up copying the default View Controller set up in the Storyboard 5 times to achieve the user flow that we wanted - #scrappinessisavirtue.

 

THIRD LESSON LEARNED: Cocoapods don't play nicely with tvOS (yet).

 

Despite the Cocoapods fix for tvOS, released on Wednesday, we couldn't import the frameworks we use in our iOS App as pods, so Billy ended up importing them into our project directly. That resulted in a massive amount of errors that took almost two days to debug. In the meantime, Sandy learned how to create LCR files and make use of Apple's new tools to design parallax icons - ParallaxExporter and ParallaxPreviewer. I, on the other hand, tried to figure out how to best mimic Apple's interface. When the user moves from one element to another, the second element has to expand and cast a shadow to create the feedback needed for the user to know what element they're currently on. While this is done for us in some UI elements, like the UITableViewCells, it's not done in others, like the UICollectionViewCells. In order to achieve the look and feel that the user expects, I had to learn how to use special Focus Engine Controls only available on the tvOS.

We could play with this icon for hours!

We could play with this icon for hours!

 

FOURTH LESSON LEARNED: Parallax icons look and feel fantastic. We played with that app icon just a little too long when we finally got it on the screen.


FIFTH LESSON LEARNED: Don't count on everything you see in examples to be pre-built. I had to put in some muscle in order to get the interface looking and feeling the way Apple does in their examples.

 

SIXTH LESSON LEARNED: Swift 2.1 has evolved-a lot. Make sure to always read the newest documentation carefully, instead of just assuming the old ways work. Otherwise you will experience unnecessary frustration.

 

Swift offers a severely streamlined process of creating apps. Unfortunately, because Swift is still evolving, many of the language's aspects have changed with each iteration. Because of that evolution, learning from older examples proved to be a little difficult, because they didn't work with this new syntax. For example, background tasks and requests now have to be wrapped inside a try/catch block.

 

SEVENTH LESSON LEARNED: Persisting data on tvOS is tricky. We knew from the documentation that there was no local store in the appleTV, and we planned not to persist anything in the device, but when we tried to use a SaaS solution (Parse) as a bridge between iOS and tvOS the app wouldn’t even load, because most of these types of frameworks use local store for caching.


 

In the spirit of HackWeek, we ended up using Parse via REST, and storing user credentials to Parse in plaintext (a definite no, no in production apps) based on data received from the iBeacon. Inside the app, we used a timing function that periodically checked if a new user had appeared on Parse. If there was no user on Parse, the app would play the official RTR promotional video. If the user appeared, however, the app immediately redirected to their shortlists.

 

By Friday, we ended up with a pretty solid working demo, and presented it to the whole company. Billy presented the hack and explained how it works, while Sandy and I did a small roleplaying sketch to make sure everyone understood our use case. Everyone seemed to enjoy it, and we're excited to explore its use. Even though, the demo was a success, we all know that the app has several problems, and is therefore not ready for production. Because this was HackWeek, though, we allowed ourselves to use not-so-stellar coding practices, pass data that shouldn't be passed around willy-nilly, and all in all, hack our ways until we made it work.

 

EIGHTH LESSON LEARNED: Never use the "F*** it, ship it!" method. If you decide to make a hackathon project a production project, scrap the whole thing and start from scratch. This will allow you to follow good development practices, and create a well-maintainable product, instead of having a codebase with so many leaks, you spend more time working on covering up the problems, rather than fixing them and focusing on moving the product forward.

 

All in all, HackWeek was a fantastic experience and a great success. Our team collaborated well and iterated quickly. We learned a lot of new things, and in the end produced a beautiful and exciting app using completely new hardware. I'm extremely proud of my team, and couldn't be happier I worked with them this entire week. We all can't wait to actually create a live Apple TV app, because we believe that the Apple TV has tremendous potential for how our customers can experience Rent the Runway!

Yours in Fashion,

Lea, Sandy & Billy