ChairNerd

Code, Design, and Growth at SeatGeek

Jobs at SeatGeek

We currently have more than 10 open positions.

Visit our Jobs page

Care Begets Care

There’s a phrase my friend, Stephanie, says often and whenever I think of it, I hear the words in her voice:

“Hurt people hurt people.”

There are a million examples of this out in the world every day: people lashing out as a reaction to the emotional wounds they’ve sustained, hurting others because they are hurting.

Being in service to customers often means doing some heavy emotional work. You observe and interact with people at various psychic levels and, for the sake of helping people, you have to be deft at identifying the feelings expressed and navigating them while you diagnose and resolve the issues brought to you.

So, knowing that a person’s emotional state can affect the way they act and interact with others it should go that the opposite of “hurt people hurt people” is true too:

“People who are shown care can better care for others.”

In CX (our Customer Experience team), we create an environment where we show each other that we care for each other. The leaders on our team work hand-in-hand to put things in place to amp up encouragement, to provide clear paths for each team member to be successful, and to emphasize a culture of assumed positive intention. Compassion and humor run throughout all of our internal interactions and generate space where we’re best able to care for the customers who come our way too.

This is an ongoing, growing, and ever changing process and it honestly takes quite a bit of trial and error and tons of feedback from all the members of the team. Luckily, there are some clear signs that a team is feeling taken care of:

  1. We take responsibility for our behavior
  2. We assess people correctly and from a place of empathy, giving people the benefit of the doubt
  3. We can identify where communication may be breaking down and can fill in the gaps to reconnect with others
  4. We are at ease so the impulse to attack with words disappears
  5. We see and comprehend the impact our behavior has on others
  6. We let down our guard so we are not constantly on the defensive
  7. We are not easily offended
  8. We do not react in anger
  9. If a resolution is not easily found for an issue, we see it as an opportunity for individual, team, and/or organizational improvement
  10. We have close friendships which each other and spend real quality time together

When any of those are out of whack on a team level or individually, it’s a red flag that something needs to be shown extra care. It deserves the same careful consideration and response as all the other pieces—minimizing the instances where knee-jerk reactions take place and provide only short term fixes. If your team is cared for, it’s like they proudly own a vintage car: one that’s polished, maintained, and set up to last for years to come. When it comes to CX, we also want to make sure that our “car” is set up and ready for passengers.

How do you create this space for your team? How do you acknowledge your team and show them care so they can turn around and best care for others?

Meet Us in Minneapolis: SeatGeek Goes to the Super Bowl

Fan at Fulfillment Center

It’s a cold Sunday morning in Minneapolis, but this isn’t your typical Sunday… it’s Super Bowl Sunday, and SeatGeek’s Inventory team is gearing up for our third and final day of delivering Super Bowl tickets to customers. You may be asking yourself, “Why deliver tickets in person, isn’t SeatGeek’s whole philosophy around using your phone to buy tickets and get in?” Well each year, there are a handful of major events that utilize good old fashioned paper tickets for admission, and the Super Bowl is their king.

With all the advancements in mobile ticketing, it’s odd the industry still uses hardstock (paper) tickets for high profile, expensive events. This is mostly due to hardstocks serving as one of the best formats for preventing fraudulent tickets from floating around. The paper format also allows for larger than average, holographic tickets with lots of fun details, allowing the ticket itself to act as a souvenir. And given the high dollar value of Super Bowl tickets (prices often start around $2,000 before the teams are even decided), SeatGeek’s number one priority is to eliminate the risk associated with shipping tickets via a third party carrier. The Super Bowl is that rare event where the ticket is as important as the game itself; so you’ll definitely want to hold on to it after all is said and done.

To combat the logistical difficulties of delivering thousand dollar tickets, our team flew out to Minneapolis (home of this year’s Super Bowl) to hand deliver tickets to all our customers at SeatGeek’s official fulfillment center for Super Bowl LII. This year’s center was located in a conference room at the Hotel Minneapolis, a few blocks away from the U.S. Bank Stadium where the game was played. And the Hotel Minneapolis served as a great location for stargazing. Several members of our team ran into the likes of superstar producer Pharrell in a hotel elevator and resident SeatGeek influencer Casey Neistat who picked up his tickets, camera in tow. Oh… and of course there were one or two dozen professional athletes roaming the halls.

Every event that requires a fulfillment center poses new challenges and questions for our team. And there’s a ton of work to be done; from tracking new orders in real time, to coordinating with sellers delivering tickets, to talking with customers and getting them pumped for the big game. But the biggest lesson is one we’re reminded of at every event - SeatGeek plays a key role in creating magic for all of our users. And the fulfillment center is always a great opportunity for our team to put a face to our amazing fans who call on SeatGeek for all their live event needs.

It’s an incredibly special experience seeing our users prepare to go to the big game, an event that will surely become a lifelong memory. When thinking of our users there’s a young boy who comes to mind, who came to pick up tickets with his dad. The father explained that the young man worked hard and saved up $4,000 over the last few years to attend this year’s Super Bowl. This boy chose SeatGeek to help fulfill his dream, which reminded us all just how important our role is in facilitating and protecting the dreams of our customers. And for each of us on SeatGeek’s Inventory team, our work securing tickets has taken on new meaning, knowing we helped turn a dream into reality.

