Scalable Cloud Apps That Won't Keep You Up At Night

Post on 10-May-2015

1.577 views 8 download

Tags:

description

Most applications writing for mobile platforms need some sort of integration with web services. Unfortunately, most times backend infrastructure becomes an oversight and the app ends up suffering in the long run. Using cloud infrastructure technologies like Parse can help you get from concept to App Store insertion in no time. Parse's simple API, extendable Cloud Code feature and Push notification API let you focus on your app while getting a scalable backend solution.

Transcript of Scalable Cloud Apps That Won't Keep You Up At Night

Scalable Cloud Apps That Won't Keep You Up At

Night

Aaron Douglas @astralbodies Twitter/ADN

Red Arrow Labs - Milwaukee, WI

Friday, March 8, 13

So you have an app (or an idea)

Friday, March 8, 13

You want people to download and use it.

Friday, March 8, 13

Most apps need to integrate with

something.

Friday, March 8, 13

Because integration (collaboration) is

interesting

Friday, March 8, 13

Interesting apps = MOAR MONEY

Friday, March 8, 13

Why should I use the “Cloud”?

Friday, March 8, 13

Scalability & Infrastructure

Friday, March 8, 13

Cross Platform

Friday, March 8, 13

Our App Idea

Friday, March 8, 13

• Conference App

• Speakers

• Sessions

• Map

• Comments & Notes

• Photos

Friday, March 8, 13

• Still a hot mess with Core Data

• iOS and Mac only

• Hard to debug

Why not iCloud?

Friday, March 8, 13

Options

Friday, March 8, 13

We’re Going to Use Parse

Friday, March 8, 13

What Parse Provides

• Data storage - RESTful API & Native SDKs

• Queries

• ACLs / Users

• Cloud Code & Push Notifications

• File Storage

• In-App Purchases

• GeoPoints & Spatial Queries

Friday, March 8, 13

Friday, March 8, 13

$ vi Podfilepod 'Parse'

$ pod install

Add To Your Project

Friday, March 8, 13

Friday, March 8, 13

Friday, March 8, 13

AppDelegate.m

#import <Parse/Parse.h>

...

[Parse setApplicationId:@"3lZSGBNTs03wQigx2apDHwUv6ZczMVaIib8nUz" clientKey:@"rstZrElVxBiB5tzsWn10QK9AfrRR0GkQQj16Hj"];

Friday, March 8, 13

Objects

• Session

• Schedule

• Speaker

• Attendee Notes

• Attendee Schedule

• ... and on and on

Friday, March 8, 13

PFObject

• Key-Value pairs

• Schema-less

• JSON data types: NSString, NSNumber, NSDate, NSData, NSArray, NSDictionary

• Associations - 1:1, 1:N, N:N

• objectId, updatedAt, createdAt

Friday, March 8, 13

PFObject

PFObject *speaker = [PFObject objectWithClassName:@"Speaker"]; [speaker setObject:@"Marty" forKey:@"firstName"]; [speaker setObject:@"McFly" forKey:@"lastName"]; [speaker setObject:@"Hill Valley, CA" forKey:@"location"]; NSLog(@"Object ID before save: %@", speaker.objectId); [speaker save]; // MAGIC HAPPENS HERE NSLog(@"Object ID after save: %@", speaker.objectId);

2013-03-03 16:19:08.923 CocoaConfParse[4803:c07] Object ID before save: (null)2013-03-03 16:19:09.468 CocoaConfParse[4803:c07] Object ID after save: 6iXsTrvWd0

Friday, March 8, 13

Back on Parse.com...

Friday, March 8, 13

Refresh

[speaker refresh];

[speaker refresh:&error];

