Overview
One Approach
Tech Tips and Tales, and Lessons Learned
Parse.com announced on January 28th that they will be shutting down. Although this is disappointing news, the way Parse is handling the shutdown is exemplary. They are giving their customers one full year’s notice before they shut down their services, they have open-sourced their core technologies and all of their SDKs, provided a series of guides on how to move applications over to replacement service providers, and provided tools to assist in those migrations. In theory, it should be possible to move an app from Parse.com over to other providers with minimal downtime and minimal code changes. My testing so far has shown that theory to be correct.
I’ve completely moved only one of my systems so far, but the transition was indeed very straightforward and relatively simple. After spending some time to get familiar with the Parse server code, the actual time required to make the few changes necessary to my code was very small. My new Node.js server is based on the example parse-server-example GitHub code, but the server is just a very basic, standard Node.js server plus any Cloud Code and any static HTML files. All the Parse.com features are provided by the open source parse-server Node module.
The example server code required only some minor customization and configuration changes (and a small fix of a server bug) to be functional. My iOS and Android apps needed an update only for the new REST server URL, and my Parse Cloud Code needed only a few very minor security-related changes. My database needed no changes although I did have to create some maintenance and backup scripts for the new database host. Add in some testing time and that was all the effort it took.
The following are the service providers I chose. In each case, the vendor offers a free plan that provides decent capacity and also offers a series of reasonably-priced paid plans to scale up when the need arises. I already have other systems on these providers and I am happy with them.
There is one bright spot with these changes: because the Parse server is now open source, I can much more easily extend the services of the RESTful server and provide additional functionality when I need it. I still love the ease with which I create a system using the Parse platform — see this post for details — and I love all the features the Parse platform gives me out of the box and the ability to use Cloud Code for simple server-side code. However, one concern I always had with a Parse-based solution was that Parse’s Cloud Code could only go so far, so while it was fine for smaller or simpler systems, Parse never seemed like a good option for larger or more complex projects. With these changes, I now have full access to a real Node.js server while still being able to use the Parse “wrapper”, thus giving me the power to quickly start with a simple, “2-tier-like” system but easily grow into a more powerful system as necessary. If Cloud Code alone is not sufficient, I can now create standard RESTful services using normal Node.js code, and thus have infinite capability.
I’m still not thrilled with Parse.com shutting down — we are losing a nice, effortless, single-vendor solution and replacing it with the need to juggle multiple services and service providers — but perhaps the longer-term benefits outweigh the losses. Perhaps this is now the best of both worlds: we can start a system quickly and simply, but have no real limits on where and how far that system can grow.
Parse.com may be dead, but long live Parse Server!
So you just downloaded someone’s code sample from GitHub, loaded it into Xamarin Studio on your Mac, started to build the app for the iOS Simulator … and promptly got smacked by the big red error message saying “Error: No installed provisioning profiles match the installed iOS code signing keys”. Fear not — the error message is wrong. You aren’t missing a provisioning profile. Provisioning profiles are only needed when building for an actual physical device — they aren’t needed for running iOS apps on the Simulator.
Using Parse.com allows me tremendous simplicity when writing mobile apps: it lets me focus on just writing the mobile code and the database, but lets me use an N-tier deployment model and a remote NoSQL database. However, there are times when I really want to run a tiny piece of code inside the database — the same way I would use stored procedures or triggers in a relational database — or inside the REST server as I would normally do with server-side business logic.
For example, one of my mobile apps (PatchTrader) enables Scouts to more easily trade patches at large Scouting events. In this app, whenever a Scout “checks-in” at a new location, any of their older check-ins should be marked as expired in the remote database. I could have the mobile app save the new check-in to the remote database, then retrieve any old check-ins for that user and reach back to the server to expire each one, but this is a terrible use of mobile bandwidth and battery life. It also very fragile. PatchTrader is used at campsites with bad cell service, so it is very possible that the app will be unable to successfully complete all that work, thus leaving old check-ins still showing as “active” in the database. In an ideal world, I’d want a database trigger to fire on the first update and mark the other rows as expired, or I’d have my “check-in” RESTful service handle this … but I didn’t build a REST server and I’m not on a relational database.
Enter Parse’s “cloud code” — it fills that need nicely, and once again saves me from having to write a full server application when I just need one little bit of server-side code.
Parse’s “cloud code” allows you to run custom JavaScript inside the Parse server rather than in your client app, but still without requiring you to build a real REST server. You can use that cloud code to do things such as providing custom server-side logic, doing more efficient database processing or specialized counts, sending push notifications, and most importantly in my “PatchTrader” case, it provides hooks for code that can be run before or after a database object is saved or deleted in the MongoDB database. Pseudo-triggers on MongoDB!
Admittedly these are not real triggers but instead merely server-side JavaScript that is called by Parse’s underlying Node.js engine, but they feel like database triggers so calling them triggers better fits my mental model. And while one could argue that database triggers are evil because they hide business logic inside the database rather than keeping it visible in the server-side code, my DBA hat would reply that there are valid cases for triggers. Then my developer hat would chime in and explain that in this case, PatchTrader is a free app with a very limited audience that I’m doing in my spare time and it is tracking nothing more serious than map check-ins while trading patches, and my time would be better spent enhancing the app rather than building a REST server for it, so the trade-off is acceptable.
To show a simple cloud code example, this is the “after save” code that gets fired off by the server whenever a new check-in is saved by a PatchTrader user:
Parse.Cloud.afterSave("Checkin", function(request) { // Skip the update if we are being updated by server-side code // (i.e.: if this afterSave call is being cascaded from a previous afterSave call) if (request.master) { console.log("Cascading afterSave ignored on ID: " + request.object.id); return; } // mark any other "active" checkins for this user as "inactive" query = new Parse.Query("Checkin") .equalTo("user", request.user) .notEqualTo("objectId", request.object.id) .notEqualTo("isActiveCheckin", false); query.find( { success: function(results) { console.log("Updating " + results.length + " items..."); for (var i = 0; i < results.length; i++) { var checkin = results[i]; console.log(" Updating ID: " + checkin.id); checkin.set("isActiveCheckin", false); } Parse.Object.saveAll(results, {useMasterKey: true}); }, error: function(error) { console.error("Error setting items to 'inactive'." + " Error: " + error.code + " : " + error.message); } }); });
As you can see, it’s very simple and it gets the job done without adding any extra burden to the mobile app or mobile bandwidth, and it prevents bad data from gathering in the database.
It’s very handy, when used appropriately. If you’re a Parse.com developer and you haven’t played with Cloud Code, I urge you to take a look!