SeatGeek Team

Software Design Patterns in Android Development

In just the past few years, mobile development has changed greatly in terms of not only what is capable on a pocket-sized device, but also in terms of what users want and expect out of the average app. With that, we developers have had to change how we build things in order to account for more complex, robust applications. The Android development community in particular has had a huge shift in focus (hopefully 🙏) from massive, logic-heavy Activities, to MVWhatever based approaches to help split our logic out. Most of us have also adopted the Observer Pattern through libraries like RxJava, dependency injection with Dagger, and more extensive testing. These tools, along with the adoption of Kotlin and the introduction of Architecture Components, have made it easier and easier to get off on the right foot with new Android apps to help ensure their maintainability and scalability for the future. However, these simple patterns are really just the tip of the iceberg and as our apps have some time to grow and mature in the wild, it is often necessary for us to employ other design patterns to allow applications to grow without becoming an unmaintainable mess. In this article, I’d like to take a look at some other common object oriented design patterns that have been around for while in the software world, but are talked about a little less in the typical Android development article. Before taking off and trying to implement these on your app as soon as you’re done reading, it’s worth noting that although these are good principles to abide by, using all or even some of them when they aren’t really necessary can lead to overly convoluted code that ends up being harder to understand than it needs to be. Not every app needs to implement them, but the key is to know when it’s time to start. Okay, enough of an intro, let’s get started!

Note: All examples are in Kotlin, so it’s recommended to be fairly familiar with the language and / or have this reference guide on hand

The Adapter Pattern

The adapter pattern is a strategy for adapting an interface from one system so that it works well in another, usually by abstracting away implementation via an interface. It is a common and useful design pattern that can help make components that are hard to reuse or integrate into a system more susceptible to doing so by changing (wrapping) their interface with one we design ourselves. In fact, it’s no coincidence that a RecyclerView.Adapter is named as such. Although every RecyclerView (or even each cell in a single RecyclerView) is going to likely display something different, we can utilize the common adapter interface for each ViewHolder. This allows for an easy way to hook into a RecyclerView but also gives the flexibility of allowing for different data types to be shown. This idea can be utilized in other areas as well. For example, say we’re working with a web API that doesn’t quite give us the data we need throughout the rest of our app. Maybe it gives us too much info, or gives shortened versions / acronyms of certain information in order to save cellular data, etc. We can build our own adapters to convert these API results to something that useful to the rest of our application. For example let’s take a look assume we’re making a basic ticketing app and have a TicketResponse that looks something like this after being converted from JSON to a Kotlin data class (note: not actually what our web API looks like):

1
2
3
4
5
6
data class TicketResponse(
    val seat: String = "R17S6",
    val price: Double = 50.55,
    val currency: String = "USD",
    val type: String = "Mobile"
)

For the sake of example, ignore the debate on whether or not this is a good looking API model. Let’s assume that it is, but regardless it’s a little messy for us to use throughout our application. Instead of R17S6 we’d really like to have a Row model with a value of 17, and a Seat model with a value of 6. We’d also like to have some sort of Currency sealed class with a USD child that will make life much easier than what the API currently gives us. This is where our the Adapter pattern comes in handy. Instead of having our (presumably Retrofit based) API return the TicketResponse model, we can instead have it return a nicely cleaned up Ticket model that has everything we want. Take a look below:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
data class Ticket(
    val row: Row,
    val seat: Seat,
    val price: Currency,
    val type: TicketType
)

class TicketApiClient {
    fun getTicket(): Ticket {
        val ticketResponse : TicketResponse = getTicketResponse()
        return TicketAdapter.adapt(ticketResponse)
    }
}

object TicketAdapter {
     fun adapt(ticketResponse: TicketResponse) = Ticket(
        row = TicketUtil.parseRow(ticketResponse.seat),
        seat = TicketUtil.parseSeat(ticketResponse.seat),
        price = CurrencyUtil.parse(ticketResponse.price),
        type = TicketUtil.parseType(ticketResponse.type)
    )
}

Although there’s still some improvements that could be made here (Api likely would return an RxJava Single for threading purposes), this little adapter gives us a nice clean Ticket model that’s much easier to use throughout the rest of our app than the model our Api gives us. There’s obviously many more usages for the adapter pattern, but this is a pretty straightforward one that most apps will likely find useful at some point along the way.

The Façade Pattern

