In 2017, Artsy adopted Relay in both its front-end web and iOS codebases (using React and React Native, respectively). Generally speaking, this investment has turned out very well for us! Relay empowers product teams to quickly iterate on new features and to share common infrastructure across web and iOS codebases. However, most of the original engineers who pioneered using Relay at Artsy have since moved on to their next role; this has left a knowledge gap where Artsy engineers are comfortable using Relay, but they don’t totally understand how it works.

This is a problem as old as software engineering itself, and it has a simple solution: learn and then teach others. We’ll be driving a peer learning group centering around Relay, but today we are going to dive into the part of Relay that comes up the most in requests for pairing: getting Relay pagination to work. (Note: we’re going to use plain old Relay and not relay-hooks.)

Read on →

This blog post is going to motivate and describe Artsy’s adoption and evolution of the usage of review apps.

This first part of this post covers a couple of common problems where topic-specific servers (i.e. review apps) are useful.

The rest of the post describes Artsy’s history with review app automation via incremental problem solving and the composition of a few well-known technologies.

Read on →

Code review is an engineering process that has benefited greatly from a move toward asynchronous communication. Long ago, engineering teams would sit in a room with code on a projector to review changes together. 😱 For many teams this led to batching code reviews or even skipping them altogether. 😱😱

Today, most engineering teams use incredible tools like GitHub or GitLab to review changes through Pull Requests (PRs). The greatest advantage of PRs is that the review can happen when it’s convenient for the reviewer: asynchronously. Asynchronous communication isn’t all sunshine and unicorns, though. Notably, it lacks the ability to course-correct when context is misunderstood.

Read on →

Good team culture strives for cohesion. Once organizations get large enough, a tension emerges between the culture of individual teams and the culture of the larger organization. How do you achieve team cohesion across small teams and the larger organizations they comprise?

The culture at Artsy is driven by every team member, not mandated or handed down from above. This adds another level of tension, between individuals and their smaller teams. Team working agreements embrace that tension to provide a framework for converting tension into healthy culture.

Read on →

Software deploys! What a concept. You have some code running somewhere, and you need to get it running somewhere else. What could possibly go wrong? While web developers have become accustom to some really slick deploy processes, iOS developers have to work within some very different constraints.

Today I want to explore the differences between deploying iOS software and front-end/back-end web software. Some of these differences are inherent to how the code gets executed, and some of the differences are incidental to choices that Apple has made. These are constraints that iOS developers need to work within. As Artsy has adopted React Native over the past four years, we have had more and more of our web engineering colleagues contributing to our iOS app. For these web engineers, getting familiar with the iOS deploy constraints is as important as getting to know Xcode and CocoaPods.

Read on →

Coordinating changes across many packages in the node ecosystem can be quite the challenge. You can use npm link or yarn link to create a symlink of the package you’re developing on into another package, but it has some drawbacks. If you’re doing local development and need to rapidly see updates and yarn link isn’t working out there’s always tools like yalc to help you out. That’s really only for local development though.

What if you need to test packages together in a staging environment? Generally the approach would to be to deploy a canary version to npm that you can use in your staging environment. I’ll go over how to do that and how Artsy automates it.

Read on →

It’s the year 2020. You use a modern front-end stack of Relay, GraphQL, React and TypeScript. You can build an infinite scroll ‘feed’ type UI totally out of the box with these tools, by mostly putting together boilerplate (proper connections, along with a pagination container). You have a design system, and are rapidly building up a component library. Things are great!

Then you take a look at the latest design comps for a ‘browse’ type page, and you see that the controversial infinite scroll has been replaced by a more traditional pagination bar.

You know the one. Like the following, from Amazon:

You start to realize that the cursor-based setup of a connection, along with a Relay pagination container, does not lend itself to this more traditional UI. For one thing, a user can arbitrarily ‘jump’ to any page by including a ?page=X query param (typically). For another, the user can only actually see the current page of content, versus a feed. As you go to sleep and dream of REST, Rails controllers, kaminari, will_paginate, and a simpler time, you start to have a vision…

Read on →

In 2013, Artsy shipped the first version of our iOS app. Typical for an early-day startup, the app was a “minimum viable product” (with a big emphasis on “minimum”). One of the features that didn’t make the cut was something you expect to see in most apps: a log out button.

When I joined Artsy a year later, there was still no log out button. And there would be no log out button for another six years, until today.

I want to talk about this quirk of our app, from both product and technical perspectives. Why wasn’t this already in our app? Why was it so difficult to build? These are interesting questions, and their answers shed light on how products mature over time. I also want to talk about how we finally managed to prioritize this kinda weird feature request (spoilers: it was our company-wide hackathon). Let’s go!

Read on →

This will be the first in a series of posts about how we used advanced GraphQL tooling and functionality to better handle errors occurring during query resolution, and better equip clients to reason about such errors.

The goal is to describe our current approach, but also do a deep dive into specific ways we’ve extended our GraphQL server to help us accomplish that. If you are an interested GraphQL user, you may find this useful, even if some of the larger context specifically around how we are using it to help standardize error handling doesn’t apply.

Read on →