Given our love for Docker—not to mention Principal Systems Engineer Jonathan Leibiusky’s recent open source work)—the topic of our next free tech course is super-exciting and also timely. Go is an open-source programming language aimed at increasing developer productivity. During this class, we will explore the benefits of programming in Go and learn the basics. By the end of the day, you will have built:

  • A basic webapp using only the built-in standard libraries
  • A more sophisticated web app that supplements the Go standard library
  • with some third-party tools
  • A web scraper for some basic data analysis
  • A tool for conducting basic natural-language processing in Go

Teaching the session is Aditya Mukerjee, who has been writing Go professionally since the first stable release of the language, and is an author of several open-source Go libraries.

Details:

When: August 22, 2014 from
Where: Gilt’s office in NYC

About the Instructor: Aditya Mukerjee is the co-founder & CTO of BoardRounds, a health-tech start-up focused on ER followup care. Prior to founding BoardRounds, he was a student at Cornell University’s NYC Tech campus, during which time he served a partner on First Round Capital’s Dorm Room Fund. As a member of Foursquare’s server team, he worked on the Explore recommendation/search engine, and as a member of OkCupid’s data team he worked on OkTrends reports. He studied statistics at Columbia University and is a hackNY alumnus (‘11) and mentor, as well as a mentor for the Thiel Fellowship.

image

August 8-9 marks the first-ever Scala By the Bay conference: two days of training, talks and reverie for the San Francisco-area Scala and functional programming community. Scala By the Bay is made possible by Alexy Khrabrov, conference co-organizer (along with Jason Swartz) and founder. Alexy’s also the founder and co-organizer (along with Swartz) of SF Scala, whose +2K members “use Scala to dominate the world.” Exciting! We chatted with Alexy to find out more about next week’s conference—try to go, if you can!

Compared to last year’s Silicon Valley Scala Symposium, which you also organized—and have rebranded as SbtB—what’s different and new about this year’s conference?

This year everything is different. We renamed the conference Scala By the Bay to attract folks from all over the world to our beautiful area. We’ve rented Fort Mason for the location and are holding the conference over two days instead of one. We ran a proper call for proposals, and selected a very competitive program. We decided to do just one track to make the conference more communal, and have a hackathon and an unconference scheduled for the evenings.  

You’re also offering training this year.

Yes, Scala and Spark training sessions; both are filling up rapidly.  My company, By the Bay LLC, is a Typesafe Training Partner, and we offer Spark training jointly with Databricks. After the conference I’ll do training regularly.

In terms of topics in Scala, what’s new or different about this year’s conference?

The Big Data/Scala theme is even more powerful this year, with a separate keynote on Spark in Scala given by Databricks CTO Matei Zaharia, who wrote the original Spark in Scala. The other keynote will be by Marius Eriksen, whose work at Twitter has demonstrated how Scala can power web-scale companies in real time.

How many people submitted talks?

We received nearly 50 proposals for about half that number of speaking slots. Some of the proposals we compressed to halftime. It’s still plenty of time and much more informative than lightning talks, and lets folks get a taste of the tools and approaches (which are hard to pick up on your own, or not as exciting).  We hope folks who didn’t get into the main program will propose their talks to the unconference.

How many proposals came from women?

We do have talks from women, but should work more on the outreach.  I’m personally following up on it, and this work started to pay off.

Did you notice any patterns, trends or similarity topics-wise?

Big Data is ascendant, with Spark a darling of the whole Big Data community at large.  We see people registering to learn Spark, which they then realize is in Scala, and so they join SF Scala next and ramp up on Scala itself. Akka is a perennial favorite, with not one but two proposals showing how to run farms of R servers with it—building a SparkR at home, so to speak. Various aspects of Play and web applications are dominating, showing how Scala-based web apps are taking hold.

Who is traveling the longest distance to speak?

Someone is coming from Hungary, and another from Argentina. 

What surprised you about this year’s proposals?

The sheer strength and depth.  Also the amount of type-related work, which got many votes. Scala folks are intellectually rigorous and efficient at the same time, and that’s why we’ll eventually take over the world.

How has the SF/Bay Area Scala community grown/changed/evolved over the past year? What would a visitor expect to find?

Play, Akka and Spark are growing exponentially and bringing more and more Scala beginners to the community.  The importance of professional training is obvious, hence our offerings.  More startups are relying on Scala, and whole categories of businesses are aligning around it, such as healthcare-related API startups. 

