It's been three years, and Swift Package Manager (SPM) is at a point where it can be useful for iOS projects. It'll take a bit of sacrifice and a little bit of community spirit to fix some holes probably but in my opinion, it's time for teams to start adopting SPM for their 3rd party dev tools.

TDLR: You should be using SPM for 3rd party dev tools like: SwiftLint, SwiftFormat, Danger, Sourcery, SwiftGen and Git Hook management.

This post covers: What made it feasible to use SPM now? What are the downsides of the status quo? Why use SPM at all? What are the downsides to using SPM?

Read on →

In the JavaScript world, the idea of deploying your libraries on every PR is pretty common. As someone who runs a dependency manager but comes from a native background, it's easy for me to cringe and imagine the strain this puts on NPM's servers. However, that is where the ecosystem is and continuous deployment can be really useful. So, about a year ago we started moving a lot of our libraries to do this at Artsy too. Starting with our most critical dependencies:

We started off using a commit message based workflow, but have just finished the migrating to a GitHub Label based workflow that is less workload on individual contributors. This post will cover how, and why.

Read on →

Last month I was chatting at a bar with an engineer working on the Swift team, and we welcomed someone to our conversation where they opened with the question: "When can I stop using CocoaPods and switch to Swift PM?" I chuckled, because I get this a lot (I have been helping to maintain CocoaPods for about 6 years now) but they had made mistake of asking an Apple employee about something which sounds even remotely like a future product question. So, it didn't go anywhere.

Well, person whose name I don't remember, let me try to re-frame that question into something I can take a reasonable stab at: "Why are we all still using CocoaPods now instead of Swift PM for iOS apps three years after its release?"

Read on →

Micro-Services make sense for an engineering team of our size. You can scope a domain of your business to particular small unit of abstraction like an API. Doing so makes it easy to work in isolation, experiment with new ideas and evolve in many directions.

We've been carefully pushing for years to move away from our single monolithic API, to a collection of smaller, more focused projects. Our highlights docs showcase this well. The movement to smaller composable services works great from an isolated platform/systems perspective but can be a bit tricky to handle with front-end clients. Until 2018, the way that we've addressed the growing complexity in our service later has been to migrate the complexity inside our main GraphQL API, metaphysics. Metaphysics is our GraphQL API gateway that consolidates many API sources into a single service, then extending and interleaving and their data to make clients easier to write.

However, as more services have been created, and grown - so has metaphysics. This creates a worrying trend, as the growth of code in metaphysics isn't quite linear.

Our main line-of-thought on how to address this is via GraphQL schema stitching. We've been running experiments in stitching for over a year, and have have been running with stitching enabled in production for a few months.

Read on →

Hi! Let's talk a little bit about user authentication. We'll discuss it through the context of authentication within Artsy's ecosystem of applications, but ideally the same concepts will translate into other systems as well. The goal here is to build an understanding of (1) what exactly authentication is, (2) how it works, and (3) how to use artsy's specific infrastructure to delegate authentication for a new application to the existing ecosystem.

There are two primary authentication flows that we use at Artsy. We support user authentication through OAuth to allow users to log into our applications by delegating authentication to Gravity, our primarily application API. Alternately, we support app authentication for those cases where an application will only be called by other applications. We don't care about user authentication in this context, there's no need to redirect to a login screen etc - we just need to establish permissions between services. In both cases you'll be working with JSON Web Tokens (JWTs), and the difference is how the token you're looking at is generated.

User authentication happens at login - when the user provides their credentials to our server, our server confirms that they are who they claim to be and then generates a cryptographically signed token that encodes a few facts about that user.

App authentication, by contrast, all gets done in advance. We create the token manually, and share it with whatever application we want to grant access to.

In this document we'll first develop an understanding of what OAuth is and how it works. Then we'll examine the tokens we're using to get a better sense of what kind of information we have to work with. Finally, we'll go into how to set up authentication for users and for applications, building on the knowledge we've established.