Simply put, the façade pattern hides complex code behind a simple, easy to use interface. As our apps grow, there is bound to be some complicated business logic that comes about in order to implement product requirements. The façade pattern helps us not to have to worry about how those complex business logic implementations work, and instead let us plug into them very easily. Staying on the ticket theme, we may have some caching mechanisms implemented to ensure that users are able to view their tickets, even though they may not have service in the venue when they scan in. This logic is probably housed in some sort of TicketStore class that may have references to our TicketApiClient class above, our database, and maybe even a memory cache so we can load tickets as quick as possible. Determining where to load the tickets from can get pretty complicated pretty quickly and we therefore want to keep this logic isolated and abstracted away from those classes simply trying to get a reference to a ticket object to display on the screen for example. Let’s say we have a basic Model-View-Presenter architecture set-up. Our presenter shouldn’t have to worry about whether the ticket comes from the server, a memory cache, or from disk, it should just be able to say “Hey TicketStore, give me a ticket!” and get one back without having any knowledge of where it came from. This is where the Façade pattern comes into play. Our TicketStore class is a Façade that hides anything related to storing tickets behind a simple interface with potentially one simple method called something like getTicket(id: Int) : Ticket. Integrating with this interface now becomes incredibly easy.

1
2
3
4
5
6
7
class TicketPresenter(view: TicketView, ticketStore: TicketStore) {
    init {
        ticketStore.getTicket(SOME_ID)?.let {
            view.show(it)
        }
    }
}

The Command Pattern

The command pattern utilizes objects (value / data classes) to house all the information needed to perform some action. This is a design pattern that is becoming more and more common in Android development these days, largely due to lambdas / higher-order functions (functions that take in functions) available in Java 8 / Kotlin. With the command pattern, we can encapsulate a request or an action as an object. This object can take in function types that are executed when the request is handled. We tend to typically use these with third party libraries such as RxJava, but they can actually be useful for various internal APIs that we may have throughout our applications as well. Consider some sort of UI transition API we’ve created internally to help manage different view states. Let’s say we want to transition from the Loading state of our screen to the Content state. Let’s also say want certain actions to be executed before and after we make this transition. With the command pattern (and Kotlin), this becomes fairly trivial.

First we have our Transition class that takes in the layout to transition to, as well as functions to be executed during the transition process.

1
2
3
4
5
6
data class Transition(
    @LayoutRes val layoutRes: Int,
    val beforeTransition: () -> Unit,
    val onViewInflated: (View) -> Unit,
    val afterTransition: () -> Unit
)

We then have some sort of TransitionCoordinator class that is able to take in Transition objects and perform our transition as well as execute these various actions when needed. The key piece of the puzzle that makes the command pattern so useful is that the TransitionCoordinator doesn’t need really know anything about the calling class in order to go about this transition process. It is very generic and can take in functions from any class without knowing its innards. This makes the command pattern very powerful while being quite generic. This TransitionCoordinator might look something like this:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
class TransitionCoordinator {
    fun startTransition(transition: Transition) {
        transition.run {
            beforeTransition()
            val view = inflate(layoutRes)
            onViewInflated(view)
            doTransition()
            afterTransition()
        }
    }

    fun inflate(@LayoutRes layoutRes: Int): View = { /* Inflation code */ }

}

Thanks to the brevity of Kotlin, we are able to execute this transition process in very few lines of code.

In our Activity (or wherever we’re calling this code) we can now do something like this.

1
2
3
4
5
6
7
8
transitionCoordinator.startTransition(
    Transition(
        layoutRes = R.layout.activity_sample,
        beforeTransition = { unsubscribeObservables() },
        onViewInflated = { view -> bind(view) },
        afterTransition = { fetchData() }
    )
)

In this scenario we want to transition to some sample activity, unsubscribe to some observables before our transition, bind the newly inflated view upon transition, and fetch data after we’ve transition. Of course, once we brought this into the real world, our implementation would likely not be this simple, but it’s easy to see that encapsulating these method calls with “Command” objects makes them generic and easy to use.

Null Object Pattern

One other convenient design pattern, but possibly less frequently used is the “Null Object Pattern”. For those of us who have been Android developers for ~2+ years (before Kotlin came into play), we are all too familiar with null pointer exceptions that bring our apps to a crippling crash. Kotlin has helped to reduce this greatly, but there are still some cases in which we may need to account for null or empty states. The null object pattern can help us in scenarios where, although we may not have the necessary data to say populate a view, we still want to show some sort of empty (null) state in the meantime. This is only one potential example, but is a good place to start. Consider some sort of MVWhatever framework we’ve implemented in our UI layer. Our View takes in ViewModels and shows them on the screen. Let’s say for instance we’re displaying a user’s profile. In the ideal scenario, we simply fetch the profile from our database, cache, api or wherever and display it on the screen. Simple as that. However, what do we show if api request is taking a very long time? Maybe the user has bad cell signal or our server is at high demand for some reason. Of course we’ll want to show some sort of loading indicator here to let the user know we’re working on loading this info, but one other cool thing we can do is actually populate the view with an “null” or empty user state. Many popular apps (Facebook, Twitter, etc) utilize this type of pattern to give the app the appearance of loading even faster than it technically is. Let’s take a look at brief bit of code to help make better sense of this.

1
2
3
interface ViewModel {
     val titleText: String
}
1
data class UserViewModel(val user: User, override val titleText: String = user.name) : ViewModel
1
data class NullViewModel(override val titleText: String = "") : ViewModel

