iOS Data Binding is Better with Signals

Here at Rent the Runway, we want to make sure that all of our users have a responsive and rewarding iOS mobile app experience. With our backend architected to use many highly performant microservices, there is a whole lot of data and user interactions to keep in sync. We have services for user memberships, promotions, products, search categories, user hearts, and so much more. Without a one-to-one mapping of API service calls to application views, it was critical that we come up with a robust and coordinated approach for data binding and content updates.

One of the main iOS communication patterns is delegation. Delegation creates a one-to-one messaging structure between two objects, where one object can act on behalf of another. Using this pattern, it is typical that a completed API call would inform its delegate object that new data exists and is ready for processing and/or display somewhere else in the app.

On this diagram we can see that we have several UIViewControllers (ProductCollectionsVC, ProductsGridVC, ProductVC) that hold a ModelController (HeartsMC), which is responsible to fetch all the hearts from a user. 
While this approach is useful in many situations, it makes it difficult for communicating data updates from one object to many objects at the same time as we can see on the diagram.
 
As an alternative to delegates, we can use ReactiveCocoa’s framework to use signals for communication. In short ReactiveCocoa is a functional reactive programming framework which represents dataflows by the notion of events. An event is just a concept that represents that something happened, which could represent a button being tapped or the status of a network call being made. ReactiveCocoa uses Signals and SignalProducers to send messages representing these events.  A Signal will only notify an observing object of events that have occurred after the observer has started observing, not any past actions. On the other hand, a SignalProducer allows you to start observing for an event but also have the visibility for past and future events.

ReactiveCocoa explains these concepts by comparing them to a person (the observer) watching television (the signal or signal producer). 

[A signal] is like a live TV feed — you can observe and react to the content, but you cannot have a side effect on the live feed or the TV station. [A signal producer] is like a on-demand streaming service — even though the episode is streamed like a live TV feed, you can choose what you watch, when to start watching and when to interrupt it.
— https://github.com/ReactiveCocoa/ReactiveSwift

Signals work very well for UI events like tapping a button, where an observer would only be interested in reacting to touch events after it has started observing. A Signal Producer would be more useful for a network request, where its on-demand nature would help provide more contextual information about a network request, such as allowing an observer to know if it is in progress, has it previously failed, should we cancel it, etc.

Objects throughout our app can then observe these event-driven signals and take any action they need to bind data to views, process data, or trigger any other actions. This allows multiple views and viewControllers in our app to be notified of data changes at the same time without the need for complex delegation chains. 

In the code snippet above, we are setting up signals for a modelController. When it receives a signal, it can call a method that is defined by our protocol. If we were to configure these methods and interactions with a delegate, other ViewControllers would not receive any message and would not know to update their data.

In the app, we have a TabBarController that allows users to quickly switch between viewControllers that provide different functionality. However, we do have some shared data sources between these controllers, so our signals allow us to update data on every accessible viewController so the user can interact with them immediately after switching tabs.

This approach has been very helpful for broadcasting changes of the datasource on a ModelController throughout the app. While implementing, we paid special attention to weak/strong references with our observers to prevent retain cycles, routinely testing that objects were being deallocated when needed. Additionally, deadlocks can occasionally occur if signals trigger other signals that are dependent on the completion of another signal. However, with well thought out protocols and implementation patterns, we have been able to provide a responsive and stable app experience for our users.


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