In making Gilt.com responsive to the mobile device, the Special Ops team identified several responsive patterns that we relied upon to “responsivize” our site layout. Identifying these patterns early on helped us to more confidently make subsequent responsive-related decisions. For our fourth responsive-related blog post, I would like to share how we discovered and implemented one of our favorite design patterns that we identified: the full-screen modal.

The Gilt iPhone app was the primary source of responsive design inspiration for our team. One of our iPhone app’s strongest design elements is its full-screen view for filtering, which differs greatly from the filtering layout on Gilt.com where filtering exists as a set of dropdowns on the sale page and a sticky sidebar on the search page.

The app’s filtering:

image.png

Gilt.com’s filtering:

Screen Shot 2014-07-08 at 5.08.21 PM.png

The full Gilt site’s filtering style fits well on both PC and tablet-sized screens, but is too large for mobile devices. This is one of the reasons our current mobile site (m.gilt.com) does not give users the filtering feature. With this in mind, our team emulated the Gilt iPhone app’s design by creating a full-screen view for filtering on mobile-sized screens. This pattern uses almost exclusively CSS (we use less.js) and therefore doesn’t add significant size to the pages’ payload.

Full-screen modal was simple to implement, so we decided to apply it in other places on the site—for example, in a product’s size chart. Here’s a JS Bin that demonstrates our implementation.

On narrow screens (a mobile device in landscape, for example) and tiny screens (a mobile device in portrait):

  •  Set the content’s wrapper element to
position: fixed
display: none

          by default, and set it to fit the entire screen

  • Add a call to action that’s visible only on narrow and tiny screens, and that, when clicked/touched, adds the class ‘content-open’ to either the content’s parent or to the content itself
  • Add CSS to display the content when the ‘content-open’ class is added
  • Add a no-scroll class to the body when the button is clicked that sets the whole page to
position: fixed

           this prevents the body from scrolling behind the open modal

  • Add a button/action in the open content modal which closes the content and returns the user to the full page

Special Ops believes that the best mobile user experiences permit users to focus on a page’s core content without being distracted by other features. With the full-screen modal, we abstracted away all the complexity of the filtering into a separate user experience and gave the abstracted feature the full-screen ‘real estate’ it deserves. Everything the user sees—a product, a list of products, etc.—is built around this simplified experience. Now that this pattern is well understood, we plan on continuing to use it in our future responsive design efforts.

Screen Shot 2014-07-06 at 11.07.35 AM.png

Screen Shot 2014-07-06 at 11.07.45 AM.png

In our last blog post on responsive design at Gilt, my colleague Greg Mazurek explained why we use in-selector CSS media-queries instead of blocks. The impetus for choosing this pattern was to make our code less brittle to future development. Today I’ll talk about how we’re applying the same principle to our testing practices.

We’ve thought a lot about how we can design our code to minimize—even prevent—unexpected adverse changes made during future development cycles. The Gilt engineering team uses automated testing for all of our apps, but in transitioning to a responsive design environment many of these tests have become inapplicable because page elements have been shifted, hidden, altered, or added. Furthermore, if a developer makes a change to a CSS property for a tablet experience, she needs to know whether this change might adversely affect the mobile web experience. A modified class name, a JavaScript side-effect, or a CSS specificity change are three possible negative consequences of such a change.

To deal with this potential problem, the Special Ops team has been writing Selenium-automated tests for responsive pages—more specifically, for each browser responsive breakpoint. (If you are unfamiliar with Selenium, it is a web testing framework that allows you to automate your web application within the browser. Its robust API interacts with your website the way a user would, and can handle automating most scenarios.) First, we have a browser resize itself to the breakpoint we want to test—for example, iPhones in portrait view fall under a maximum width of 479px, while in landscape its a minimum width of 480px, and a maximum width of 767px. With Selenium, via the web driver object, this is very easy to achieve.

Here is a small snippet of what that code might look like:

def resizeWindow(width: Int, height: Int)(implicit webDriver: WebDriver) = {
  webDriver.manage().window().setSize(new org.openqa.selenium.Dimension(width, height))
}

This reusable piece of code is what you’ll want to execute before the start of each test. Execute it before, not after, the initial page load, to ensure your site responds as it natively would at those breakpoints (rather than scaling your site down—which could cause inconsistencies with the view). Executing the code before the initial page load will also help you to ensure the automation doesn’t start before the browser has fully scaled down.

Example

To help you ensure that a page responds correctly to the appropriate viewport of the screen or device, here is a very basic test. It uses Selenium with ScalaTest and a dash of jQuery (there are many ways to test, but this is my preferred way):