So what we have here is a ViewModel interface that holds the titleText we want to show on the screen as well as a couple of data classes that implement this interface and pass the necessary bits of data for the view to show what it needs to. Take a look at the NullViewModel data class. It might look pointless to pass this object to the view since there’s really nothing to show. However, by passing this model instead of waiting, our view can start to draw and allocate space on the screen. We can then even recycle this view when a real UserViewModel is available to make our rendering time even faster. Again, this is just one of many applications of this design pattern, and although it’s very simple it can be very useful in the right scenario.


Hope you enjoyed this little list of some design patterns less talked about in the Android development community. Again, there are not always applications for all of these, and they should only be used when the provide a tangible benefit to your app. There’s many more design patterns out there, each with their own specific purpose. A couple great books that go more in depth into different patterns can be found here and here. Happy coding!


We’re hiring! Learn more here

Customer and Experiences and ‘Customer Experience’

When I was in 8th grade, I got a once-in-a-lifetime opportunity to travel from my small town to Disney World as part of a school trip. It was an extra special experience in my mind because it was also my first time ever leaving home without my parents right by my side. Independence!

My teacher gave our whole group tons of agency on the trip: We were responsible for all of our own meals, and we dictated most of our own daily schedules. We were a special kind of obnoxious tour group, I’m sure. I mention the meal thing specifically because my strongest memory from the whole trip involved a lunch that changed my life.

When you’re first stepping into big responsibilities there can be a learning curve. Sometimes small things get dropped or forgotten. In this case, that small thing was my very expensive retainer which I had forgotten about and dropped directly into the trash can outside Frontierland.

Of course, I was embarrassed. I can only imagine the hard work Disney cast members do on a regular day and the last thing I wanted to do was to add “dig through the garbage to fish out a tween’s mouthguard” to their to-do list. I also knew what would happen if I flew home and told my parents that I’d doomed my teeth back into being crooked. Braces are expensive. This trip was expensive. Having one ruin the other was not the best situation.

I was stuck at the trash can, panicked. Other people passed, dumping their trays before heading off to Splash Mountain. I swear, Disney employees must have a sixth sense that helps them identify kids who are about to cry because this cast member got to me right in time. “What’s wrong?” She asked with the warmest, kindest, most genuine tone you can imagine. I don’t even think I said the entire word “retainer” before she ripped the top off the can and started hunting. She found it within seconds and saved the day. What was even more surprising was that she thanked me for letting her help. What the heck?!

I wasn’t “garbage she had to go through” at her job. To her, I was a person in the middle of the experience of my life, facing an issue that brought all that to a halt. She knew what she could do to positively affect the person at the other end of this interaction and she dove in without hesitation. That is amazing and it showed me how much of an impact someone in service can have on others.

As a company, we’re obsessed with getting more people out to live events they care about. We pour our energy into creating a smart, intuitive website and app that connects people and unlocks their ability to go make memories with the people they care about, seeing the artists and teams they love. It’s a sweet gig. Obviously an app can’t answer every question or resolve every issue that may pop up, which is why we have a dedicated (and sizeable!) customer experience team in the first place.

We have a special CX team at SeatGeek. A group so passionate about helping people create memorable experiences that we built careers around it. We dive in without hesitation and help people resolve anything that’s stopping their outing from being the time of their life.

What’s extra nice is that our work in CX goes beyond emails and phone calls. We have high level conversations about what our customers go through at every step, from browsing for events to the very last song performed during an encore, and we get to base them on the first-hand accounts we hear directly from fans. Then we use all of this information to connect with the other teams at SeatGeek and together we improve.

Empathy is the name of the game and it’s not just a buzzword that we fling around. We’re bold in our consumer advocacy: protecting them with our SeatGeek guarantee, anticipating their needs, and using the focus of who is on the other end to influence our decision making. We are truly in service to others in a way that would make Disney proud.

In a world that’s becoming more and more automated, our team is excited to learn and offer new and better ways for customers to reach us – we are a tech company, after all. However, we take special care to maintain a human touch at the end of those channels. Email, phone, or social media, any way someone tries to reach us there’s another person waiting and ready to help.

We’re dedicated and committed to connecting with the person on the other end. Reach out to us and let’s dive in.

SeatGeek is a Glassdoor Best Place to Work (Again!)

The past year has been an extraordinarily exciting one for SeatGeek. In 2017, we’ve built the industry’s best seating previews, signed a deal with the world’s biggest social media network, launched our primary ticketing brand, and partnered with our first-ever NFL and NBA teams.

But in the last month of the year, we’re lucky to add one more accolade to the list. It’s an important one to us because it’s about our team. We’re thrilled that for the second straight year, SeatGeek is on Glassdoor’s list of Best Places to Work in 2018.

Something noteworthy about this award is that there was no self-nomination process. The scores are based on SeatGeek employee feedback given voluntarily (and anonymously) on Glassdoor over the past year. It’s humbling to make the list two years in a row – there were only nine other companies in the US that did so.

The fact that SeatGeek is a great place to work is one of the things we’re most proud of as a company. Working here has its perks: SeatGeek’s social calendar is full of parties and retreats, our kitchen pantry is on par with that of a five-star restaurant, and our monthly ticket perk helps employees attend their favorite live events.