Read on →

Volt is the internal app name of Artsy CMS, and our partners use it to manage their inventory and presence on It's a Rails-based UI app that talks to many API services. We use RSpec extensively to cover controller, model, view, and feature specs. As of Jun. 2018, Volt had 3751 specs and 495 of them were run with JavaScript enabled. It took about 16 mins to run on CircleCI with 6x parallelism.

Capybara-webkit was introduced from the very beginning of Volt for testing JavaScript-enabled specs via headless WebKit browser. It's been providing a lot of confidence for the past 4+ years; however, a few reasons/growing concerns have encouraged us to look for (more modern) alternatives:

Read on →

Hey everyone! I'm Justin, a senior engineer here at Artsy. I've been here for about 6 months and I'm a bit overdue on my first blog post. This will be one of a series of posts I'm dubbing roads and bridges (thanks Orta) describing infrastructure and tooling work here at Artsy.


Here at Artsy we have a lot of internal dependencies. Keeping these dependencies up to date across all of our projects can be a bit of a headache. For example, there's Palette (our design system) which is consumed by Reaction (our react component/app library), Emission (our React Native application), Force (our main site), and Positron (our editorial creation tool). That's not even an exhaustive list. As you can imagine, after making an update to Palette we have to make a lot of Pull Requests to get everything synced up across our many projects. And that's just one dependency.

Read on →

This year TypeScript gained a new feature that punches far above its weight.

Working through our (enormous) backlog of unsorted TypeScript "Suggestions" and it's remarkable how many of them are solved by conditional types.

-- Ryan Cavanaugh, TypeScript maintainer

Conditional types probably aren't something you'll write every day, but you might end up using them indirectly all the time. That's because they're great for 'plumbing' or 'framework' code, for dealing with API boundaries and other behind-the-scenes kinda stuff. So, dear reader, read on! It's always good to learn how the sausage is made. Then you can make sausage of your own.

Typewurst! 🌭

Read on →

Let's talk about email HTML.

If you've never worked on emails before, you might think the process works something like this:

  1. Write some HTML, but maybe with a few more tables than you usually use since emails like those.
  2. Render it in your browser. Nice! Looking great.
  3. Send yourself a quick test. Just like in your browser! Sweet!
  4. Send that PR and move on to the next thing.


In reality, it's more like this:

  1. Write some HTML with more tables than you think could possibly be necessary. There's no way it'll break with all these tables, right?
  2. Render it in the browser. Cool, looks fine.
  3. Send yourself a test, and send one to a service like Litmus or Email on Acid that renders the email in dozens of clients
  4. Looking good in Gmail...good in Apple mail...wait why is it completely broken in Outlook 2007 (and 2010, 2013, and 2019)? And Yahoo Mail on Internet Explorer? Shoot.
  5. Better add some more tables. That's usually the solution.
  6. Well...that didn't work. Find a post from 2009 in a forum for Netscape enthusiasts that implies you might want to add an extra Outlook-only table using <!--[if mso | IE]> with role="presentation" and cellpadding="0" cellspacing="0". Maybe that'll work.
  7. Outlook 2007 is fixed! Nice! Oh...but now it looks broken on iPhones. Back to the drawing board.


Read on →

Artsy's New York HQ occupies four top floors of 401 Broadway, located in historic Tribeca at the intersection of Broadway & Canal St., famous for its sellers of fake designer bags. Five elevators carry you up to our breathtaking views, albeit slowly.

Despite having been fully rebuilt in the last few years these machines are simply too few for the too many people working in the building. The lobby gets packed in the morning. The floors are crowded with coworkers waiting for an elevator to go to lunch around noon. Elevators make all local stops.

Because everything is a technology problem, I decided to improve this situation during our fall hackathon by building a Slack bot to call the elevator. Slack it, keep working for a few minutes, then dash out when you hear the elevator "ding", collectively gaining hours of productivity!

Read on →