describe("When resizing the browser to 479px and navigating to product listing page") {
  it("should fit all the elements within the 479px limit") {
    val expectedPageWidth = 479
    resizeWindow(width = expectedPageWidth, height = 800)
 
    webDriver.navigate().to("http://www.gilt.com/sale/men")
 
    // Using scrollWidth instead of width(), to get the true width of the html container
    val actualPageWidth = webDriver.asInstanceOf[JavascriptExecutor]
      .executeScript("return $('html')[0].scrollWidth;").asInstanceOf[Long]
 
    actualPageWidth.toInt should be <= expectedPageWidth
  }
}

(Note: Your page should not be scrollable to the right.)

That’s all there is to it. If you have no other test, at least this one will ensure your site is still responsive. But we highly recommend adding more specific tests that target the functionality of the site.

image

Lisp is an interesting language. Its emphasis on functional programming and properties such as homoiconicity make it quite different from other languages. Although it’s not suited for all developers, those who have experienced building large applications in other languages may appreciate the simplicity that Lisp provides.

When I ask other developers for their thoughts on Lisp, the most common response I receive is, “Why are there so many brackets?” As it turns out, Lisp’s brackets establish some consistency across the language that allows for some neat code-writing tricks. So neat, in fact, that they can make coding a Zen-like experience. Read these tips and you’ll soon be able to make onlookers wonder how you’re able to make code fly around the screen so quickly and elegantly—and with just a few keystrokes.

Lisp Refresher

For those of you who aren’t quite clear on Lisp syntax, here are a few basic things to know:

  • Everything is a list
  • The first element in every list is the “function call position”

That’s it! Easy, right? Let me show you a few examples written in Clojure (a dialect of Lisp) to make things more concrete. First, a standard “Hello World” example:


(println "Hello World")

In Clojure, you create lists by using rounded parentheses. The first element in this list is println, so we are calling a function called println with a single argument “Hello World”.

Next, we create a new function called inc:


(defn inc
  "Define a fn that increments a number by 1"
  [x] (+ x 1))

The first element (the one in function-call position) calls a special function called defn that allows us to create a new function. The other arguments are:

  • The name of the function we want to define—in this case, inc
  • A string comment that we can use as a human-readable description of what our function does
  • [x] is a vector of the arguments that our new function will receive
  • The body of our function

In this final example, we create a try-catch statement:


(try
  (/ 1 0)
  (catch ArithmeticException e (println "Kaboom!"))
  (finally (println "We’ve recovered!")))

We can start to see from this example how lists can be nested to provide richer programming capabilities. This nesting actually results in a tree structure (which in compilers is referred to as an ‘abstract syntax tree’) that provides the basis for some interesting coding workflows.

The Structure of Lisp

To illustrate what this abstract syntax tree looks like, let’s draw the try-catch example as a tree:
image
I’ve omitted the “finally” block to keep the illustration compact, but it should be clear now how we can visualize Lisp code as a tree. The workflow tips in this article revolve around making edits to this tree: navigating to parent nodes, moving a branch, removing levels, etc.

***I’ll provide these tips specifically for Vim, but there are equivalents in Emacs as well if you prefer that.***

Without further ado!

Tip #1: Give your brackets some color 

image

Rainbow Parentheses’ is a plugin for text editors that will change the color of your brackets depending on their depth in a list. This enables you to visually recognize the start and close of a particular list. Once we can visualize this, it becomes much easier to jump between depth levels.

In the above gif, the cursor starts inside the println then makes jumps upward to each parent node in the tree (println -> catch -> try). These jumps can be performed with the ParEdit plugin while in normal mode by pressing "(".

Tip #2: Keep your parens balanced

image

There’s nothing worse in Lisp than having unbalanced parentheses—especially if you have blocks of code that include several levels of nesting. Finding which block is missing a closing bracket can become a nightmare. Fortunately, ParEdit can prevent us from having this problem.

Say we have a try-catch-finally block and wish to delete the ‘finally’ clause. In Vim, we can easily remove this entire line when in normal mode by pressing ‘dd’. The problem is that if we do this, we will make our parentheses unbalanced by deleting the closing bracket of the try block (in the above gif, the closing red bracket).

The ParEdit plugin solves this by forcing our brackets to always remain balanced. With paredit enabled we can perform ‘dd’ to delete the line and delete everything except for any brackets necessary to maintain balance.

Tip #3: Learn motions. Master the brackets!

image

Vim provides motions right out of the box, with no additional plugins needed. The handiest motions for dealing with parentheses are “select in” and “select all.” These can perform actions on an entire list in just a few keystrokes. For example, say in our try-catch block we want to return positive infinity instead of print a message. Place the cursor inside the println list, issue a “select all,” and hit “c” for “change.” This will replace the entire println list in just three keystrokes.

Note that “select in” will select everything inside the parentheses, while “select all” will select everything inside the parentheses (including the parentheses themselves). This command will work with round brackets, curly brackets, square brackets and even quotations, making it useful in other non-Lisp languages as well.