But what really makes this a place to do great work – and have fun – is less tangible. SeatGeek is is an amazing place to contribute, grow, and build something special. The team believes in the power of live entertainment to make people happier, and there is a genuine passion for building a product that enables great experiences. The environment here encourages that, and the reviews reflect it.

As a company, we have some lofty goals for 2018 and beyond. We operate in an industry that has long been overdue for a fundamental shift, and SeatGeek is a catalyst for change in ticketing. We’ll stay focused on launching great products, partnering with amazing clients, and building out a distribution network for ticketing across the internet.

But one of our most important goals is to continue to be a fixture on awards lists like Glassdoor’s. As our team continues to grow, we’re fortunate to have found people that continue to embody SeatGeek’s core values. The people at SeatGeek that bring these values to life are our most valuable asset, and are what we hear about most often when employees talk about their favorite parts of working here.

SeatGeek Portraits


If this sounds interesting to you, come work with us at SeatGeek! We have a number of roles open across engineering, marketing, business development, and more.

Distributed Team Meetings and Learnings - Copenhagen Edition

WorldUnited

Cultural diversity is an important ingredient in creativity. At the tip of our process and teamwork, we leverage the different ways we use the internet and user interfaces to help us craft a well-rounded product and user experience. While cultural diversity can often be taken for granted being in New York City (where we call home, and can arguably be considered the “melting pot of the world”) we at times will hire extraordinary talent, no matter which city they call home.

I’m a Senior Director of Engineering at SeatGeek, and my team consists of engineers from 5 countries across 3 continents: North America, Europe and Africa. My situation is not at all unique in the engineering industry. Distributed team management is often a challenge many organizations face as they scale and sometimes hire extraordinary talent outside of their borders.

In my career, I’ve been involved in rapid scale, with remote teams, across many timezones and different working cultures. This type of scale and distributed team organization would not have been successful without travel, regular facetime, lots of communication, good processes and supporting software. So, naturally, one of the first things after I started at SeatGeek and joined my team was book flights to Copenhagen to meet some of them.

Now, I realize there are very good blog posts, books and talks about distributed team management and I certainly don’t have all the answers (I read those blogs and books, too!), but I felt it would be interesting to you to hear about my trip to Copenhagen, and share with you where we learned to be better with our distributed team.

Here’s what went down:

Copenhagen

Saturday & Sunday - Day 1 & 2 - Copenhagen:

It was great being back in Scandinavia (I used to live in Stockholm, Sweden). The weather was cool, the food was delicious (fish, pickled everything, breads, cheeses…) and the beer (Mikkeller ftw) was plentiful.

If you ever get out to Copenhagen, here’s my hit list:

  • Warpigs
    • An American style BBQ joint which is founded by Mikkeller and Three Floyds brewing. Expect nothing but amazing beer flights and hearty meats.
  • Mikkeller everything
    • Mikkeller is a tour de force of beer in Copenhagen. Their locations around Copenhagen are all worth checking off your list.
  • Nørrebro neighborhoods.
    • The northern neighborhoods of Copenhagen are tree lined, quaint and picturesque. Easy to get lost and found again.

Monday - Day 3 - Meets and Greets:

Workspace

Workspace

Workspace

Workspace

One of the immediate thoughts I had walking into workspaces is that it felt just as I remembered what any good Scandinavian workspace should be. Lots of plants, the low northern sunlight creeping through some shades, the smell of coffee, subtle music playing in the background… the atmosphere was very familiar. The floor the workspace is on is packed with other Danish tech startups. Some companies were game makers, others were building PaaS software, and there was everything in between. This workspace definitely had the better corner views, though. Great vibes all round, I loved being surrounded by other technologists and watching the Danish startup culture in full flight.

Day Agenda:

  • SeatGeek news, updates & open conversation
  • Distributed Team Effectiveness (Open Conversation)
  • 1:1’s!
  • Dinner and beer.

SeatGeek news, updates & open conversation:

We sat around the workspaces in an open conversation and discussed things that have been going on in the SeatGeek offices of New York. As a distributed team you can sometimes miss out on the regular news updates that you can get at the HQ. I learned that we can be better at sharing milestones and regular news, which at first may not seem mission critical, but really are vital to building the SeatGeek culture across the pond.

Distributed Team Effectiveness:

This was a great discussion around how we can be better working in a distributed team model. Hot topics like being social, communication and process and tools were discussed at length.

Being Social:

While we don’t follow “Capital A” agile strictly speaking, we do conduct the typical scrum ceremonies. I learned that we can be better in our standups. Given that standups are the one time of the day that the whole team is together, we should give our best effort to make it as effective and useful as possible. One idea was that since we are a little loose in our agile ceremonies, given the distributed nature of the team we thought that being a little more social in those meetings would help grow relationships and allow us time to bond. Having a few offtopic points about our weekends, or hobbies are a great way to learn about each other. This has been a great tweak to our process and I know there is some great back chatter amongst the team. We do our best to stay the course during the stand up, and enjoy some light chatter afterwards.

We also decided to have an “always open” Google hangout for people to join and chat like a party line. This has proven to be a great idea and a lot of fun!