If I’m a Java programmer who’s new to Scala, will I be able to follow along with the talks?

You’ll have a much better time if you begin by taking Fast Track to Scala with Brendan McAdams on August 6-7. Brendan is a bona fide Unix/Scala/Akka longbeard, and he authored both the original and reactive Scala drivers for MongoDB. But our Scala speakers are excellent communicators, so every level of ability will be able to advance to the next one.  See you shortly By the Bay!

image

With The Shops, Gilt’s Product/UX team has just made it easier than ever to shop on Gilt for basics and special-occasion items, and to browse for inspiration. This new feature provides a destination spot for our customers who are looking for:

  • Men’s and women’s attire for special occasions such as weddings, parties, and holidays

  • Denim, dress shirts, and other wardrobe essentials

  • Home décor ideas and advice

  • Must-have’s for your babies and children—including everything from Easter attire to comfy onesies for newborns

We launched The Shops as part of our mission to provide ever more consistent and dependable destinations for our members. Let us know what you think of this and other new features by emailing us at productfeedback@gilt.com!

image

image

image

PageObjects enable you to take a group or collection of elements on a page that share some commonality and group them together. In general, a PageObject can be any web page, but can also be broken down into more precise PageObjects. If a Page has elements and services—or some repeated group of elements and services—that can logically be grouped together, those elements and services can be modeled as PageObjects.

A PageObject can be thought of in the context of a full Page or grouped objects on a Page. Here’s what Selenium has to say about them:

“The PageObject pattern represents the screens of your web app as a series of objects … PageObjects can be thought of as facing in two directions simultaneously. Facing towards the developer of a test, they represent the services offered by a particular page. Facing away from the developer, they should be the only thing that has a deep knowledge of the structure of the HTML of a page (or part of a page).

It’s simplest to think of the methods on a PageObject as offering the “services” that a page offers rather than exposing the details and mechanics of the page. Because we’re encouraging the developer of a test to try and think about the services that they’re interacting with rather than the implementation, PageObjects should seldom expose the underlying WebDriver instance. To facilitate this, methods on the PageObject should return other PageObjects. This means that we can effectively model the user’s journey through our application.”

Selenium

At Gilt, we’ve adopted the practice of breaking a Page into smaller parts that can be modeled as PageObjects. We’ve done this to generate fewer lines of code and to make PageObjects easier to understand and analyze.

A PageObject should be an object; otherwise, it should be a class with constructor params that provide the context. For example:


package com.giltgroupe.repository.page.foo

/**
 * Foo PageObject.
 */
object Foo extends FooActions with FooAssertions{
 def doSomethings
     (implicit eventType: EventType, driver: WebDriver): Foo.type = {
     clickSomething
       triggerSomething
       selectSomething
    this
  }
}
package com.giltgroupe.repository.page.foo

/**
 * Foo PageObject.
 */
case class Foo(foo: String) extends FooActions with FooAssertions{
 def doSomethings(foo: String)
     (implicit eventType: EventType, driver: WebDriver): Foo.type = {
     clickSomething(foo)
       triggerSomething
       selectSomething
    this
  }
}

Here, the PageObject Foo can extend Actions. It can also be mixed with Assertions and even Rich Actions.

More on Actions

Actions can either be simple or rich.

Simple Actions:

  1. Provide a PageObject return type.
  2. Are located in an Actions trait.
  3. Should simulate user actions e.g., clickSomething, triggerSomething, selectSomething. Should not make any Assertions. In other words, an Action does one thing well.
  4. Assertions should happen as part of the test and should not be included in the Action. If there is an Assertion that is reusable, it should be located in an Assertions trait for the PageObject.
  5. Rich Actions: Are located in the PageObject Can be a number of grouped simple actions which are commonly used. Simple vs. Rich Actions A rich action is made up of a number of Simple Actions. clickSomething is a simple action described above. triggerSomething and selectSomething are also simple actions. Calling them together makes a it a rich action. Here’s an example of a simple action:
private[foo] trait FooActions extends BrowserAction {

  def locators = FooLocators  

  def clickSomething(foo: String)
     (implicit eventType: EventType, driver: WebDriver): Foo.type = {
     click(locators.myDefLocator(foo))
    this
  }

 def goFooUrl(url: String)
    (implicit driver: WebDriver): Foo.type = {
       go to url
 }

And here is a Rich Action:


  def doSomethings(foo: String)
     (implicit eventType: EventType, driver: WebDriver): Foo.type = {
     clickSomething(foo)
       triggerSomething
       selectSomething
    Foo
  }

The Gilt engineering team has been discussing the value of rich vs. simple action terminology. We haven’t yet decided if locating the rich actions in the PageObject is valid, or if rich and simple actions should just be actions because they all live inside the Actions trait.

BrowserAction

Gilt’s Selenium automation is built around the ScalaTest Framework. The WebBrowser trait, which we can see in the following code example, can be found here. BrowserAction is a wrapper for Selenium WebDriver that removes much of the required boilerplate. We’ve been using BrowserAction so that engineers who aren’t familiar with Selenium can still write cool end-to-end tests (instead of copying and pasting code):

/**
   * Click on a WebElement by using native or synthetic event simulation.
   *
   * @param query : WebBrowser#Query to define the webElement
   * @param eventType : Native or Synthetic.
   */
  def click(query: WebBrowser#Query)(implicit eventType: EventType, driver: WebDriver) {
    WaitTool.waitForElementClickable(query)
    eventType match {
      case Native => query.webElement.click()
      case Synthetic => JQueryHelper.click(query)
    }
    JQueryHelper.pageIsLoadedAndAjaxIsCompleted()
  }

The click action is based on the implicit event type passed to it by the test, and waits for an element to become clickable before it carries out the action.

The code above shows a simple action, which performs a mouse click on the page on the element. This is subsequently passed as an argument to the function click. There is an implicit, EventType, which defines how the browser should behave—either Native or Synthetic.

The Gilt team has developed a library called WaitTool, which handles implicit waits and expected conditions. The click action uses WaitTool, which hides the complexity of making sure that the element—which was passed to the click function—can be clicked. As soon as the element becomes clickable by Selenium WebDriver, a mouse click is performed (dependent on the EventType). The last step of the action click is to wait for page to load, and also wait for all Ajax calls to complete.

The click action nicely shows how you can hide some of Selenium’s complexity behind a simple action. As a result, people who lack Selenium WebDriver expertise or a full understanding of what goes on under the hood can write a test and get a clear API (click function) to use.

With WaitTool, upon entry into an action we can wait for expected conditions to be true, then carry out an action:

/**
   * Wait for the element to clickable in the DOM.
   *
   * Returns an Option of the first WebElement using the given method.
   *
   * @param query selector to find the element
   * @param timeOutInSeconds time to wait until returning None
   * @return an Option of the first WebElement using the given method, or (None if the timeout is reached)
   */

  def waitForElementClickable(query: WebBrowser#Query,
                              timeOutInSeconds: Int = DefaultWaitTimeForElement)
                             (implicit driver: WebDriver): Option[WebElement] = {
    try {
      driver.manage().timeouts().implicitlyWait(0, TimeUnit.SECONDS)
      val element = {
        val wait = new WebDriverWait(driver, timeOutInSeconds)
        wait.until(ExpectedConditions.elementToBeClickable(query.by))
      }
      driver.manage().timeouts().implicitlyWait(DefaultWaitTimeForElement, 
                                                TimeUnit.SECONDS)
      Some(element)
    } catch {
      case e: Exception => None
    }
  }

To ensure we can exit the action correctly we then wait for the DOM or page to be loaded, and for all Ajax calls and other actions to be completed, before returning control to the caller or carrying out the next called Selenium action. This enables us to instantly and easily see how our work flow is naturally progressing. Without such a library, test cases look muddy, unclear and unreadable.

  /**
   * Ensure the page is loaded and AJAX calls are completed using jQuery.
   */
  def pageIsLoadedAndAjaxIsCompleted()(implicit driver: WebDriver) {
    eventually {
        withClue("Ajax calls may not have completed within time specified") {
            executeScript("return jQuery.active")
             .asInstanceOf[Long] shouldBe (0)
        }
    }

    eventually {
        withClue("Document ready state was not [complete] within time 
                  specified by eventually clause.") {
              executeScript("return document.readyState")
              .asInstanceOf[String] shouldEqual ("complete")
        }
    }
  }

Locators

Locators should be objects, not traits. As objects, locators are naturally namespaced and give compile-time checking. You can’t mix in two locator traits and, without knowing it, have selectors overridden. e.g., FooLocators.myLazyLocator. Selectors that require parameters are defs; otherwise, they are lazy vals.

object FooLocators extends WebBrowser {
    lazy val myLazyLocator: Query = cssSelector("[data-gilt-test=’foo’]")
    def myDefLocator(foo: String): Query = cssSelector(s"[data-gilt-test=’$foo’]")
}

Assertions

Assertions are generally located with tests, but commonly used assertions can be implemented as an assertions trait in the PageObject.

trait CartAssertions extends WebBrowser with Checkpoints with Matchers {
  self: Foo.type =>

  def assertSomething()(implicit eventType: EventType, driver: WebDriver): Foo.type ={
  
      val cp = new Checkpoint    
      cp {  assertSomething  should be(something) }
      cp {  assertAnotherThing  should be(anotehrThing) }

      cp.reportAll
    Foo
  }

ScalaTest offers a really useful feature called checkpoints, which enables multiple assertions to be performed within a test. Any failures are accumulated and reported together at the end of the test.

Using PageObjects in Tests

Now with our newly created Foo PageObject we can write tests like this:

/**
 * Test Using PageObject.
 *
 */
@Selenium
class MyFooTest extends FunSpecTestBase {
describe("Test using Foo PageObject") {
  it("should test stuff") {
         withFixture() { 
        fixture =>
            Foo
         .goFooUrl(fixture.url)
         .doSomethings(fixture.foo)
         .assertSomething
        }
      }
   }
}

We can also include additional PageObjects in tests:

/**
 * Test Using PageObject.
 *
 */
@Selenium
class MyFooTest extends FunSpecTestBase {
describe("Test using Foo PageObject") {
  it("should test stuff") {
         withFixture() { 
        fixture =>
            Foo
         .goFooUrl(fixture.url)
         .doSomethings(fixture.foo)
         .assertSomething

        Foo2         
         .clickSomeStuff
         .assertSomeStuff
        }
      }
    }
 }

And if Foo has an action getFoo2, with a return type of Foo2, we can chain actions together:


/**
 * Test Using PageObject.
 *
 */
@Selenium
class MyFooTest extends FunSpecTestBase {
describe("Test using Foo PageObject") {
  it("should test stuff") {
         withFixture() { 
        fixture =>
            Foo
         .goFooUrl(fixture.url)
         .doSomethings(fixture.foo)
         .assertSomething
         .getFoo2        
         .clickSomeStuff
         .assertSomeStuff
        }
      }
    }
 }

Take, for example, Gilt’s Sale Listing page:

image

The Sale Listing page serves several elements to users, such as breadcrumbs, sale end times, sale titles, and filters. Each Sale Listing page also features n product looks, also known as Listing Looks, that contain product names, brand names and prices. We can now logically abstract the Listing Look as a function or factor of the page. In other words, the Listing Look has a number of related elements and actions that are uniquely identifiable as belonging to a Listing Look. Each Listing Look can be its own PageObject and resolve to a Quick Add Modal, which in turn can resolve to a Cart modal based on user interactions.

image

image

As we can break down and describe the services on the page into unique, logical groupings, we can start to define PageObjects for the page. According to our team’s interpretation of PageObjects, we regard PageObjects not as an Object of the entire page, but rather as a number of easily defined services, elements, and actions that can be grouped together to model the page. With PageObjects broken down into these component parts, we can create PageObjects for each element.

For a Sale Listing page, we can have four PageObjects:

SaleListing -> ListingLook -> QuickAdd -> Cart

We can also have a CartItems PageObject, as a Cart can have n items (up to five user selections).

Show me some real code, dude!

At Gilt, we’ve set up a repository for our Sale Listing code. We’ve also created a Selenium folder that has its own project structure:

image

With this setup, we can export a PageObject listed under the src/main folder in web-search-selenium as its own jar, import it into another project, and use it in that project’s tests. To port tests from the repository to a global/integration regression, we tag a test so that it can be called and included from within an integration execution job. Let’s look at a test:

abstract class QuickAddToCartTestOnSaleListing extends FunSpecTestBase
  with SkuFixture
  with SaleHelper
  with BeforeAndAfterEach
{
  implicit val eventType = Synthetic

  override protected def beforeEach() { registerAUser() }
  override protected def afterEach() { logoutAndCloseBrowser }
  protected def skuFilter(sku: Sku): Boolean

  describe("Sale listing") {
    it("should add available sku to cart using quick add") {
      withActiveSku(filter = skuFilter, lock = true) { sku =>
          Given(s"a sku[$sku.getSkuId]")
          val sale = getSale(sku)
          val productLook = sku.getProductLook
          And(s"its sale[$sale.getSaleId]")
          Then("go to the sale listing")
          SaleListing
            .goToSaleListing(sale.getRelativeUrl
                .asScala
                .getOrElse(cancel("Sale did not have a relativeUrl")))
             //SaleListing action which returns a ListingLook PageObject. 
            .getListingLook(productLook.getProductLookId)

             //ListingLook rich action which selects a size and click add to cart. 
            .triggerQuickAdd

             //QuickAdd action which returns a Cart.
            .addToCart(sku.getSize.asScala.map(_.getLabel.toLowerCase))

             //Cart action which returns a CartItem.
            .getCartItem(sku.getSkuId)

             //CarItem Assertion
            .assertCartItem(sku.getProductLook.getProduct.getName,          
                            sku.getProductLook.getProduct.getBrand.getName)

          Cart.clearCart()
            .assertCartEmpty
            .assertContinueShoppingIsDisplayedWhenCartIsEmpty
      }
    }
  } 

Because the test steps are located in an abstract class, we can reuse the code to create brand-new tests and check other functionalities, based on the SKU and its attributes (which are passed into the test via the fixture).


/**
* Tests for Quick Add on Search-Listing Page
*/
@Selenium
class QuickAddToCartTestOnSaleListingSkuHasSize 
extends QuickAddToCartTestOnSaleListing
   with SearchHelper {
  
   //Use filters to find a specific sku to test with.
   override def skuFilter(sku: Sku): Boolean = 
               SkuFilters.hasSearchBaseFilters(sku) &&                           
               SkuFilters.hasSizeAttribute(sku) &&
               isOnFirstPageLoad(sku)
}

Let’s dig deeper:


            //ListingLook rich action which selects a size and click add to cart.
            .triggerQuickAdd

             //QuickAdd action which returns a Cart.
            .addToCart(sku.getSize.asScala.map(_.getLabel.toLowerCase))

             //Cart action which returns a CartItem.
            .getCartItem(sku.getSkuId)

.triggerQuickAdd. This action is a ListingLook Simple Action that performs a mouseEnter on a productName element Listing Look and returns a QuickAdd PageObject.

def locators = ListingLookLocators
def triggerQuickAdd()
(implicit eventType: EventType, driver: WebDriver): QuickAdd = {
        
      mouseEnter(locators.productName(this.productLookId))
    QuickAdd(productLookId)
  }

.mouseEnter

/**
   * Move Mouse into Element Position.
   *
   * @param query : WebBrowser#Query to define the webElement
   * @param eventType : Native or Synthetic
   */
  def mouseEnter(query: WebBrowser#Query)
     (implicit eventType: EventType, driver: WebDriver) {
      WaitTool.waitForElementIsDisplayed(query)
      eventType match {
          case Native => {
                 val builder = new Actions(driver)
                 builder.moveToElement(query.webElement).build().perform()
          }
          case Synthetic => JQueryHelper.mouseEnter(query)
    }
    JQueryHelper.pageIsLoadedAndAjaxIsCompleted()
  }

This action is located in our commons-selenium library and will execute a Selenium action or a jQuery action based on the eventType. This action is wrapped to perform:

  • - on enter : ensure the element is displayed
  • - on exit : ensure, all Ajax calls are completed and the DOM is in a readyState of “complete”.
  • .addToCart is a rich action comprised of a number of simple actions. It calls the Cart PageObject waitForCartDisplayed action, which returns a Cart PageObject:
/**
   * Selects (if necessary) the size and adds it to the cart, 
   * asserting that the cart opens successfully.
   */
  def addToCart(sizeOpt: Option[String])
      (implicit eventType: EventType, driver: WebDriver): Cart.type = {
    selectSize(sizeOpt)
    clickAddToCartButton()
    Cart.waitForCartDisplayed()
  }

.getCartItem(sku.getSkuId) is a Cart action that returns a CartItem PageObject based on the skuId. .assertCartItemDisplayed() and ensures that the CartItem is actually in the cart:


  def getCartItem(skuId: Long)
     (implicit eventType: EventType, driver: WebDriver): CartItem = {
    CartItem(skuId).assertCartItemDisplayed()
  }

A CartItem is a function of the Cart, so it is a PageObject, as you can have n items on a cart.

Wrap-up

With PageObjects, we’ve eliminated a lot of the flakiness associated with testing. Breaking PageObjects down into smaller logically grouped constituent parts works just as well for small projects as for bigger ones. And because we’re using BrowserAction and more of the wrapping, we can more easily follow our work flow from one step to the next. The motivation for this work is to drive more voluntary adoption of Selenium within teams at Gilt.

image

Gilt gives a hearty welcome to Michal Kowaliszyn, a Dublin-based software engineer who joins our email team (Push)! Before joining Gilt, he worked on audience targeting for advertising platforms. Besides programming (most recently in Scala), he enjoys running and traveling the world with his wife. Welcome, Michal!

Gilt Insider, our customer loyalty program, just turned one year old, and to celebrate we’re sharing presents!

Today all Insider benefits are half-off—meaning 2x the payback for your hard-earned points. This works for dollars off any order, free shipping, or even products in our curated rewards shops.

image

As a refresher: Insider members earn five points for every dollar spent on Gilt. These points can be redeemed either as cash, or for a rotating array of products, deals, and gift cards for our favorite brands.

Not a member yet? Join Now! Old news? Well look for some exciting, free new benefits to come your way this fall!

And in the meantime, cash in…

Let us know what you think of this and other new features by emailing us at productfeedback@gilt.com.

Earlier this summer Gilt Senior Software Engineer Giancarlo Silvestrin was a featured presenter during Typesafe’s Play Day—a whole day of technical talks focused on Play Framework. Giancarlo talked about how we implement Play across our hundreds of small applications and microservices. Check out Giancarlo’s presentation above!

To get things done, Gilt technologists organize ourselves into small cross-functional teams that work together on specific initiatives. All of our teams pick their own names—Ninjas, Disco, T-Rex, Cerebro, etc.—and some go the extra mile by designing logos and producing swag. Our favorite swag items are stickers: They’re low-cost, easy to reproduce in big batches, and make our laptops look cool.

Let’s take a look at some of our sticker creations. First up is the Gilt Tech sticker, our adhesive bread-and-butter:

image

Based in our Dublin office, Team Ouroboros focuses on our continuous delivery efforts: development, test tooling, and enabling continuous improvement through voluntary adoption. They are our go-to team for helping with quick iterations and feedback through the build-test-deploy cycle. They also drive our “Developer Happiness KPI”:

image

Another Ireland Team with a strong branding concept and identity is Team Fire, which works on some of our platform engineering initiatives:

image

The brand-new Team Twain is working on a top-secret project—so secret, in fact, that their sticker is really the only thing about them that we can share:

image

Turning to NYC: The Gilt Ninjas are responsible for building our beautiful sales and product pages and many of the other things you see when you visit Gilt.com:

image

Principal Software Engineer Kevin Scaldeferri and Senior Software Engineer Sean Sullivan both live in Portland and have their own region-specific sticker:

image

The mighty Gilt Back Office team is one of Gilt’s largest and handles many of our key business operations. They’ve created this appropriately fierce sticker:

image

Teams within the Back Office Team have begun crafting their own stickers. Team Customer Transactions makes a bold statement with this Soviet-dollar design:

image

In addition to team stickers, we also make stickers for things we really care about—like LOSA (“Lots of Small Applications”):

image

Another thing we care about: User Interface Things:

image

And another thing: we care about great technology! As co-organizers of the Play NYC meetup group, we give out these stickers to all of our new friends and tech event guests:

image

Celebrating is another important part of Gilt’s tech culture. For their work anniversaries, we give people badges. This is the first-year Gilt-iversary badge:

image

And the five-year Gilt-iversary:

image

We’ll add more new sticker designs here as they become available!

Did you know you can now use the Gilt iPhone and iPad apps to shop Gilt by product category?! Tap on the search bar to reveal the “Shop by Category” feature and search for “shoes,” “dresses,” “sofas,” or any other type of item you’re looking for, more quickly and easily. And never miss a deal!

 image

To use Shop by Category on your iPad, tap on the “Shop By Category” bar that sits right underneath our store selector to reveal a visual list of categories that you can shop from:

image

Share your feedback on this customer-guided new feature by emailing our mobile team at iphonefeedback@gilt.com.

 

image #gilttech gives a hellaciously hot welcome to software engineer Nick Rogers, who joins Team Fire—the Dublin-based Gilt engineering team that’s currently focusing on SEO/SEM. Before joining Gilt, Nick spent five years working for a UX design and Development company, specializing in JavaScript applications and front-end development. “I do love working with JavaScript,” he says. “The whole front-end space has moved at a frantic pace over the last couple of years, and it’s been nice riding that wave!”

In his off hours Nick enjoys reading, music, football (fussball could well be a new love), Qi Gong, and spending time with his family. Welcome aboard, Nick!