{"action":"created","comment":{"url":"https://api.github.com/repos/artsy/artsy.github.io/pulls/comments/98818472","pull_request_review_id":19472865,"id":98818472,"diff_hunk":"@@ -0,0 +1,245 @@\n+---\n+layout: post\n+title: \"Postmortem: Swift at Artsy\"\n+date: 2017-01-22 12:18\n+author: orta\n+categories: [swift, eigen, eidolon, javascript, emission, reactnative]\n+series: React Native at Artsy\n+---\n+\n+<center>\n+<img src=\"/images/swift-in-rn/swift-in-react-native.svg\" style=\"width:300px;\">\n+</center>\n+\n+Swift became public in June 2014, by August we had started using it in Artsy. By October, we had [Swift in production][eidolon-postmortem] channeling hundreds of thousands of dollars in auction bids. It was pretty obvious that Swift is the future of native development on Apple platforms. \n+\n+Since then we've built an [appleTV app][emergence] in Swift, integrated Swift-support into our key app Eigen and built non-trivial parts of that [application in Swift][live-a].\n+\n+We first started experimenting with with React Native in February 2016, and by August 2016, we announced that [Artsy moved to React Native][artsy-rn] effectively meaning new code would be in JavaScript from here onwards.\n+\n+We're regularly asked _why_ we moved, and it was touched on briefly in our announcement but I'd like to dig in to this and try to cover a lot of our decision process. So, if you're into understanding why a small team of iOS developers with decades of experience switched to JavaScript, read on. \n+\n+<!-- more -->\n+\n+We were finding that our current patterns of building apps were not scaling as the team and app scope grew. Building anything new inside Eigen barely re-used existing code, and it was progressively taking longer and longer to build features. App and test build times were increasing, it would take 2 iOS engineers to build a feature in a similar time-frame as a single web engineer. \n+\n+By [March 2015][gave_up], we gave up trying to keep pace with the web.\n+\n+Once we came to this conclusion, our discussion came to \"what can we do to fix this?\" Over the course of the 2015/2016 winter break we explored ideas on how we could write more re-usable code.    \n+\n+# What are Artsy's apps?\n+\n+Eigen specifically is an app where we taken JSON data from the server, and convert it into a user interface. It nearly always can be described as a function taking data and mapping it to a UI.\n+\n+We have different apps with different trade-offs. [Eidolon][eidolon] (our Auctions Kiosk app) which contains a lot of Artsy-wide unique business logic which is handled with local state like card reader input, or unique user identification modes. [Emergence][emergence] is a trivial-ish tvOS app which has a few view controllers, and is mostly handled by Xcode's storyboards.\n+\n+Eigen is where we worry, other apps are limited in their scope, but Eigen is basically the mobile representation of Artsy. We're never _not_ going to have something like Eigen.\n+\n+We eventually came to the conclusion that we needed to re-think our entire UIKit stack for Eigen. Strictly speaking, Objective-C was not a problem for us, our issues came from abstractions around the way we built apps.\n+\n+Re-writing from scratch was not an option. That takes a lot of time and effort, which will happily remove technical debt, but that's not our issue. We also don't need or have a big redesign. However, a lot of companies used the Objective-C -> Swift transition as a time to re-write from scratch. We asked for the experiences from developers who had opted to do this, they said it was a great marketing tool for hiring - but was a lot of pain to actually work with day to day. They tend to talk abut technical debt, and clean slates - but not that Objective-C was painful and Swift solves major architectural problems. \n+\n+In the end, for Eigen, we came to the conclusion that we could try build a component-based architecture either from scratch ( similar to the patterns in Spotify's ([hub][hub]) or Hyperslo's ([Spots][spots]) ) or inspired by React ( like Bending Spoons's ([Katana][katana]) ).\n+\n+# Swift's upsides\n+\n+Continuing to build native apps via native code had quite a bit running for it:\n+\n+* **It was consistent with our existing code.** We wrote hundreds of thousands of lines of code in Objective-C and maybe around a hundred thousand of Swift. The majority of the team had 5+ years of Cocoa experience and no-one needs to essentially argue that _continuing_ with that has value.\n+\n+* **Swift code can interact with Objective-C and can work on it's own.** We can write Swift libraries that can build on-top of our existing infrastructure to work at a higher level of abstraction. Building a component-based infrastructure via Swift could allow easy-reuse of existing code, while providing a language difference for \"new app code\" vs \"infra.\" \n+\n+* **People are excited about Swift.** It's an interesting, growing language, and one of the few ones non-technical people ask about. \"Oh you're an iOS developer, do you use Swift?\" is something I've been asked a lot. The rest of the development team  have signed up multiple times for Swift workshops and want to know what Swift is, and what it's trade-offs are.\n+\n+* **Swift improves on a lot of Objective-C.** Most of the patterns that we use in Objective-C are verbose, and they can become extremely terse inside Swift. Potentially making it easier to read and understand. \n+\n+* **We would be using the official route.** Apple obviously _want_ you to be using Swift, they are putting a _lot_ of resources into the language. There are smart people working on the project, and it's becomes more stable and useful every year. There aren't any _Swift-only_ APIs yet, but obviously they'll be coming.\n+\n+* **It's a [known-unknown][known-known] territory.** We have a lot of knowledge around building better tooling for iOS apps. From libraries like [Moya][moya], to foundational projects like [CocoaPods][cocoapods]. Coming up with, and executing dramatic tooling improvements is possible. Perhaps we had overlooked a smarter abstraction elsewhere and it was worth expanding our search.\n+\n+  This is worth continuing here, because if we end up building something which gains popularity we get the advantage of working with a lot of perspectives, and being able to gain from other people working on the same project. It's a pattern Basecamp discuss when they [talk about rails][rails] by beginning with a real project and abstracting outwards.\n+\n+# Native Downsides\n+\n+The dominant two issues come from differences in opinions in how software should be built\n+\n+* **Types.** Types are useful. Overly strict typing systems make to hard to build _quick_ (not easy) to change codebases.\n+\n+  Strictly typed language work _really_ well for [building systems][systems], or completely atomic apps - the sort Apple have to build on a day to day basis. When I say an atomic app, I mean one where the majority of the inputs and outputs exist within the domain of the application. Think of apps with their own filetypes, that can control inputs and outputs really easily.\n+\n+  Even in Objective-C, a looser-typed language where you were not discouraged from using meta--programming, handling JSON required _a tonne_ of boilerplate laden, inelegant code when working with an API. Considering how bread-and-butter working with an API is for most 3rd party developers it should come as no surprise that the most popular CocoaPods are about handling JSON parsing, and making network requests.  \n+\n+  Problems which Apple, generally speaking, don't have. They use iCloud, or CloudKit, or whatever, and expect you to too. The official Apple opinion was neatly summed up on the official Swift blog on how to handle JSON parsing [exhibits the problem well][swift_blog].\n+\n+  > Swift’s built-in language features make it easy to safely extract and work with JSON data decoded with Foundation APIs — without the need for an external library or framework.\n+\n+  They do, but it's not great code to write nor maintain. I don't know anyone who does what they recommend in production.\n+\n+* **Slow.** Native development when put next to web development is slow. Application development requires full compilation cycles, and full state restart of the application that you're working on. A trivial string change in Eigen takes [25 seconds][eigen_25] to show up. When I tell some developers that time, they laugh and say I have it good.\n+\n+  This becomes extremely painful once you start [getting used][injection_twitter] to technologies like Injection for Xcode, which is what ruined my appetite for building apps the traditional way. We were starting to come up with all sorts of techniques to allow separation of any part of the codebase into a new app so you can iterate just there. \n+  \n+  I've heard developers say they use using Playgrounds to work around some of these problems, and the Kickstarter app has probably the closest I've seen to an [actual implmentation of this][kickstart_play].\n+\n+  The Swift compiler is slow. Yes, it will improve. One argument that it won't ever be as fast as Objective-C comes from Swift being a more complicated language to compile - it's doing more work. On the side of doing more work, the awesome type inference systems can make it feel arbitrary about what will take longer to compile or not. We eventually [automated having our CI warn us][danger-eigen] whether the code we were adding was slow.\n+\n+\n+# React Native\n+\n+You may want to read our announcement of switching to [React Native][artsy-rn] in anticipation of this. However the big three reasons are:\n+\n+* Better developer experience.\n+* Same conceptual levels as the rest of the team.\n+* Ownership of the whole stack.\n+\n+However, the key part of this post is how does this compare to native development? Also, have these arguments stood up to the test of time a year later? \n+\n+_Sidenote:_ I found it hard to write this without being able to comprehensively reference what we are doing now, and so, I'll be referencing a sibling article: [JS 2017][js-2017]. \n+\n+### Developer Experience\n+\n+The JavaScript ecosystem cares about how someone using the tool will feel. This is a part of what separates the good from the great in the community. It's not enough to just provide a great API, documentation but it should substantially improve the way you work. \n+\n+> References from JS 2017: [Relay][relay], [Jest][jest]\n+\n+As _everyone_ inside the community has both the ability and the tools to contribute to the ecosystem you get better tools. \n+\n+Apple make _great_ tools. I do miss Xcode sometimes. It's cohesive, beautifully designed and doesn't show it's age. It's a perfect Mac citizen.\n+\n+Though it's important to note that they make tools for Apple first and then for us 3rd party devs. Outside influence obviously exists, but they're shipping whatever _they_ want and you can only influence that via Radars and through going to a conference once a year and talking directly to the dev tools team. Only the Swift language is Open Source (and [SwiftPM][swiftpm])\n+\n+There are so few well built, large developer tools for the Apple eco-system. Developers are wary [of][stack] [being copied by Apple][https://twitter.com/mattt/status/473544723118837760] - something so prevalent that there is a common word for it, being [Sherlocked][sherlocked]. The project I've worked on for 5 years, CocoaPods, had an announcement of being sherlocked in late-2015 - you just have to deal with it. The idea that only Apple should be shipping these kind of things kills community momentum.\n+\n+If you're going to build something amazing, only to have all support pulled out from under you once it gets popular because apple copied it and made it for free and with a full time team behind it - why bother? \n+\n+This makes it tough for us, as the 3rd party community, to build useful tools on the kind of scale that is normal in other developer eco-systems. Think of Fastlane, which _needs_ a company like Twitter/Google to behind to handle the scale of usage because no-one else is fixing toolchain issues.\n+\n+### Better Abstractions, Better Developer Experience\n+\n+I've mentioned that the apps we build have problems specific to API-driven applications. This means that the majority of our work tends to be that we have the full data already, and need to iterate to get the right styling and logic mapping correct, in doing so we want to also make it easy to re-use code.\n+\n+The React component-oriented architecture makes it very easy to build these types of applications. Born out of the [JavaScript primordial soup][js-soup], where conceptual frameworks come and go every year or so. React has been around for a while now, and seems to have a lot of stopping power.\n+\n+All of these frameworks have the same domain problems that our iOS apps have, external API stores, complex user device state and a mature end-of-line API (either the DOM, or UIKit.) \n+\n+With React, the core concept of a virtual DOM means that you can simplify a lot of complicated state-management for your application. It becomes trivial, removing the need for more complicated state-handling ideas like functional or reactive programming.\n+\n+With Relay, we got an genuinely ground-breaking change in how interactions get handled with our API. I don't want to ever work against an API without a tool like Relay.\n+\n+> References from JS 2017: [React][react], [Relay][relay]\n+\n+Both of these tools provide a developer experience better than iOS native tooling. React's strict state management rules allow external tools to extend a React application easily, so the onus is not on the React team to make better tools. Other projects provide tools like:[debuggers][rn-debugger], [external state viewers][reactotron], [runtime code injection][hrm], [component storyboarding][storybook] all of which can be running simulatiously at runtime. \n+\n+A single press of save would take your changes, inject it into your current running application, keep you in the exact same place, depending on the type of change it could re-layout your views, and so you can stay in your editor and make your changes. From 25 seconds, to less than one.\n+\n+So, you're thinking _\"Yeah, but JavaScript...\"_ - well, we use TypeScript and it fixes pretty much every issue with JavaScript. Mix that with the fact that it's no problem for us to write native code when we need to. The last project I did on our React Native codebase require copious JS <-> Swift communication. It feels like the best of both worlds. Elegant, fast to work with application code in JS, with native tooling when we think it will be best for the project.\n+\n+> Reference from JS 2017: [TypeScript][typescript]\n+\n+There's one more thing that I want to really stress around developer experience, it's really easy to write tests for our React components. Testing in JavaScript is night-and-day better than native testing. Because we can run our tests outside of the simulator (due to React's virtual DOM) we have all tests related to all the changes in git running on save.\n+\n+#### Same Tools, Different Dev\n+\n+We wanted to stop being special snowflakes inside the dev team. Artsy has around 25 developers, the majority of which work with Ruby and JavaScript on a day-to-day basis. The mobile team was the single development team that didn't make their own API changes, used different toolchains and were much slower in shipping anything.","path":"_posts/2017-01-22-Swift-at-Artsy.md","position":143,"original_position":143,"commit_id":"0429d7246c333206ef1894eda15ce2106d0db3be","original_commit_id":"0429d7246c333206ef1894eda15ce2106d0db3be","user":{"login":"orta","id":49038,"avatar_url":"https://avatars.githubusercontent.com/u/49038?v=3","gravatar_id":"","url":"https://api.github.com/users/orta","html_url":"https://github.com/orta","followers_url":"https://api.github.com/users/orta/followers","following_url":"https://api.github.com/users/orta/following{/other_user}","gists_url":"https://api.github.com/users/orta/gists{/gist_id}","starred_url":"https://api.github.com/users/orta/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/orta/subscriptions","organizations_url":"https://api.github.com/users/orta/orgs","repos_url":"https://api.github.com/users/orta/repos","events_url":"https://api.github.com/users/orta/events{/privacy}","received_events_url":"https://api.github.com/users/orta/received_events","type":"User","site_admin":false},"body":"Cool re:snowflakes 👍 \r\n\r\nre: not strictly true - this is why I tried to note the lack of API work too, all other projects like this  ( like the elixir projects ) are backend systems","created_at":"2017-02-01T02:24:58Z","updated_at":"2017-02-01T02:24:58Z","html_url":"https://github.com/artsy/artsy.github.io/pull/309#discussion_r98818472","pull_request_url":"https://api.github.com/repos/artsy/artsy.github.io/pulls/309","_links":{"self":{"href":"https://api.github.com/repos/artsy/artsy.github.io/pulls/comments/98818472"},"html":{"href":"https://github.com/artsy/artsy.github.io/pull/309#discussion_r98818472"},"pull_request":{"href":"https://api.github.com/repos/artsy/artsy.github.io/pulls/309"}}},"pull_request":{"url":"https://api.github.com/repos/artsy/artsy.github.io/pulls/309","id":103786842,"html_url":"https://github.com/artsy/artsy.github.io/pull/309","diff_url":"https://github.com/artsy/artsy.github.io/pull/309.diff","patch_url":"https://github.com/artsy/artsy.github.io/pull/309.patch","issue_url":"https://api.github.com/repos/artsy/artsy.github.io/issues/309","number":309,"state":"open","locked":false,"title":"Post-mortem: Swift at Artsy + Exploration: Front-end JS in 2017","user":{"login":"orta","id":49038,"avatar_url":"https://avatars.githubusercontent.com/u/49038?v=3","gravatar_id":"","url":"https://api.github.com/users/orta","html_url":"https://github.com/orta","followers_url":"https://api.github.com/users/orta/followers","following_url":"https://api.github.com/users/orta/following{/other_user}","gists_url":"https://api.github.com/users/orta/gists{/gist_id}","starred_url":"https://api.github.com/users/orta/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/orta/subscriptions","organizations_url":"https://api.github.com/users/orta/orgs","repos_url":"https://api.github.com/users/orta/repos","events_url":"https://api.github.com/users/orta/events{/privacy}","received_events_url":"https://api.github.com/users/orta/received_events","type":"User","site_admin":false},"body":"This is going to take a while, and I'll keep hammering on it for a good few days in my spare moments. Wanted to get it out so it could have time to breathe, and so that we can get some interesting feedbcak","created_at":"2017-01-30T17:53:39Z","updated_at":"2017-02-01T02:24:58Z","closed_at":null,"merged_at":null,"merge_commit_sha":"7144e61e69eb2289263779232820360db82f4899","assignee":null,"assignees":[],"milestone":null,"commits_url":"https://api.github.com/repos/artsy/artsy.github.io/pulls/309/commits","review_comments_url":"https://api.github.com/repos/artsy/artsy.github.io/pulls/309/comments","review_comment_url":"https://api.github.com/repos/artsy/artsy.github.io/pulls/comments{/number}","comments_url":"https://api.github.com/repos/artsy/artsy.github.io/issues/309/comments","statuses_url":"https://api.github.com/repos/artsy/artsy.github.io/statuses/0429d7246c333206ef1894eda15ce2106d0db3be","head":{"label":"artsy:swift","ref":"swift","sha":"0429d7246c333206ef1894eda15ce2106d0db3be","user":{"login":"artsy","id":546231,"avatar_url":"https://avatars.githubusercontent.com/u/546231?v=3","gravatar_id":"","url":"https://api.github.com/users/artsy","html_url":"https://github.com/artsy","followers_url":"https://api.github.com/users/artsy/followers","following_url":"https://api.github.com/users/artsy/following{/other_user}","gists_url":"https://api.github.com/users/artsy/gists{/gist_id}","starred_url":"https://api.github.com/users/artsy/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/artsy/subscriptions","organizations_url":"https://api.github.com/users/artsy/orgs","repos_url":"https://api.github.com/users/artsy/repos","events_url":"https://api.github.com/users/artsy/events{/privacy}","received_events_url":"https://api.github.com/users/artsy/received_events","type":"Organization","site_admin":false},"repo":{"id":3114581,"name":"artsy.github.io","full_name":"artsy/artsy.github.io","owner":{"login":"artsy","id":546231,"avatar_url":"https://avatars.githubusercontent.com/u/546231?v=3","gravatar_id":"","url":"https://api.github.com/users/artsy","html_url":"https://github.com/artsy","followers_url":"https://api.github.com/users/artsy/followers","following_url":"https://api.github.com/users/artsy/following{/other_user}","gists_url":"https://api.github.com/users/artsy/gists{/gist_id}","starred_url":"https://api.github.com/users/artsy/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/artsy/subscriptions","organizations_url":"https://api.github.com/users/artsy/orgs","repos_url":"https://api.github.com/users/artsy/repos","events_url":"https://api.github.com/users/artsy/events{/privacy}","received_events_url":"https://api.github.com/users/artsy/received_events","type":"Organization","site_admin":false},"private":false,"html_url":"https://github.com/artsy/artsy.github.io","description":"The Artsy Engineering Open-Source Developers Blog","fork":false,"url":"https://api.github.com/repos/artsy/artsy.github.io","forks_url":"https://api.github.com/repos/artsy/artsy.github.io/forks","keys_url":"https://api.github.com/repos/artsy/artsy.github.io/keys{/key_id}","collaborators_url":"https://api.github.com/repos/artsy/artsy.github.io/collaborators{/collaborator}","teams_url":"https://api.github.com/repos/artsy/artsy.github.io/teams","hooks_url":"https://api.github.com/repos/artsy/artsy.github.io/hooks","issue_events_url":"https://api.github.com/repos/artsy/artsy.github.io/issues/events{/number}","events_url":"https://api.github.com/repos/artsy/artsy.github.io/events","assignees_url":"https://api.github.com/repos/artsy/artsy.github.io/assignees{/user}","branches_url":"https://api.github.com/repos/artsy/artsy.github.io/branches{/branch}","tags_url":"https://api.github.com/repos/artsy/artsy.github.io/tags","blobs_url":"https://api.github.com/repos/artsy/artsy.github.io/git/blobs{/sha}","git_tags_url":"https://api.github.com/repos/artsy/artsy.github.io/git/tags{/sha}","git_refs_url":"https://api.github.com/repos/artsy/artsy.github.io/git/refs{/sha}","trees_url":"https://api.github.com/repos/artsy/artsy.github.io/git/trees{/sha}","statuses_url":"https://api.github.com/repos/artsy/artsy.github.io/statuses/{sha}","languages_url":"https://api.github.com/repos/artsy/artsy.github.io/languages","stargazers_url":"https://api.github.com/repos/artsy/artsy.github.io/stargazers","contributors_url":"https://api.github.com/repos/artsy/artsy.github.io/contributors","subscribers_url":"https://api.github.com/repos/artsy/artsy.github.io/subscribers","subscription_url":"https://api.github.com/repos/artsy/artsy.github.io/subscription","commits_url":"https://api.github.com/repos/artsy/artsy.github.io/commits{/sha}","git_commits_url":"https://api.github.com/repos/artsy/artsy.github.io/git/commits{/sha}","comments_url":"https://api.github.com/repos/artsy/artsy.github.io/comments{/number}","issue_comment_url":"https://api.github.com/repos/artsy/artsy.github.io/issues/comments{/number}","contents_url":"https://api.github.com/repos/artsy/artsy.github.io/contents/{+path}","compare_url":"https://api.github.com/repos/artsy/artsy.github.io/compare/{base}...{head}","merges_url":"https://api.github.com/repos/artsy/artsy.github.io/merges","archive_url":"https://api.github.com/repos/artsy/artsy.github.io/{archive_format}{/ref}","downloads_url":"https://api.github.com/repos/artsy/artsy.github.io/downloads","issues_url":"https://api.github.com/repos/artsy/artsy.github.io/issues{/number}","pulls_url":"https://api.github.com/repos/artsy/artsy.github.io/pulls{/number}","milestones_url":"https://api.github.com/repos/artsy/artsy.github.io/milestones{/number}","notifications_url":"https://api.github.com/repos/artsy/artsy.github.io/notifications{?since,all,participating}","labels_url":"https://api.github.com/repos/artsy/artsy.github.io/labels{/name}","releases_url":"https://api.github.com/repos/artsy/artsy.github.io/releases{/id}","deployments_url":"https://api.github.com/repos/artsy/artsy.github.io/deployments","created_at":"2012-01-06T00:31:22Z","updated_at":"2017-01-27T18:03:17Z","pushed_at":"2017-01-31T01:59:15Z","git_url":"git://github.com/artsy/artsy.github.io.git","ssh_url":"git@github.com:artsy/artsy.github.io.git","clone_url":"https://github.com/artsy/artsy.github.io.git","svn_url":"https://github.com/artsy/artsy.github.io","homepage":"https://artsy.github.io","size":65092,"stargazers_count":189,"watchers_count":189,"language":"CSS","has_issues":true,"has_downloads":true,"has_wiki":false,"has_pages":true,"forks_count":98,"mirror_url":null,"open_issues_count":25,"forks":98,"open_issues":25,"watchers":189,"default_branch":"source"}},"base":{"label":"artsy:source","ref":"source","sha":"9f5ddf13c949c877048cabe24b1e2cd0912c0f57","user":{"login":"artsy","id":546231,"avatar_url":"https://avatars.githubusercontent.com/u/546231?v=3","gravatar_id":"","url":"https://api.github.com/users/artsy","html_url":"https://github.com/artsy","followers_url":"https://api.github.com/users/artsy/followers","following_url":"https://api.github.com/users/artsy/following{/other_user}","gists_url":"https://api.github.com/users/artsy/gists{/gist_id}","starred_url":"https://api.github.com/users/artsy/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/artsy/subscriptions","organizations_url":"https://api.github.com/users/artsy/orgs","repos_url":"https://api.github.com/users/artsy/repos","events_url":"https://api.github.com/users/artsy/events{/privacy}","received_events_url":"https://api.github.com/users/artsy/received_events","type":"Organization","site_admin":false},"repo":{"id":3114581,"name":"artsy.github.io","full_name":"artsy/artsy.github.io","owner":{"login":"artsy","id":546231,"avatar_url":"https://avatars.githubusercontent.com/u/546231?v=3","gravatar_id":"","url":"https://api.github.com/users/artsy","html_url":"https://github.com/artsy","followers_url":"https://api.github.com/users/artsy/followers","following_url":"https://api.github.com/users/artsy/following{/other_user}","gists_url":"https://api.github.com/users/artsy/gists{/gist_id}","starred_url":"https://api.github.com/users/artsy/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/artsy/subscriptions","organizations_url":"https://api.github.com/users/artsy/orgs","repos_url":"https://api.github.com/users/artsy/repos","events_url":"https://api.github.com/users/artsy/events{/privacy}","received_events_url":"https://api.github.com/users/artsy/received_events","type":"Organization","site_admin":false},"private":false,"html_url":"https://github.com/artsy/artsy.github.io","description":"The Artsy Engineering Open-Source Developers Blog","fork":false,"url":"https://api.github.com/repos/artsy/artsy.github.io","forks_url":"https://api.github.com/repos/artsy/artsy.github.io/forks","keys_url":"https://api.github.com/repos/artsy/artsy.github.io/keys{/key_id}","collaborators_url":"https://api.github.com/repos/artsy/artsy.github.io/collaborators{/collaborator}","teams_url":"https://api.github.com/repos/artsy/artsy.github.io/teams","hooks_url":"https://api.github.com/repos/artsy/artsy.github.io/hooks","issue_events_url":"https://api.github.com/repos/artsy/artsy.github.io/issues/events{/number}","events_url":"https://api.github.com/repos/artsy/artsy.github.io/events","assignees_url":"https://api.github.com/repos/artsy/artsy.github.io/assignees{/user}","branches_url":"https://api.github.com/repos/artsy/artsy.github.io/branches{/branch}","tags_url":"https://api.github.com/repos/artsy/artsy.github.io/tags","blobs_url":"https://api.github.com/repos/artsy/artsy.github.io/git/blobs{/sha}","git_tags_url":"https://api.github.com/repos/artsy/artsy.github.io/git/tags{/sha}","git_refs_url":"https://api.github.com/repos/artsy/artsy.github.io/git/refs{/sha}","trees_url":"https://api.github.com/repos/artsy/artsy.github.io/git/trees{/sha}","statuses_url":"https://api.github.com/repos/artsy/artsy.github.io/statuses/{sha}","languages_url":"https://api.github.com/repos/artsy/artsy.github.io/languages","stargazers_url":"https://api.github.com/repos/artsy/artsy.github.io/stargazers","contributors_url":"https://api.github.com/repos/artsy/artsy.github.io/contributors","subscribers_url":"https://api.github.com/repos/artsy/artsy.github.io/subscribers","subscription_url":"https://api.github.com/repos/artsy/artsy.github.io/subscription","commits_url":"https://api.github.com/repos/artsy/artsy.github.io/commits{/sha}","git_commits_url":"https://api.github.com/repos/artsy/artsy.github.io/git/commits{/sha}","comments_url":"https://api.github.com/repos/artsy/artsy.github.io/comments{/number}","issue_comment_url":"https://api.github.com/repos/artsy/artsy.github.io/issues/comments{/number}","contents_url":"https://api.github.com/repos/artsy/artsy.github.io/contents/{+path}","compare_url":"https://api.github.com/repos/artsy/artsy.github.io/compare/{base}...{head}","merges_url":"https://api.github.com/repos/artsy/artsy.github.io/merges","archive_url":"https://api.github.com/repos/artsy/artsy.github.io/{archive_format}{/ref}","downloads_url":"https://api.github.com/repos/artsy/artsy.github.io/downloads","issues_url":"https://api.github.com/repos/artsy/artsy.github.io/issues{/number}","pulls_url":"https://api.github.com/repos/artsy/artsy.github.io/pulls{/number}","milestones_url":"https://api.github.com/repos/artsy/artsy.github.io/milestones{/number}","notifications_url":"https://api.github.com/repos/artsy/artsy.github.io/notifications{?since,all,participating}","labels_url":"https://api.github.com/repos/artsy/artsy.github.io/labels{/name}","releases_url":"https://api.github.com/repos/artsy/artsy.github.io/releases{/id}","deployments_url":"https://api.github.com/repos/artsy/artsy.github.io/deployments","created_at":"2012-01-06T00:31:22Z","updated_at":"2017-01-27T18:03:17Z","pushed_at":"2017-01-31T01:59:15Z","git_url":"git://github.com/artsy/artsy.github.io.git","ssh_url":"git@github.com:artsy/artsy.github.io.git","clone_url":"https://github.com/artsy/artsy.github.io.git","svn_url":"https://github.com/artsy/artsy.github.io","homepage":"https://artsy.github.io","size":65092,"stargazers_count":189,"watchers_count":189,"language":"CSS","has_issues":true,"has_downloads":true,"has_wiki":false,"has_pages":true,"forks_count":98,"mirror_url":null,"open_issues_count":25,"forks":98,"open_issues":25,"watchers":189,"default_branch":"source"}},"_links":{"self":{"href":"https://api.github.com/repos/artsy/artsy.github.io/pulls/309"},"html":{"href":"https://github.com/artsy/artsy.github.io/pull/309"},"issue":{"href":"https://api.github.com/repos/artsy/artsy.github.io/issues/309"},"comments":{"href":"https://api.github.com/repos/artsy/artsy.github.io/issues/309/comments"},"review_comments":{"href":"https://api.github.com/repos/artsy/artsy.github.io/pulls/309/comments"},"review_comment":{"href":"https://api.github.com/repos/artsy/artsy.github.io/pulls/comments{/number}"},"commits":{"href":"https://api.github.com/repos/artsy/artsy.github.io/pulls/309/commits"},"statuses":{"href":"https://api.github.com/repos/artsy/artsy.github.io/statuses/0429d7246c333206ef1894eda15ce2106d0db3be"}}}}
{"actor":{"display_login":"orta"}}