Communication:

We felt that the communication channels we use should be consistent. Sometimes an issue will be discussed in a private chat and not in the team chat, or sometimes an issue is discussed in a ticket and not updated in any chat channels. We agreed to be better at communication and work to moving the conversation into a single channel, and to use our tools to help communication be more visible to the wider team.

Process and tools:

We recognized that there needs to be a little more planning in place to avoid being blocked by the 6 hour time gap between Copenhagen, Africa and NY being online. Let’s use our tools to understand the bottlenecks and try to resolve them and any blockers before EOD.

We have been using Geekbot as our stand-up / stand-down bot in Slack. It’s working really well for us.

Dinner and beer:

Beer

Beer

One of our engineers, having just returned from a vacation to Croatia, decided to take all of us to a Croatian restaurant in the center of Copenhagen - Restaurant Dubrovnik (don’t worry, I got my fair share of Danish cuisine in). We ate some delicious Croatian fare and started to get into the nitty-gritty of our work.

It was getting a little warm in that restaurant, so we decided to move to a craft beer bar called Taphouse. Taphouse is a pretty cool bar, owned by a Danish engineer with a love for beer and tech (perfect!). It had digital displays for what beers are currently on tap and the lights of the bar would flash when a new keg got hooked up – us geeks loved that. Great selection of beer!

Our discussions went long into the night, and without realizing it an hour had passed with empty glasses due to rich conversation. We decided to call it a night and pick things up in the morning.

Tuesday - Day 4 - Wrap up:

We were off to an early start and continued our conversations around being distributed, our engineering duties and plans for the future. A quick taxi ride to the airport and I was back on my way to NYC… a whirlwind trip but the facetime is invaluable and sets grounds for a great long lasting relationship.

In summary:

Overall, traveling, whether you’re going there or coming here is going to be the catalyst for a great engineering culture with distributed teams. Some of my best friendships were forged through working in a distributed team. I have been on the other side of the fence (living in Stockholm and working for a NYC-based company) and I understand that it takes extra effort to be effective and optimized. If you encourage a great communication culture, and use good processes, and travel, you’re already heading in the right direction.

Some reading / viewing:

Karl Stanton is a Senior Director of Engineering at SeatGeek with a core focus on technical leadership, career development and distributed team management.

Employee Spotlight: Lily Dai, Finance

Welcome to SeatGeek Employee Spotlights – an opportunity to meet the fantastic folks on our world-class team.

By day, we’re a group of talented developers, designers, marketers, and businessfolk working together to build something new and different. But we are also fans and live event junkies of every kind: diehard sports fans, passionate concert-goers, sophisticated theater enthusiasts, and more. From our lives outside the office and within, we all have interesting stories to tell.

Up next: Lily Dai from our finance team!

Lily Dai

Where were you born?
Los Angeles

Have you always lived in NYC?
No, I just moved from LA six months ago.

Where did you go to school?
I went to the University of Southern California and studied Business and Film with a double major in Accounting

Any funny roommate or apartment stories in NYC? Feels like everyone has at least one…
We were friends on Facebook, but we never talked until I reached out to see if she needed a roommate. Can’t think of any funny stories, but we once had 12 pints of Halo Top in the freezer. I called it the “Juice Cleanse”.

How would your friends describe you in 3 words?
Goofy, perceptive, adventurous

Best project you’ve worked on at SeatGeek
We’re currently redoing our forecast for the next 18 months. We’re talking to the product, marketing, and recruiting teams and learning what their needs are. I’m diving a lot deeper into our business. (I know all the secrets.)

What is your dream project to work on at SeatGeek?
My dream project would be to do a deep dive into our snack inventory and find out what’s the most popular. Personally, some of the protein bars taste like chalk, so figuring out which can go and what new ones we can get.

3 “fun facts” about yourself that people would be surprised to know
* You can pour 5 cans of any beverage into a frisbee disk, and I can drink it very quickly. * I fixed cars with my dad for about 10 years. If I’m ever stranded, I can fix the car. * I’ve taught my kitten to fetch.

Favorite place(s) to hang out in NYC
Prospect Park. I’ve been there about 30 times, and I still get lost almost every time. I also love that NYC has a bunch of queer spaces to hang out.

Best vacation you’ve ever taken
My post-college trip with my friends to East Asia. We went to six countries. We had island lifestyle and ancient temples. It was a great way to close out college plus everything was a dollar. We had an oceanfront hotel room for 50 bucks.

Favorite SeatGeek snack
Peanut butter pretzels

Why do you love SeatGeek?
Besides our business model, I love our culture. We had a pride themed happy hour. I almost teared up at how supportive everyone was of our LGBTQ co-workers. It was the perfect example of how supportive and open-minded everyone is here.

Favorite part of the office?
I love the pods in the lounge. They’re super comfy, and you could take a nap if you wanted to while watching the people at Blink work out.

SeatGeek Adds Facebook as Distribution Partner to Fuel Event Discovery

