{"id":2015,"date":"2016-02-09T11:48:51","date_gmt":"2016-02-09T17:48:51","guid":{"rendered":"http:\/\/jamesonquave.com\/blog\/?p=2015"},"modified":"2016-02-09T12:02:13","modified_gmt":"2016-02-09T18:02:13","slug":"how-to-migrate-your-app-and-protect-it-from-shutdowns-like-parses","status":"publish","type":"post","link":"https:\/\/jamesonquave.com\/blog\/how-to-migrate-your-app-and-protect-it-from-shutdowns-like-parses\/","title":{"rendered":"How To Migrate Your App And Protect It From Shutdowns Like Parse&#8217;s"},"content":{"rendered":"<h1 id=\"how-to-migrate-your-app-and-protect-it-from-shutdowns-like-parse-s\">How To Migrate Your App And Protect It From Shutdowns Like Parse&#8217;s<\/h1>\n<div style=\"display: block; clear: both;\">\n<img decoding=\"async\" src=\"http:\/\/jamesonquave.com\/blog\/wp-content\/uploads\/reinder100px.jpg\" align=\"left\" style=\"clear: both;\" \/><br \/>\n<strong>Editor&#8217;s Note:<\/strong> This article is written by Reinder de Vries, indie app developer at <a href=\"https:\/\/learnappmaking.com\">LearnAppMaking.com<\/a>.<\/div>\n<h1> <\/h1>\n<h1>Oh no! Parse is shutting down&#8230; How do you move on?<\/h1>\n<p>On January 28th <a href=\"http:\/\/blog.parse.com\/announcements\/moving-on\/\">Parse announced<\/a> it will be shutting down its service. They&#8217;re winding down the done-for-you Backend-as-a-Service, fully retiring it on January 28, 2017.<\/p>\n<p>That&#8217;s bad news for over 500.000 developers who relied on the service since 2011. <a href=\"http:\/\/jamesonquave.com\/blog\/your-parse-backend-was-always-a-bad-idea\/\">Like Jameson argued in his recent blog post<\/a>, developers are feeling betrayed in their trust. <\/p>\n<p>Parse was acquired in 2013 by Facebook for $ 85 million and now the &#8220;Big Five&#8221; monarch cold-bloodedly pulls the plug on the backbone of many developer&#8217;s apps. <\/p>\n<p>Back in 2013 Parse was a risky acquisition, which Facebook needed to get a foothold in the mobile market. Facebook&#8217;s recent earnings report shows a growth in mobile advertising revenue of 52%, comparing Q4 of 2014 and 2015, which clearly shows they&#8217;ve landed in mobile. <\/p>\n<p>With the rise in competition of cloud services by the likes of Amazon, Microsoft and Google, you could argue Facebook doesn&#8217;t need Parse anymore. From a business perspective I couldn&#8217;t agree more with them, but from a developer&#8217;s perspective it&#8217;s an awful move to make.<\/p>\n<p>Or is it?<\/p>\n<h2 id=\"parse-s-shutdown-is-an-opportunity-for-app-developers\">Parse&#8217;s Shutdown Is An Opportunity For App Developers<\/h2>\n<p>Before I built apps, I built websites. Lots and lots of websites. I learned all the necessary skills: HTML, CSS, JavaScript, PHP and MySQL. The quality and elegance of my code back then would make your skin crawl, but through trial and error I eventually mastered delivering quality websites.<\/p>\n<p>Throughout the years I kept my craft up-to-date by building the occasional web app. Newer and more advanced tools became available and my job required I use them. I&#8217;ve transitioned from jQuery to Angular to React, touched on too many JavaScript frameworks in between, saw the rise of package managers and GitHub (SourceForge, anyone?), the switch from PHP 4 to PHP 5 to PHP 5.6 and the upcoming PHP 7. My MySQL tables exploded, so I switched to Elasticsearch and Mongo.<\/p>\n<p>A while back I wanted to automate email newsletter signups and TestFlight beta invites. If you&#8217;d subscribe to the newsletter and confirmed your subscription, the workflow would automatically add you to my TestFlight pool of beta testers. I knew about the awesome FastLane toolset, and its <em>boarding<\/em> component, and figured <em>boarding<\/em>&#8216;s HTML form must have a POST URL endpoint I could hijack. Essentially, I&#8217;d catch the subscriber&#8217;s email address from my form and input it into the <em>boarding<\/em> form. <em>Boarding<\/em> would take care of the rest, like adding the subscriber to the TestFlight beta tester pool.<\/p>\n<p>There was only one problem: the <em>boarding<\/em> form had CSRF protection, which meant it expected a unique token to be included in every request. Those tokens are created server-side and in my workflow I didn&#8217;t have access to them. <\/p>\n<p>I had access to <em>boarding<\/em>&#8216;s source code, so technically I could solve the problem by disabling the CSRF protection. There was only one caveat: the source code was in Ruby, and I haven&#8217;t seen a single line of Ruby in my entire life (OK, maybe one), let alone have written one.<\/p>\n<p>Thanks to my extensive background in back-end programming, I&#8217;m not afraid of getting my hands dirty with technology I don&#8217;t know. Years of tinkering and making mistakes gave me a perfect understanding of how the web works. Instead of shying away from a black box, I dug deeper. <\/p>\n<p>I saw libraries I&#8217;d never heard of, with even stranger names (is this a thing?), and finally found the file that governed the CSRF protection feature. Ultimately, turning it off simply meant &#8220;nulling&#8221; a controller.<\/p>\n<h2 id=\"the-back-end-black-box\">The Back-End Black Box<\/h2>\n<p>Almost every successful app uses some sort of back-end service to connect app users to each other, and persist user data on a server. <\/p>\n<p>Many developers I meet and coach don&#8217;t have a solid understanding of back-end programming. Once they set up their Parse configuration in the overly simple Dashboard, write a query, they just assume their data is &#8220;out there&#8221;. Why would you bother finding out what happens in the cloud?<\/p>\n<p>I often explain Parse as &#8220;a spreadsheet for your app&#8221;. It&#8217;s true: the Parse Dashboard isn&#8217;t more complicated than Google Spreadsheets, yet it powers the entire back-end of your app. You don&#8217;t even have to write queries for data, instead you use convenience methods like:<\/p>\n<pre><code><div id=\"highlighter_104790\" class=\"syntaxhighlighter nogutter highlightedCode \"><table border=\"0\" cellpadding=\"0\" cellspacing=\"0\"><tbody><tr><td class=\"code\"><div class=\"container\"><div class=\"line number1 index0 alt2\"><code class=\"color2\">PFQuery<\/code><code class=\"plain\">(className: <\/code><code class=\"string\">\"Tweet\"<\/code><code class=\"plain\">).whereKey(<\/code><code class=\"string\">\"user\"<\/code><code class=\"plain\">, currentUser);<\/code><\/div><\/div><\/td><\/tr><\/tbody><\/table><\/div><\/code><\/pre>\n<p>It&#8217;s perhaps also Parse&#8217;s fault. Their <code>PFQueryTableViewController<\/code> is so incredibly easy to use, but pretty dangerous: it directly couples back-end code with your app&#8217;s view controller (which is already a ViewModel). Even if you wanted to switch from Parse to Firebase, your code is so tightly coupled you have to rewrite your entire app before you can migrate.<\/p>\n<p>Parse&#8217;s <code>PFObject<\/code> class has mapping built in, so you can work with string data as native Swift <code>String<\/code> objects, while in fact the Parse SDK turns that into data it can send over the internet. If you pass around <code>PFObject<\/code> instances in your user-facing code, you&#8217;re going to have a hard time replacing that with a new Backend-as-a-Service SDK.<\/p>\n<p>If you would have built your own back-end from scratch, you would have known for instance that <code>true<\/code> (a boolean) is sometimes turned into <code>\"true\"<\/code> (a string) when encoded as JSON. If that hits your app, you&#8217;re suddenly working with an instance of <code>String<\/code> instead of the <code>Bool<\/code> you expected. Fortunately Swift has an incredible type system, but an <code>if let<\/code> optional binding statement only protects against a type mismatch &#8212; it doesn&#8217;t resolve it!<\/p>\n<p>So how&#8217;s this Parse shutdown good for you? It&#8217;s time to start tinkering again, to dig deeper into the black box and to protect your code against shutdowns like Parse&#8217;s.<\/p>\n<h2 id=\"3-ways-to-make-your-app-shutdown-proof\">3 Ways To Make Your App Shutdown Proof<\/h2>\n<p>Next time you build an app, keep these three heuristics in mind. Instead of relying for 100% on one provider whose service is vital to the continuity and success of your app, you can protect yourself against shutdowns.<\/p>\n<p><strong>1. Make a list of alternatives<\/strong><br \/>\nParse has a couple of similar providers, like Firebase. Perhaps you didn&#8217;t even know Firebase existed until you Googled for alternatives in reaction to Parse&#8217;s shutdown. <\/p>\n<p>The cool thing is: most of these services know you&#8217;re looking for them. If you Google &#8220;parse shutdown&#8221; or &#8220;parse migration&#8221;, you&#8217;re hit with multiple highly relevant Google AdWords ads that tell you to migrate over to their service. Don&#8217;t do it!<\/p>\n<p>Instead, make a list of alternatives. Just make yourself comfortable with what&#8217;s out there. It&#8217;s never a bad idea to have a list of providers you rely on, and their alternatives. Just like a supermarket has a list of alternative milk suppliers in case their main provider goes out of business, you should keep a list of companies <em>you do business with<\/em>.<\/p>\n<p>You can of course also use the list of alternatives to do some proper research about the technologies and SDKs you&#8217;re going to use. I didn&#8217;t know OneSignal existed until I started looking for a free push provider, to replace Urban Airship, because I found it too expensive.<\/p>\n<p><strong>2. Decouple your code<\/strong><br \/>\nRegardless of how dull it may sound: Model-View-Controller still has a point. We&#8217;re getting used to coding Model-View-Whatever, but the principle of MVC remains: your Controller shouldn&#8217;t configure Views, and your View shouldn&#8217;t manipulate a Model.<\/p>\n<p>Cocoa Touch makes it hard to not use MVVM (Model-View-ViewModel), but that doesn&#8217;t mean you should tightly couple your Model code in your View Controller code.<\/p>\n<p>In programming theory we&#8217;ve got two principles: <em>coupling<\/em> and <em>encapsulation<\/em>. Working with two tightly coupled classes means ClassA makes a lot of assumptions about the inner functionality of ClassB. <\/p>\n<p>Imagine a car and a driver. The driver sits in the front of the car, because the steering column is directly connected to the engine. What if the driver suddenly decided to sit in the back, in order to drive the car? Then the driving doesn&#8217;t work. Of course, such a situation never happens in real life, but it happens in your code all the time.<\/p>\n<p>A protection against tight coupling is encapsulation. This means every class has a strictly defined set of methods, such as <code>speedUp()<\/code> and <code>steerLeft()<\/code>. Instead of letting the driver inject more gas into the combustion chamber, relying on the engine being of the combustible kind, you simply let the driver call <code>speedUp()<\/code>. This way the driver doesn&#8217;t have intricate knowledge about the workings of the engine, but instead calls upon a function he knows is safe.<\/p>\n<p>When the engine gets replaced by an electric one, which doesn&#8217;t have a combustion chamber, you don&#8217;t have to change the driver&#8217;s code: he relies on a <code>speedUp()<\/code> method to be present, instead of relying on a <code>injectGasMixture()<\/code>, <code>gasMixture<\/code> and <code>sparkTimer<\/code>.<\/p>\n<p>If you find the principle of decoupling and encapsulation hard to grasp, think of it as <em>responsibilities<\/em>. Whose responsibility is it to drive the car? The driver&#8217;s. Who&#8217;s responsibility is it to make the car able to move forward? The engine&#8217;s.<\/p>\n<p>When you&#8217;re coding your back-end enabled app, make sure you clearly define its components and their responsibilities. Create a class you only use as an intermediary between back-end code and front-end code. The front-end code is based on your own native classes, like <code>Car<\/code>, and the back-end code has intricate knowledge about the back-end SDK you use, and works with classes like <code>PFObject<\/code>. <\/p>\n<p>It&#8217;s the intermediary&#8217;s job to communicate between the front-end and the back-end. In case your back-end code becomes obsolete, you can replace the intermediary with code that understands your new back-end SDK, without rewriting the front-end code as well.<\/p>\n<p><strong>3. Use the Adapter Pattern<\/strong><br \/>\nThe third and last heuristic ties into the principle of loosely coupled code. The <em>Adapter Pattern<\/em>, older than the internet itself, is an Object-Oriented Programming pattern. It&#8217;s a set of programming design rules you can use to make two incompatible classes compatible with each other. <\/p>\n<p>It&#8217;s similar to making a &#8220;wrapper&#8221;, but instead of just exposing the interface of one resource (like wrapping a REST API) it also mediates between two incompatible interfaces by defining a set of rules. In many programming languages these rules are called interfaces (Java and PHP), in Swift and Objective-C they&#8217;re called <em>protocols<\/em>.<\/p>\n<p>You do know Swift&#8217;s <em>generics<\/em>, right? If it swims like a duck and quacks like a duck, it must be a duck. The Adapter Pattern has a similar mechanism. Instead of integrating ClassA and ClassB tightly with each other, by making direct calls from A to B, you build an adaptor class around ClassA.<\/p>\n<p>The adapter class has intricate knowledge about how ClassA works. The adapter class also conforms to a protocol. The protocol says: &#8220;You can be sure I have methods X, Y and Z&#8221;.<\/p>\n<p>ClassB doesn&#8217;t know ClassA. It only knows it wants to work with an instance that conforms to the adapter&#8217;s protocol. It doesn&#8217;t care if the instance is a duck, as long as it swims and quacks like a duck.<\/p>\n<p>What&#8217;s the benefit of working with an adapter? Well, in case your original ClassA code becomes obsolete, you can just find another class (i.e. another Parse alternative) and write an adapter for it. As long as this adapter conforms to the protocol, the rules you defined earlier, ClassB still works.<\/p>\n<p>In reality, you would write an adapter (<code>MyTwitterAdapter<\/code>) that has a method with this signature:<\/p>\n<pre><code><div id=\"highlighter_866603\" class=\"syntaxhighlighter nogutter highlightedCode \"><table border=\"0\" cellpadding=\"0\" cellspacing=\"0\"><tbody><tr><td class=\"code\"><div class=\"container\"><div class=\"line number1 index0 alt2\"><code class=\"keyword\">class<\/code> <code class=\"color2\">MyTwitterAdapter<\/code><code class=\"plain\">:<\/code><code class=\"color2\">AnyTwitterServiceProtocol<\/code><\/div><div class=\"line number2 index1 alt1\"><code class=\"plain\">{<\/code><\/div><div class=\"line number3 index2 alt2\"><code class=\"undefined spaces\">&nbsp;&nbsp;&nbsp;&nbsp;<\/code><code class=\"keyword\">func<\/code> <code class=\"plain\">getTweetsWithUser(user:<\/code><code class=\"color2\">User<\/code><code class=\"plain\">, withPage page:<\/code><code class=\"color1\">Int<\/code> <code class=\"plain\">= 0)<\/code><\/div><div class=\"line number4 index3 alt1\"><code class=\"undefined spaces\">&nbsp;&nbsp;&nbsp;&nbsp;<\/code><code class=\"plain\">{<\/code><\/div><div class=\"line number5 index4 alt2\"><code class=\"undefined spaces\">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<\/code><code class=\"plain\">...<\/code><\/div><\/div><\/td><\/tr><\/tbody><\/table><\/div><\/code><\/pre>\n<p>The protocol (<code>AnyTwitterServiceProtocol<\/code>) contains the exact same method signature, but it doesn&#8217;t have any logic or method implementation. It just sets the rules.<\/p>\n<pre><code><div id=\"highlighter_272267\" class=\"syntaxhighlighter nogutter highlightedCode \"><table border=\"0\" cellpadding=\"0\" cellspacing=\"0\"><tbody><tr><td class=\"code\"><div class=\"container\"><div class=\"line number1 index0 alt2\"><code class=\"keyword\">protocol<\/code> <code class=\"color2\">AnyTwitterServiceProtocol<\/code><\/div><div class=\"line number2 index1 alt1\"><code class=\"plain\">{<\/code><\/div><div class=\"line number3 index2 alt2\"><code class=\"undefined spaces\">&nbsp;&nbsp;&nbsp;&nbsp;<\/code><code class=\"keyword\">func<\/code> <code class=\"plain\">getTweetsWithUser(user:<\/code><code class=\"color2\">User<\/code><code class=\"plain\">, withPage page:<\/code><code class=\"color1\">Int<\/code> <code class=\"plain\">= 0);<\/code><\/div><div class=\"line number4 index3 alt1\"><code class=\"undefined spaces\">&nbsp;&nbsp;&nbsp;&nbsp;<\/code><code class=\"plain\">...<\/code><\/div><\/div><\/td><\/tr><\/tbody><\/table><\/div><\/code><\/pre>\n<p>The front-end code (<code>MyTweetsViewController<\/code>) has a variable <code>twitter<\/code> of an undefined type, which it got from the &#8220;adapter factory&#8221;. This factory ensures you only have to replace class names once (or twice) if you change adapters. <\/p>\n<p>If you&#8217;d strictly define <code>twitter<\/code> to be of type <code>MyTwitterAdapter<\/code>, you would still tightly couple your code, most likely in more than one place. Then, if you replace your adapter for a new one, you still have to update a lot of code.<\/p>\n<p>Once you&#8217;ve got this set up, you can test if the <code>twitter<\/code> instance you&#8217;re working with conforms to the <code>AnyTwitterServiceProtocol<\/code>. <\/p>\n<pre><code><div id=\"highlighter_295627\" class=\"syntaxhighlighter nogutter highlightedCode \"><table border=\"0\" cellpadding=\"0\" cellspacing=\"0\"><tbody><tr><td class=\"code\"><div class=\"container\"><div class=\"line number1 index0 alt2\"><code class=\"keyword\">if<\/code> <code class=\"keyword\">let<\/code> <code class=\"plain\">_twitter = twitter <\/code><code class=\"keyword\">as<\/code><code class=\"plain\">? <\/code><code class=\"color2\">AnyTwitterServiceProtocol<\/code><\/div><div class=\"line number2 index1 alt1\"><code class=\"plain\">{<\/code><\/div><div class=\"line number3 index2 alt2\"><code class=\"undefined spaces\">&nbsp;&nbsp;&nbsp;&nbsp;<\/code><code class=\"comments\">\/\/ Yes, it conforms<\/code><\/div><div class=\"line number4 index3 alt1\"><code class=\"plain\">}<\/code><\/div><\/div><\/td><\/tr><\/tbody><\/table><\/div><\/code><\/pre>\n<p>Your front-end code doesn&#8217;t care anymore whether <code>twitter<\/code> is of type <code>Car<\/code>, <code>FooBar<\/code> or <code>Facebook<\/code>, as long as it conforms to <code>AnyTwitterServiceProtocol<\/code>. It simply wants to know if the instance has a method called <code>getTweetsWithUser:withPage:<\/code>.<\/p>\n<p><em>Note: in case you do want to strictly define the type of <code>twitter<\/code>, you can use a protocol as a type, and you can also work with generics.<\/em><\/p>\n<h2 id=\"what-s-next-\">What&#8217;s Next?<\/h2>\n<p>Now that you&#8217;ve learned that you should improve your business operations and your reliance on suppliers, and protect your code against sudden changes, you can figure out <em>how<\/em> to do that.<\/p>\n<p>Are you going to switch to Firebase? You should know that Firebase is owned by &#8220;Big Five&#8221; Google, and although Parse&#8217;s shutdown is no harbinger of more shutdowns, solely relying on a new provider leaves you equaly vulnerable as you were. Unless you protect your code, of course.<\/p>\n<p>A good exercise would be to learn about back-end programming. Parse has released an excellent replacement product, Parse Server, which you can run on your own server (as long as it can run NodeJS and MongoDB). In the following code guide I&#8217;ll show you how to migrate a simple app from Parse to Parse Server, with Heroku and MongoLab.<\/p>\n<p>Continue: <a href=\"https:\/\/learnappmaking.com\/how-to-migrate-parse-app-parse-server-heroku-mongolab\/\">Guide: How To Migrate Your Parse App To Parse Server With Heroku And MongoLab<\/a><\/p>\n<p>Another relatively easy exercise is to migrate your Push Notifications to <em>two<\/em> services instead of one. Implementing the client-side SDK of a push provider is relatively easy, usually you only have to send over the unique push ID and set up a segment. <\/p>\n<p>Use the Adapter Pattern to create a unified interface your front-end code can talk to. Decouple the actual adapter from the front-end code by defining a protocol. Pick a second Push Notifications provider (like Urban Airship, Mixpanel, Pusher or PushOver) and write a second adapter. Make sure it conforms to the protocol, and then simulate a service breakdown in which you have to deploy your new adapter. Does it work?<\/p>\n<h2 id=\"conclusion\">Conclusion<\/h2>\n<p>Don&#8217;t be afraid to go deep into the black box. It&#8217;s not a bad idea to write your own back-end REST API, just for the fun and experience of it. You&#8217;ll learn a lot.<\/p>\n<p>Did you know Crashlytics is owned by Twitter? Anything could shutdown&#8230; Make sure you know what Crashlytics does for you, and how it works. It&#8217;s the only way to build a stable, reliable and long-term profitable business.<\/p>\n<p><em>Down the rabbit hole you go.<\/em><\/p>\n<h2 id=\"about-the-author\">About the author<\/h2>\n<p>Reinder de Vries is an indie app maker who teaches aspiring app developers and marketers how to build their own apps at <a href=\"https:\/\/learnappmaking.com\">LearnAppMaking.com<\/a>. He has developed 50+ apps and his code is used by millions of users all over the globe. When he\u2019s not coding, he enjoys strong espresso and traveling.<\/p>\n","protected":false},"excerpt":{"rendered":"<p>How To Migrate Your App And Protect It From Shutdowns Like Parse&#8217;s Editor&#8217;s Note: This article is written by Reinder de Vries, indie app developer at LearnAppMaking.com. Oh no! Parse is shutting down&#8230; How do you move on? On January 28th Parse announced it will be shutting down its service. They&#8217;re winding down the done-for-you&#8230;<\/p>\n","protected":false},"author":8,"featured_media":0,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"_links_to":"","_links_to_target":""},"categories":[50,26,10],"tags":[15,80],"yoast_head":"<!-- This site is optimized with the Yoast SEO plugin v19.13 - https:\/\/yoast.com\/wordpress\/plugins\/seo\/ -->\n<title>How To Migrate Your App And Protect It From Shutdowns Like Parse&#039;s - Jameson Quave<\/title>\n<meta name=\"robots\" content=\"index, follow, max-snippet:-1, max-image-preview:large, max-video-preview:-1\" \/>\n<link rel=\"canonical\" href=\"https:\/\/jamesonquave.com\/blog\/how-to-migrate-your-app-and-protect-it-from-shutdowns-like-parses\/\" \/>\n<meta property=\"og:locale\" content=\"en_US\" \/>\n<meta property=\"og:type\" content=\"article\" \/>\n<meta property=\"og:title\" content=\"How To Migrate Your App And Protect It From Shutdowns Like Parse&#039;s - Jameson Quave\" \/>\n<meta property=\"og:description\" content=\"How To Migrate Your App And Protect It From Shutdowns Like Parse&#8217;s Editor&#8217;s Note: This article is written by Reinder de Vries, indie app developer at LearnAppMaking.com. Oh no! Parse is shutting down&#8230; How do you move on? On January 28th Parse announced it will be shutting down its service. They&#8217;re winding down the done-for-you...\" \/>\n<meta property=\"og:url\" content=\"https:\/\/jamesonquave.com\/blog\/how-to-migrate-your-app-and-protect-it-from-shutdowns-like-parses\/\" \/>\n<meta property=\"og:site_name\" content=\"Jameson Quave\" \/>\n<meta property=\"article:published_time\" content=\"2016-02-09T17:48:51+00:00\" \/>\n<meta property=\"article:modified_time\" content=\"2016-02-09T18:02:13+00:00\" \/>\n<meta property=\"og:image\" content=\"http:\/\/jamesonquave.com\/blog\/wp-content\/uploads\/reinder100px.jpg\" \/>\n<meta name=\"author\" content=\"Reinder de Vries\" \/>\n<meta name=\"twitter:card\" content=\"summary_large_image\" \/>\n<meta name=\"twitter:label1\" content=\"Written by\" \/>\n\t<meta name=\"twitter:data1\" content=\"Reinder de Vries\" \/>\n\t<meta name=\"twitter:label2\" content=\"Est. reading time\" \/>\n\t<meta name=\"twitter:data2\" content=\"13 minutes\" \/>\n<script type=\"application\/ld+json\" class=\"yoast-schema-graph\">{\"@context\":\"https:\/\/schema.org\",\"@graph\":[{\"@type\":\"WebPage\",\"@id\":\"https:\/\/jamesonquave.com\/blog\/how-to-migrate-your-app-and-protect-it-from-shutdowns-like-parses\/\",\"url\":\"https:\/\/jamesonquave.com\/blog\/how-to-migrate-your-app-and-protect-it-from-shutdowns-like-parses\/\",\"name\":\"How To Migrate Your App And Protect It From Shutdowns Like Parse's - Jameson Quave\",\"isPartOf\":{\"@id\":\"https:\/\/jamesonquave.com\/blog\/#website\"},\"datePublished\":\"2016-02-09T17:48:51+00:00\",\"dateModified\":\"2016-02-09T18:02:13+00:00\",\"author\":{\"@id\":\"https:\/\/jamesonquave.com\/blog\/#\/schema\/person\/2e3942799f6b74cc84f7a179ab2b08d7\"},\"breadcrumb\":{\"@id\":\"https:\/\/jamesonquave.com\/blog\/how-to-migrate-your-app-and-protect-it-from-shutdowns-like-parses\/#breadcrumb\"},\"inLanguage\":\"en-US\",\"potentialAction\":[{\"@type\":\"ReadAction\",\"target\":[\"https:\/\/jamesonquave.com\/blog\/how-to-migrate-your-app-and-protect-it-from-shutdowns-like-parses\/\"]}]},{\"@type\":\"BreadcrumbList\",\"@id\":\"https:\/\/jamesonquave.com\/blog\/how-to-migrate-your-app-and-protect-it-from-shutdowns-like-parses\/#breadcrumb\",\"itemListElement\":[{\"@type\":\"ListItem\",\"position\":1,\"name\":\"Home\",\"item\":\"https:\/\/jamesonquave.com\/blog\/\"},{\"@type\":\"ListItem\",\"position\":2,\"name\":\"How To Migrate Your App And Protect It From Shutdowns Like Parse&#8217;s\"}]},{\"@type\":\"WebSite\",\"@id\":\"https:\/\/jamesonquave.com\/blog\/#website\",\"url\":\"https:\/\/jamesonquave.com\/blog\/\",\"name\":\"Jameson Quave\",\"description\":\"Using computer technology to educate, and improve lives.\",\"potentialAction\":[{\"@type\":\"SearchAction\",\"target\":{\"@type\":\"EntryPoint\",\"urlTemplate\":\"https:\/\/jamesonquave.com\/blog\/?s={search_term_string}\"},\"query-input\":\"required name=search_term_string\"}],\"inLanguage\":\"en-US\"},{\"@type\":\"Person\",\"@id\":\"https:\/\/jamesonquave.com\/blog\/#\/schema\/person\/2e3942799f6b74cc84f7a179ab2b08d7\",\"name\":\"Reinder de Vries\",\"image\":{\"@type\":\"ImageObject\",\"inLanguage\":\"en-US\",\"@id\":\"https:\/\/jamesonquave.com\/blog\/#\/schema\/person\/image\/\",\"url\":\"https:\/\/secure.gravatar.com\/avatar\/1c3a5be175df03206782b6261adb8eb7?s=96&d=retro&r=pg\",\"contentUrl\":\"https:\/\/secure.gravatar.com\/avatar\/1c3a5be175df03206782b6261adb8eb7?s=96&d=retro&r=pg\",\"caption\":\"Reinder de Vries\"},\"sameAs\":[\"http:\/\/learnappmaking.com\"],\"url\":\"https:\/\/jamesonquave.com\/blog\/author\/reinder\/\"}]}<\/script>\n<!-- \/ Yoast SEO plugin. -->","yoast_head_json":{"title":"How To Migrate Your App And Protect It From Shutdowns Like Parse's - Jameson Quave","robots":{"index":"index","follow":"follow","max-snippet":"max-snippet:-1","max-image-preview":"max-image-preview:large","max-video-preview":"max-video-preview:-1"},"canonical":"https:\/\/jamesonquave.com\/blog\/how-to-migrate-your-app-and-protect-it-from-shutdowns-like-parses\/","og_locale":"en_US","og_type":"article","og_title":"How To Migrate Your App And Protect It From Shutdowns Like Parse's - Jameson Quave","og_description":"How To Migrate Your App And Protect It From Shutdowns Like Parse&#8217;s Editor&#8217;s Note: This article is written by Reinder de Vries, indie app developer at LearnAppMaking.com. Oh no! Parse is shutting down&#8230; How do you move on? On January 28th Parse announced it will be shutting down its service. They&#8217;re winding down the done-for-you...","og_url":"https:\/\/jamesonquave.com\/blog\/how-to-migrate-your-app-and-protect-it-from-shutdowns-like-parses\/","og_site_name":"Jameson Quave","article_published_time":"2016-02-09T17:48:51+00:00","article_modified_time":"2016-02-09T18:02:13+00:00","og_image":[{"url":"http:\/\/jamesonquave.com\/blog\/wp-content\/uploads\/reinder100px.jpg"}],"author":"Reinder de Vries","twitter_card":"summary_large_image","twitter_misc":{"Written by":"Reinder de Vries","Est. reading time":"13 minutes"},"schema":{"@context":"https:\/\/schema.org","@graph":[{"@type":"WebPage","@id":"https:\/\/jamesonquave.com\/blog\/how-to-migrate-your-app-and-protect-it-from-shutdowns-like-parses\/","url":"https:\/\/jamesonquave.com\/blog\/how-to-migrate-your-app-and-protect-it-from-shutdowns-like-parses\/","name":"How To Migrate Your App And Protect It From Shutdowns Like Parse's - Jameson Quave","isPartOf":{"@id":"https:\/\/jamesonquave.com\/blog\/#website"},"datePublished":"2016-02-09T17:48:51+00:00","dateModified":"2016-02-09T18:02:13+00:00","author":{"@id":"https:\/\/jamesonquave.com\/blog\/#\/schema\/person\/2e3942799f6b74cc84f7a179ab2b08d7"},"breadcrumb":{"@id":"https:\/\/jamesonquave.com\/blog\/how-to-migrate-your-app-and-protect-it-from-shutdowns-like-parses\/#breadcrumb"},"inLanguage":"en-US","potentialAction":[{"@type":"ReadAction","target":["https:\/\/jamesonquave.com\/blog\/how-to-migrate-your-app-and-protect-it-from-shutdowns-like-parses\/"]}]},{"@type":"BreadcrumbList","@id":"https:\/\/jamesonquave.com\/blog\/how-to-migrate-your-app-and-protect-it-from-shutdowns-like-parses\/#breadcrumb","itemListElement":[{"@type":"ListItem","position":1,"name":"Home","item":"https:\/\/jamesonquave.com\/blog\/"},{"@type":"ListItem","position":2,"name":"How To Migrate Your App And Protect It From Shutdowns Like Parse&#8217;s"}]},{"@type":"WebSite","@id":"https:\/\/jamesonquave.com\/blog\/#website","url":"https:\/\/jamesonquave.com\/blog\/","name":"Jameson Quave","description":"Using computer technology to educate, and improve lives.","potentialAction":[{"@type":"SearchAction","target":{"@type":"EntryPoint","urlTemplate":"https:\/\/jamesonquave.com\/blog\/?s={search_term_string}"},"query-input":"required name=search_term_string"}],"inLanguage":"en-US"},{"@type":"Person","@id":"https:\/\/jamesonquave.com\/blog\/#\/schema\/person\/2e3942799f6b74cc84f7a179ab2b08d7","name":"Reinder de Vries","image":{"@type":"ImageObject","inLanguage":"en-US","@id":"https:\/\/jamesonquave.com\/blog\/#\/schema\/person\/image\/","url":"https:\/\/secure.gravatar.com\/avatar\/1c3a5be175df03206782b6261adb8eb7?s=96&d=retro&r=pg","contentUrl":"https:\/\/secure.gravatar.com\/avatar\/1c3a5be175df03206782b6261adb8eb7?s=96&d=retro&r=pg","caption":"Reinder de Vries"},"sameAs":["http:\/\/learnappmaking.com"],"url":"https:\/\/jamesonquave.com\/blog\/author\/reinder\/"}]}},"_links":{"self":[{"href":"https:\/\/jamesonquave.com\/blog\/wp-json\/wp\/v2\/posts\/2015"}],"collection":[{"href":"https:\/\/jamesonquave.com\/blog\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/jamesonquave.com\/blog\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/jamesonquave.com\/blog\/wp-json\/wp\/v2\/users\/8"}],"replies":[{"embeddable":true,"href":"https:\/\/jamesonquave.com\/blog\/wp-json\/wp\/v2\/comments?post=2015"}],"version-history":[{"count":4,"href":"https:\/\/jamesonquave.com\/blog\/wp-json\/wp\/v2\/posts\/2015\/revisions"}],"predecessor-version":[{"id":2020,"href":"https:\/\/jamesonquave.com\/blog\/wp-json\/wp\/v2\/posts\/2015\/revisions\/2020"}],"wp:attachment":[{"href":"https:\/\/jamesonquave.com\/blog\/wp-json\/wp\/v2\/media?parent=2015"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/jamesonquave.com\/blog\/wp-json\/wp\/v2\/categories?post=2015"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/jamesonquave.com\/blog\/wp-json\/wp\/v2\/tags?post=2015"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}