Here’s a cheat sheet for using these commands:

  • viw - select in word
  • vi( - select in round bracket
  • vi{ - select in curly bracket
  • vi[ - select in square bracket
  • vi” - select in quote
  • ciw - change in word
  • ci( - change in round bracket
  • ci{ - change in curly bracket
  • ci[ - change in square bracket
  • ci” - change in quote
  •  va( - select all round bracket
  • va{ - select all curly bracket
  • va[ - select all square bracket
  • va” - select all quote
  •  ca( - change all round bracket
  • ca{ - change all curly bracket
  • ca[ - change all square bracket
  • ca” - change all quote

Tip #4: Nest with ease!

image

Say we want to assign the result of our try-catch statement to a variable name. This can be done in four easy steps:

  1. Place your cursor on either the opening or closing bracket of the try block (one of the red brackets)

  2. Hit “v%” to select everything up to and including the matching bracket

  3. Using the ParEdit plugin hit <Leader>w( to wrap the select text in another set of parentheses

  4. Inside the new parentheses, write the code to make the assignment

  5. (Optional) In the gif I have done an optional fifth step to re-indent the code by selecting the block and pressing the equal sign. “=” is a standard Vim command to re-indent.

Tip #5: Barf and Slurp!

image

 Barfing and slurping are terms used in the ParEdit plugin. These operations depend on the location of your cursor. Barfing will eject (“barf”) either the first or last element of the list where your cursor is placed. Slurping is the opposite: A slurp will find the first element to either the left or right of the list where your cursor is and slurp that element into the list.

In our try-catch example, say we create a new function called my-function. We then want to move the try-catch block inside this function so that we can call it later. Naively, we could select the try-catch block, then cut and paste it into the function body. Alternatively, in two keystrokes we can slurp the entire try-catch block into the function body! We can perform the opposite operation by then barfing the try-catch back out.

The concept might take a few minutes to sink in, but once you understand these operations you will be able to push code around like a pro.

Vim Plugins

Here are links for the vim plugins I used in the above demos:

(Lambda bird formation photo by Sigfrid Lundberg)

This is the second of five posts the Special Operations team is sharing on what we learned while making legacy applications responsive to mobile devices. In our first post, we gave a high-level overview of how we organized a successful team retrospective. In this post, I’d like to dig a little deeper into the technology side of our work and discuss how to organize media queries.

CSS3 media queries enable you to present content to a specific range of devices without having to change the DOM. If you have a view, you can use media queries to let your users see content that fits well on a mobile device, a tablet, or a desktop screen. Media queries make it easy to make separation of concerns within stylesheets without having to change the underlying DOM structure.

A media query generically looks like this:

At Gilt, we think a lot about how to use media queries so that they scale across many applications and many, many CSS files. Responsive design only increases the amount of complexity in an application. When you use media queries, your CSS files become longer, and changing the DOM becomes much riskier.

To limit the degree of complexity we’re adding—and also increase Gilt’s developer happiness KPI—we’ve adopted two useful patterns for using media queries. First, we establish variables that define our viewport breakpoints, and we reference these variables throughout all of our .less files. Our four breakpoints try to capture device widths that fit a desktop/laptop, a tablet in landscape mode, a tablet in portrait mode as well as a phone in landscape mode, and a phone in portrait mode. They are:

If the variables change at any point, all of our .less files will pick up these changes.

It’s important not to include “@media” in your variables, because you’ll sometimes want to reference multiple media in one query. For example:

The second pattern surfaced as a result of large, gnarly CSS files. When we first started adding media-queries to legacy CSS files, we added large media-query blocks to the end of each file. We did this because wanted to support IE7 (ugh… and of course, IE7 doesn’t support media queries). So, our .less files looked like this

This pattern is OK if your file is small, but becomes quite burdensome when the CSS is so long that the media queries are hundreds of lines away from the selectors that they override. You might have a selector at line 2 that is overwritten for a specific media in line 300. This creates significant opportunities for errors. An engineer working on a selector on line 2 might not think about scrolling to line 300 to change the appropriate property in a media query below.

While we were progressing with our work, Respond.js appeared. Respond.js is an open-source polyfill that handles CSS3 properties like @media for IE6, IE7, and IE8, and enables you to include your media queries anywhere. We started using it at Gilt to avoid having to place our media queries at the end of our CSS files.

Which brings me to our second media query design pattern: we use inline media-queries on CSS selectors rather than placing the CSS selectors in media-query blocks. For example, we can now write the above code sample like this:

Given this short code sample, the developer happiness gain here might not be immediately obvious. If you include the media query in each CSS selector, your engineer knows all the locations where the properties are being overwritten. This limits the chances for changes that unknowingly impact media queries elsewhere. We’ve relied upon inline media queries to keep the separation of concerns in check for us.

To summarize: We highly recommend creating variables to handle your media queries and writing your media queries inside the CSS selectors that they modify. With these two patterns, we think your responsive design workflow will be easier to maintain in the future.

Tune in next Monday (July 7, after the American holiday) for “Responsive Gilt.com: Selenium Edition”!

Here’s Gilt Co-Founder and CTO Michael Bryzek at last month’s Dockercon14 conference in San Francisco, discussing how our engineering team has been experimenting with Docker to improve and simplify end-to-end continuous delivery of our micro-services architecture. Next week Michael will give an updated version of his talk at the inaugural Docker Dublin meetup, hosted at Engine Yard!

Docker is releasing two videos per day from the conference—check them all out here.

A cross-functional team featuring the Gilt tech, marketing, HR, merchandising and finance departments gathers around the TV to watch the USA vs. Belgium World Cup match. As of this writing, the game’s still underway!

image

It was one year ago today that we held our first free tech course at Gilt: an Introduction to Scala course hosted by our NYC office! Since then we’ve hosted twelve additional free courses in Scala, Hadoop, Machine Learning, Cassandra, AngularJS, and several other topics. Nearly 500 non-Gilt folks in NYC and Dublin have joined us for our full-day, classroom-style sessions, taught by Gilt technologists and external experts.

We’re excited to bring you many more free courses over the coming months, including next week’s AngularJS session in Dublin and our July 14 sbt workshop with Josh Suereth of Typesafe; just click the respective links to apply.

If you’re a tech expert who would like to pitch us for a course, feel free to ping us via Twitter. (Dublin or NYC residents only, unless you plan on swinging through one of these towns sometime over the next year.)

image

Gilt’s Special Operations Team recently spent five weeks creating a legacy Play app that’s responsive to the mobile device for both portrait and landscape orientations. After our team finished our work, we got together to recap what we’d done. We also decided to share with you what we learned while converting Gilt’s desktop experience into a beautiful responsive mobile experience that seemed natively designed. In this post—the first in a series of five—I’d like to share how we organized a successful retrospective meeting.

As a small team, the three of us who belong to Special Ops (which handles end-to-end projects that don’t fit under the umbrella of other product-driven teams) are always very aware of what our teammates are working on, so we didn’t need to sit in a room to talk about that. Instead, we wanted to talk about some of the higher-level topics that surfaced while we were working in the weeds. To prepare, each of us spent half an hour writing on individual sticky notes the reasoning behind our choices. We then brought our personalized notes to the meeting, which had three goals:

  1. List all the things that we thought we did awesomely.

  2. List all the things that we want to do and don’t want to do in our next project, so we can heighten awesomeness levels even more.

  3. Give high-fives.

We rated our achievements and shortcomings in eight buckets:

  • internal teamwork

  • external teamwork

  • efficiency

  • knowledge

  • development workflow

  • testing workflow

  • general feeling about code quality

  • evangelism (getting people outside our team involved and including them in our work)

We arranged these buckets as points along a Y axis (aka “the category axis”), and used the X axis (aka “the awesomeness axis”) to measure our feelings of how well we did. For each of the eight buckets, each team member placed a sticky note with their initials somewhere on the X axis between a :( (at the far left end of the spectrum) and a :) (at the far right).

image

Then each of us explained why we placed our initials along the awesome-ness axis with concrete examples and explanations. At the end of the hour, our whiteboard was filled with sticky notes that neatly plotted out our satisfaction and dissatisfaction with various aspects of our work.

Our team retrospective was very important for us because, even though we work closely together, each of us gained valuable insights into the primary motivators, goals and concerns—be it better tooling, better development workflow, better testing processes, or better communication. In software engineering, the work never ends. But by holding a retrospective, we were able to look back at what we did in order to try to continuously improve as engineers.

image

Tune in tomorrow for “Inline vs Block Media Queries”!

Gilt Principal Software Engineer Gregor Heine added a frothy finishing touch to last week’s 5@4 in Dublin by brewing up a batch of his homemade ale for the team. Gregor gave a brief “Intro to Homebrewing” course (to be cont’d in future 5@4s) and included a live demo as part of his instruction. Now the Dublin team has to wait two weeks to sample his work!

Our Data team held their very first Looker hackathon and kicked off what promises to be an exciting year-long project that will impact many different Gilt departments. Lead engineers and analysts from Looker came to our NYC office to help us throughout the day. “We started work and expanded on over 10 new data models in the tool,” says Gilt Business Intelligence Engineer George Chien. “We also identified several new enhancements that we’ve suggested to Looker. Our team will be instrumental in shaping the tool’s development roadmap.” That’s Director of Data Engineering Geoff Guerdat at the screen, leading the way.

To learn more about Looker at Gilt (and to see what Geoff looks like with a wooly wintertime beard), check out this brief slideshow from our February meetup with the Looker User Group.