We launched our primary ticketing platform a year ago with one overarching goal: to get more fans to live events. Through our open API approach, an open ticketing ecosystem will create opportunities to increase distribution, empower teams and artists to sell on the platforms of their choice, and eliminate fraud through a process of barcode verification. At the end of the day, our goal is to increase discovery of live events by using the power of the open web, putting tickets where fans are already spending time online.

Today we’re taking a major step toward that goal, and are thrilled to add Facebook as a distribution partner for SeatGeek. As the world’s largest social media network, Facebook powers an incredible amount of delightful discovery of information for their users, whether it is through a news post, long-lost childhood friend, or adorable cat video. We’re stoked to be able to add a piece of the live entertainment world to that.

SeatGeek primary ticketing client Sporting Kansas City will be the first to utilize this new partnership, selling tickets directly to fans through Facebook. We’re excited to expand this partnership to more SeatGeek partners in 2018 as the industry moves toward openness.

While we have already seen great success with SeatGeek distribution partners such as Gametime and TicketNetwork, adding the world’s largest social network to the mix is a game changer for both clients and fans. Exposing inventory directly to fans on Facebook will make for a seamless shopping experience, resulting in more tickets sold, more events attended, and most importantly, more fun for fans.

Our Facebook partnership comes at an exciting time for SeatGeek, coinciding with the recent announcement of SeatGeek Enterprise, our powerful stack of primary ticketing services solidified into one brand. SeatGeek Enterprise promotes our vision of an open ticketing world, in which venues and rightsholders enjoy unprecedented flexibility, transparency and monetization potential. Our open distribution approach is a crucial piece of the SeatGeek Enterprise offering and one of the most important ways we are empowering rightsholders and putting more control in the hands of teams and venues.

We’re thrilled for fans to begin to see this partnership in action in their newsfeeds, as we continue to put the fan first in an industry that for too long has been more than happy to sit on its hands when it comes to innovation.

Facebook-SeatGeek Integration Screenshot

Employee Spotlight: Erin Elsham, People Ops

Welcome to SeatGeek Employee Spotlights – an opportunity to meet the fantastic folks on our world-class team.

By day, we’re a group of talented developers, designers, marketers, and businessfolk working together to build something new and different. But we are also fans and live event junkies of every kind: diehard sports fans, passionate concert-goers, sophisticated theater enthusiasts, and more. From our lives outside the office and within, we all have interesting stories to tell.

Up next: Erin Elsham, on our People Ops team!

Erin Elsham

Where were you born?
Toledo, Ohio. Well, I was born there – we moved to Iowa after a year, then to Kansas. My dad worked in the agriculture business, so we moved around the midwest with him a bit.

Have you always lived in NYC?
Nope! I packed 2 suitcases and bought a one-way ticket from Kansas City 6 years ago.

It’s kind of funny – I went to college in Kansas as well. I was the odd one out of my really close friends and went to Kansas State, even though I was a Kansas University fan growing up, so that was a funny rivalry thing. New York City, for some reason, draws a lot of Kansas people – there are a couple of well-known KU bars here, and I have some friends from growing up who had moved out here right after school. I went to visit one of my best friends and her husband who were living in Williamsburg, and at the time I had just gotten out of school and was bored with what i was doing, so I moved out there. They were nice to let me stay with them for a bit. I literally packed two suitcases and moved, and six years later here I am.

Where did you go to school?
Kansas State University, Go Jayhawks! Oh wait, that’s KU (I grew up a KU fan). That’s the thing - I went to school at K-State, but was not into K-State sports.

Any funny roommate or apartment stories in NYC? Feels like everyone has at least one…
I’ve always lived in WIlliamsburg, and once we found an apartment with a backyard, we decided we’d stay there for a while. Because it’s a shared backyard, we’re friends with all of the tenants now, so if there’s ever a backyard party or barbecue, everyone is invited. One time, a friend of a friend who does photo shoots and works with modeling agencies asked if she could do a shoot back there. They brought in a really fancy model and props that totally confused the neighborhood, it was pretty funny.

Here’s a picture.

How would your friends describe you in 3 words?
Full of surprises!

I’ve been told that I’m like a stealth bomber – I’m pretty quiet for the most part, but I listen to everything, so I always kind of know what’s going on. Even with friends and family, I’ll know what’s going on and plan something that will surprise them in one way or another. For example, my boyfriend’s 30th birthday: he really likes Wet Hot American Summer, so I planned a themed party in our backyard and made everyone wear 70s camp gear. He had no idea. Also, the SeatGeek portraits – nobody knew that was coming. I like surprising people.

Best project you’ve worked on at SeatGeek?
There are a ton! I love to show off how fun we are as a company, so employee portraits and Life@SeatGeek Instagram account are the top!

What is your dream project to work on at SeatGeek?
Workation was a blast planning last year and I can’t wait to plan an even better event for this year. It’s a huge challenge planning an event for 150 people, but I’ve got some good ideas and am super excited.

What are three “fun facts” about yourself that people would be surprised to know?
I’m an aerialist. I perform trapeze in seasonal circus cabarets in Brooklyn, wear funky costumes and fly in the air – think that’s the most fun fact I’ve got. It’s all volunteer, and I choose my own songs and make the costumes I wear during shows. I’ve been doing it for about 5 and a half years at the same circus school in Williamsburg, am really close with my teacher and have made some amazing friends there.