[speaker refreshInBackgroundWithBlock:^(PFObject *object, NSError *error) { // Code}];

Friday, March 8, 13

Removing Data

[speaker removeObjectForKey:@"favoriteStarWarsCharacter"]; [speaker deleteInBackground];

Friday, March 8, 13

Relationships

PFObject *session = [PFObject objectWithoutDataWithClassName:@"Session" objectId:@"6iXsTrvWd0"];

[sessionComment setObject:session forKey:@"session"];

PFObject *session = [sessionComment objectForKey:@"session"];

[session fetchIfNeededInBackgroundWithBlock:^(PFObject *object, NSError *error) { NSString *title = [post objectForKey:@"title"];}];

Friday, March 8, 13

Query by ID

PFQuery *query = [PFQuery queryWithClassName:@"Speaker"]; PFObject *object = [query getObjectWithId:@"jFgtbb2aCb"]; NSLog(@"Name: %@ %@", object[@"firstName"], object[@"lastName"]);

2013-03-03 17:08:52.484 CocoaConfParse[6892:c07] Name: Marty McFly

Friday, March 8, 13

Querying PFQuery *query = [PFQuery queryWithClassName:@"Speaker"]; [query whereKey:@"lastName" equalTo:@"McFly"]; query.cachePolicy = kPFCachePolicyNetworkElseCache; PFObject *object = [query getFirstObject]; NSLog(@"Name: %@ %@", object[@"firstName"], object[@"lastName"]);

2013-03-03 17:08:52.484 CocoaConfParse[6892:c07] Name: Marty McFly

Friday, March 8, 13

Queries

• NSPredicate

• 1000 records max (100 default)

• Relational queries

• Cache policies

Friday, March 8, 13

Asynchronous

PFObject *speaker = ...;

[speaker save]; [speaker saveEventually]; [speaker saveInBackground];

[speaker saveInBackgroundWithBlock: ^(BOOL succeeded, NSError *error){}];

Friday, March 8, 13

Users[PFUser enableAutomaticUser]; PFUser *currentUser = [PFUser currentUser];[currentUser setObject:[NSDate date] forKey:@"lastLaunched"];[currentUser saveInBackground];

PFUser *user = [PFUser user];user.username = @"martymcfly";user.password = @"awesomesauce";[user signUpInBackgroundWithBlock:^(BOOL succeeded, NSError *error) {

}]; [PFUser logInWithUsernameInBackground:@"martymcfly" password:@"awesomesauce" block:^(PFUser *user, NSError *error) {

}];

Friday, March 8, 13

ACLs

PFObject *feedback = [PFObject objectWithClassName:@"SessionFeedback"]; [feedback setObject:@"I enjoyed it." forKey:@"comment"];

feedback.ACL = [PFACL ACLWithUser:[PFUser currentUser]];

[feedback saveInBackground];

Friday, March 8, 13

Built-In Views

Friday, March 8, 13

App Structure

• Where does Parse start & end?

• Service Layers

• Parse everywhere

Friday, March 8, 13

Data Transfer Objects

• Map PFObject to some object in your code

• Parse is contract/schema-free

Friday, March 8, 13

Push Notifications

• Still requires APN setup

• Simplifies addressing & registration

• Cross platform (Android & iOS)

Friday, March 8, 13

- (void)application:(UIApplication *)applicationdidRegisterForRemoteNotificationsWithDeviceToken:(NSData *)deviceToken{ // Store the deviceToken in the current // Installation and save it to Parse. PFInstallation *currentInstallation = [PFInstallation currentInstallation];

[currentInstallation setDeviceTokenFromData:deviceToken]; [currentInstallation saveInBackground];}

Push Registration

Friday, March 8, 13

Channels

PFInstallation *currentInstallation = [PFInstallation currentInstallation]; [currentInstallation addUniqueObject:@"Speakers" forKey:@"channels"]; [currentInstallation saveInBackground];

PFPush *push = [[PFPush alloc] init]; [push setChannel:@"Speakers"]; [push setMessage:@"Thanks for all the fish!"]; [push sendPushInBackground];

Friday, March 8, 13

In-App Purchases

• Wraps StoreKit

• Receipt verification

• Asset download

• PFProductTableViewController

Friday, March 8, 13

What about server-side calls?

Friday, March 8, 13

• Create new speakers & sessions

• Attendees register preferences

• Push notifications when session changes

• Welcome emails

Friday, March 8, 13

Cloud Code lets you deploy server-side code

Friday, March 8, 13

Cloud Code

• RESTful API

• JavaScript Language

• Triggers & Validation

• Modules

Friday, March 8, 13

$ curl -s https://www.parse.com/downloads/cloud_code/installer.sh | sudo /bin/bash

$ parse new CocoaConfCloudCodeEmail: astralbodies@gmail.comPassword:1:CocoaConfSelect an App:1

$ cd CocoaConfCloudCode

Installing the CL Tool

Friday, March 8, 13

Parse.Cloud.define("numberOfSpeakers", function(request, response) {  var query = new Parse.Query("Speaker");  query.find({    success: function(results) {      response.success(results.count);    },    error: function() {      response.error("Speaker lookup failed");    }  });});

$ vi cloud/sessions.js

Friday, March 8, 13

$ parse deploy$ curl -X POST \  -H "X-Parse-Application-Id: MN28ox..." \  -H "X-Parse-REST-API-Key: RItKo..." \  -H "Content-Type: application/json" \  -d '{}' \  https://api.parse.com/1/functions/numberOfSpeakers

{  "result": 1}

Friday, March 8, 13

Friday, March 8, 13

Modules

Friday, March 8, 13

Cloud Code

• Still in its infancy

• No scheduled events

• Take a look at iron.io

Friday, March 8, 13

Cost

• Free (1 million API requests / Pushes / 1GB)

• $199/month (15mil / 5mil / 10GB)

• Enterprise >$199

Friday, March 8, 13

Portability

• Import

• Export

• Service layer to abstract

• Never really want to lock into a technology

Friday, March 8, 13

Code

Friday, March 8, 13

Questions?

Friday, March 8, 13