Favorite place(s) to hang out in NYC?
Backyards and rooftops – there’s nothing better than living in the borough with the view! There are a lot of cool places, but they’re always too crowded – once you find someone with rooftop access, you’ve made it. The beach is fun to go to as well – I usually try Rockaway.

Best vacation you’ve ever taken?
So far, my first “real” vacation as an adult with no plans and no weddings was Puerto Rico with my fiance three years ago. I’ve been a bridesmaid like seven times, and have had a wedding almost every single year, so I haven’t taken a lot of vacations because it was all weddings for a while. Puerto Rico is great – it’s cheap, fun, and the water is clear.

Favorite SeatGeek snack?
Eggs? Do those count? Is that weird?

Why do you love SeatGeek?
It’s the people – everyone’s cool. They’re all so amazing, friendly and welcoming. So many smiles. There is not a single person I don’t feel like I could talk to.

Favorite part of the new office?
SG Portrait wall – sorry, I’m biased! That was the most fun I’ve had on a project. I had to be secretive about it (which I love), and we hired an outside designer for it and worked with them to get the details right and continue to work together for SG 1-year anniversaries!

Faster (Re)deploys with Docker-build-cacher

Builds a service with docker and caches the intermediate stages

At SeatGeek we use Multi-stage Dockerfiles to build the container images that we deploy to production. We have found them to be a great and simple way of building projects with dependencies in different languages or tools. If you are not familiar with multi-stage Dockerfiles, we recommend you take a look at this blog post.

In our first days of using them in our build pipeline, we found a few shortcomings that were making our deploys take longer than they should have. We traced these shortcomings to a missing key feature: It is not possible to carry statically generated cache files from one build to another once certain source files in the project change.

For example when building our frontend pipeline we have to invoke yarn first to get all the npm packages. But this command can only be executed after adding the yarn.lock and package.json files to the Docker container. Because of the nature of how Docker caching works, this meant that each time those files are modified, the node_modules folder cached in previous built was also trashed. As you may already know, building that folder from scratch is not a cheap operation.

Here’s an example that illustrates the issue.

Imagine you create a generic Dockerfile for building node projects

1
2
3
4
5
6
7
8
9
10
11
12
13
14
FROM nodejs

RUN apt-get install nodejs yarn

WORKDIR /app

# Whenever this image is used execute these triggers
ONBUILD ADD package.json yarn.lock .

# Dowanload npm packages
ONBUILD RUN yarn

# Build the assets pipeline
ONBUILD RUN yarn run dist

We can now build and tag a Docker image with for building yarn based projects

1
docker build -t nodejs-build .

The tagged image can be used in a generic way like this:

1
2
3
4
5
6
7
8
9
10
11
# Automatically build yarn dependencies
FROM nodejs-build as nodedeps

# Build the final container image
FROM scratch

# Copy the generated app.js from yarn run dist
COPY --from=nodedeps /app/app.js .

# Rest of the Dockerfile
...

So far so good, we have build a pretty lean docker image that discards the node_modules folder and only keeps the final artifact. For example a set of js bundles from a React application.

It’s also very fast to build! This is because each individual step is cleverly cached by Docker during the build processes. That is, as long as none of the steps or files used in the step have changed.

And that’s exactly where the problem is: Whenever the package.json or yarn.lock files change, Docker will trash all the files in node_modules directory as well as the cached yarn packages and will start downloading from scratch, linking and building every single dependency.

That’s far from ideal, as it takes significant time to rebuild all dependencies. What if we could make a change to the process so that changes to those files do not bust the yarn cache? It turns out we can!

Enter docker-build-cacher`

We have built a slim utility that helps overcome the problem by providing a way to build the Dockerfile and cache all of the intermediate stages. On subsequent builds, it will make sure that the static cache files that were generated during previous builds will also be present.

The effect it has should be obvious: your builds will be consistently fast, at the cost of a bit of extra disk space.

Building and caching is done in separate steps. The first step is a replacement for the docker build command and the second step is the cache persisting phase.

1
2
3
4
5
6
export APP_NAME=fancyapp
export GIT_BRANCH=master # Used to internally tag cache artifacts
export DOCKER_TAG=fancyapp:latest

docker-build-cacher build # This will build the docker file
docker-build-cacher cache # This will cache each of the stage results separately

How It Works

The docker-build-cacher tool works by parsing the Dockerfile and extracting COPY or ADD instructions nested inside ONBUILD for each of the stages found in the file.

It will compare the source files present in such COPY or ADD instructions to check for changes. If it detects changes, it rewrites the Dockerfile on the fly, such that FROM directives in each of the stages use the locally cached images instead of the original base image.

The effect this FROM swap has is that disk state for the image is preserved between builds.

docker-build-cacher is available now on GitHub under the BSD 3-Clause License.

Make sure to grab the binary files from the releases page


If you think these kinds of things are interesting, consider working with us as a Software Engineer at SeatGeek. Or, if backend development isn’t your thing, we have other openings in engineering and beyond!