bootstrapping an app for launch

Post on 14-Apr-2017

164 Views

Category:

Software

1 Downloads

Preview:

Click to see full reader

TRANSCRIPT

Bootstrapping an App for LaunchA rapid, low-cost, server-less approach to app development

@craigpharessixoverground.com

dropdrop.it/

Developer

There’s never been a better time to be a developer

Series1

Number of apps Barrier to entry

App store markets are over-saturated

There are over 2.2 million apps available for download on the Google Play Store

Statistahttp://www.statista.com/statistics/276623/number-of-apps-available-in-leading-app-stores/

Just building a great product isn’t enough

Less than 0.01 percent of consumer mobile apps are considered a financial success

Gartnerhttp://www.gartner.com/newsroom/id/2648515

Doing what someone else already knows how to do takes the world from 1 to n, adding more of something familiar. But when you do something new, you go from 0 to 1.”- Peter Thiel

Apps need to stand out

65.5% of smartphone users download zero apps per month

Quartzhttp://qz.com/253618/most-smartphone-users-download-zero-apps-per-month/

After launch,It can take years to reach product/market fit

Product/market fit means being in a good market with a product that can satisfy that market.”- Marc Andreessen

Prepare to pivot

Successful Tech Pivots• Pinterest was a mobile shopping app called Tote for 1 year• Twitter was a side-project of the podcast directory Odeo• Instagram began as Burbn, a check-in app with gaming

elements from Mafia Wars - and a photo feature• Android was an operating system for cameras in the 2

years before it was acquired by Google

Monthly overhead

55% of companies will increase their content marketing budget this year

Content Marketing Institutehttp://contentmarketinginstitute.com/wp-content/uploads/2014/10/2015_B2B_Research.pdf

Apps are expensiveto make

How much does it cost to build an app?• Big shops: $500,000 to $1,000,000• Average shops: $150,000 to $450,000

• Small shops: $50,000 to $100,000

Savvy Appshttp://savvyapps.com/blog/how-much-does-app-cost-massive-review-pricing-budget-considerations

How much does it cost to build an app (cont.)?• Zero-frills: $9,900• Full-featured: $50,100

Crewhttp://howmuchtomakeanapp.com

How much does it cost to build an app (cont.)?

$10,000 to $1,000,000

Talent

DesignerGraphic Designer

$51,360/year = $25/hour

Glassdoorhttps://www.glassdoor.com/Salaries/graphic-designer-salary-SRCH_KO0,16.htm

Back-end engineerRuby on Rails Developer

$93,906/year = $50/hour

Glassdoorhttps://www.glassdoor.com/Salaries/ruby-on-rails-developer-salary-SRCH_KO0,23.htm

Front-end developerAndroid Developer

$84,562/year = $50/hour

Glassdoorhttps://www.glassdoor.com/Salaries/android-developer-salary-SRCH_KO0,17.htm

Project managerSoftware Project Manager

$108,659/year = $50/hour

Glassdoorhttps://www.glassdoor.com/Salaries/software-project-manager-salary-SRCH_KO0,24.htm

Server costs

Infrastructure as a Service• Approximately $60/month for:• Small EC2 instance• S3 bucket• CloudFront CDN

• $50/hour for maintenance

AWS

Amazon Web Serviceshttps://calculator.s3.amazonaws.com/index.html

Platform as a Service• Approximately $125/month for:• Standard Plan with 3-1x dynos• Production database• SSL Endpoint• Web sockets push add-on

Heroku

Heroku Pricinghttps://www.heroku.com/pricing

So… how much?

Example app• Social login• User profiles• Friendships• User-generated

content

• Push notifications• Geolocation• Analytics

Estimate• Design: $25/h x 100 h = $2,500• Back-end: $50/h x 200 h = $10,000• Front-end: $50/h x 200 h = $10,000• Project management: $50/h x 50 h = $2,500• Total: $25,000

Design

Front-endBack-end

PM

ServerBreakdown

Design

Front-endBack-end

PM

ServerPotential Savings

Imagine if we could cut out the back-end

Imagine if we could focus on making the app awesome

Imagine if our overhead was zero,and we could scale as needed

Here’s how we get there

What we often do

Untitled 1

Untitled 2

Untitled 3

Budget spent MAU / Revenue

Launch

What we should do

Untitled 1

Budget spent MAU / Revenue

Launch

MVP(Minimum Viable Product)

Ideas

CodeData

Learn Build

Measure

theleanstartup.com

Back-end as a Service

Server-less is at its most simple an outsourcing solution

Authentication Service

Traditional client/server architecture

Client(s) (app)

Authentication Service

API Gateway

Database

Server Application

Push Notification Service

File StorageSolution

Analytics

Authentication Service

Server-less architecture

Client(s) (app)

Authentication Service

API Gateway

Database

Server Application

Push Notification Service

File StorageSolution

Analytics

Authentication ServiceAnalytics Database

But… why?

Benefits• Reduced operational cost• Reduced development cost• Reduced scaling costs• Reduced operational management• Reduced time to market

Drawbacks• Vendor control• Vendor commitment• Security concerns• Repetition of logic across clients• Loss of server optimizations

Okay, great.

Back-end servicesWith free tiers

File storage

Cloudinary Filestack

Analytics

Flurry

Localytics

Segment

Fabric

Real-time Push /Push notifications

Urban Airship

OneSignal

PubNub

Mobile BaaS (MBaaS)Back-end as a service, built specifically for mobile apps

ParseSunset by Facebook

Host your own from the GitHub repo:https://github.com/ParsePlatform/parse-server

KinveyAuthorizationData storageFile storage with CDNPush/SMSAnalytics

AWS Mobile ServicesAuthenticationData storageCloud logicNoSQL databaseAnalyticsPush notifications

FirebaseRecently overhauled by Google

Realtime databaseAuthenticationPush notificationsFile storageRemote configAnalytics

Live codingLet’s build Instagram (Lite)

• Facebook loginPost photosNews feedCommentsLikesActivity feedFollow friendsPush notifications

Firebase

Bittypicgithub.com/sixoverground/bittypic-androidAn itty bitty photo sharing app

Create a project

The Firebase console

Add the SDKbuildscript { // ... dependencies { // ... classpath 'com.google.gms:google-services:3.0.0' }}

build.gradle

Add the SDK (cont.)apply plugin: 'com.android.application'android { // ...}dependencies { // ... compile 'com.google.firebase:firebase-core:9.2.1'}// ADD THIS AT THE BOTTOMapply plugin: 'com.google.gms.google-services'

Available libraries

AnalyticsRealtime DatabaseStorageCrash ReportingAuthenticationCloud Messaging / NotificationsRemote ConfigInvites / Dynamic LinksAdMobApp Indexing

app/build.gradle

The data model

User Photo Activity• facebookId• email• displayName• profilePictureUrl• pushToken

• photoUrl• user

• owner• recipient• key• text• photo

Enable Facebook login

Authenticate with Facebook// Initialize Facebook Login buttonmCallbackManager = CallbackManager.Factory.create();LoginButton loginButton = (LoginButton) findViewById(R.id.button_facebook_login);loginButton.setReadPermissions("email", "public_profile");loginButton.registerCallback(mCallbackManager, new FacebookCallback<LoginResult>() { @Override public void onSuccess(LoginResult loginResult) { Log.d(TAG, "facebook:onSuccess:" + loginResult); handleFacebookAccessToken(loginResult.getAccessToken()); }

@Override public void onCancel() { Log.d(TAG, "facebook:onCancel"); // ... }

@Override public void onError(FacebookException error) { Log.d(TAG, "facebook:onError", error); // ... }});

FacebookLoginActivity.java

Authenticate with Facebook (cont.)private void handleFacebookAccessToken(AccessToken token) { Log.d(TAG, "handleFacebookAccessToken:" + token);

AuthCredential credential = FacebookAuthProvider.getCredential(token.getToken()); mAuth.signInWithCredential(credential) .addOnCompleteListener(this, new OnCompleteListener<AuthResult>() { @Override public void onComplete(@NonNull Task<AuthResult> task) { Log.d(TAG, "signInWithCredential:onComplete:" + task.isSuccessful());

// If sign in fails, display a message to the user. If sign in succeeds // the auth state listener will be notified and logic to handle the // signed in user can be handled in the listener. if (!task.isSuccessful()) { Log.w(TAG, "signInWithCredential", task.getException()); Toast.makeText(FacebookLoginActivity.this, "Authentication failed.", Toast.LENGTH_SHORT).show(); } // ... } });}

FacebookLoginActivity.java

Authenticate with Firebaseprivate FirebaseAuth.AuthStateListener mAuthListener;

@Overrideprotected void onCreate(Bundle savedInstanceState) { mAuthListener = new FirebaseAuth.AuthStateListener() { @Override public void onAuthStateChanged(@NonNull FirebaseAuth firebaseAuth) { FirebaseUser user = firebaseAuth.getCurrentUser(); if (user != null) { // User is signed in Log.d(TAG, "onAuthStateChanged:signed_in:" + user.getUid()); } else { // User is signed out Log.d(TAG, "onAuthStateChanged:signed_out"); } } };}

FacebookLoginActivity.java

Write to your database// Write a user to the databaseFirebaseDatabase database = FirebaseDatabase.getInstance();DatabaseReference myRef = database.getReference("user");

myRef.setValue("Norm");

EditPhotoActivity.java

File Storage// Points to the root referencestorageRef = storage.getReferenceFromUrl("gs://<your-bucket-name>");

// Points to "images"imagesRef = storageRef.child("images");

// Points to "images/cat.jpg"// Note that you can use variables to create child valuesString fileName = "cat.jpg";catRef = imagesRef.child(fileName);

// File path is "images/cat.jpg"String path = catRef.getPath();

// File name is "cat.jpg"String name = catRef.getName();

// Points to "images"imagesRef = catRef.getParent();

EditPhotoActivity.java

Upload Files// Get the data from an ImageView as bytesimageView.setDrawingCacheEnabled(true);imageView.buildDrawingCache();Bitmap bitmap = imageView.getDrawingCache();ByteArrayOutputStream baos = new ByteArrayOutputStream();bitmap.compress(Bitmap.CompressFormat.JPEG, 100, baos);byte[] data = baos.toByteArray();

UploadTask uploadTask = photoRef.putBytes(data);uploadTask.addOnFailureListener(new OnFailureListener() { @Override public void onFailure(@NonNull Exception exception) { // Handle unsuccessful uploads }}).addOnSuccessListener(new OnSuccessListener<UploadTask.TaskSnapshot>() { @Override public void onSuccess(UploadTask.TaskSnapshot taskSnapshot) { // taskSnapshot.getMetadata() contains file metadata such as size, content-type, and download URL. Uri downloadUrl = taskSnapshot.getDownloadUrl(); }});

EditPhotoActivity.java

Read from your database// Read from the databasemyRef.addValueEventListener(new ValueEventListener() { @Override public void onDataChange(DataSnapshot dataSnapshot) { // This method is called once with the initial value and again // whenever data at this location is updated. String value = dataSnapshot.getValue(String.class); Log.d(TAG, "Value is: " + value); }

@Override public void onCancelled(DatabaseError error) { // Failed to read value Log.w(TAG, "Failed to read value.", error.toException()); }});

PhotoTimelineActivity.java

Monitor token generation@Overridepublic void onTokenRefresh() { // Get updated InstanceID token. String refreshedToken = FirebaseInstanceId.getInstance().getToken(); Log.d(TAG, "Refreshed token: " + refreshedToken);

// TODO: Implement this method to send any registration to your app's servers. sendRegistrationToServer(refreshedToken);}

AnDevConFirebaseInstanceIdService.java

Receive notifications@Overridepublic void onMessageReceived(RemoteMessage remoteMessage) { // TODO(developer): Handle FCM messages here. // If the application is in the foreground handle both data and notification messages here. // Also if you intend on generating your own notifications as a result of a received FCM // message, here is where that should be initiated. See sendNotification method below. Log.d(TAG, "From: " + remoteMessage.getFrom()); Log.d(TAG, "Notification Message Body: " + remoteMessage.getNotification().getBody());}

AnDevConFirebaseMessagingService.java

Send an upstream notificationFirebaseMessaging fm = FirebaseMessaging.getInstance();fm.send(new RemoteMessage.Builder(SENDER_ID + "@gcm.googleapis.com") .setMessageId(Integer.toString(msgId.incrementAndGet())) .addData("my_message", "Hello World") .addData("my_action","SAY_HELLO") .build());

AnDevConService.java

If using Firebase, sending notifications needs to be done from the server.

Launch party!

What we should do

Untitled 1

Budget spent MAU / Revenue

Launch

Create a Landing Page

Social Presence

Choose a launch date

thunderclap.it/

Test test test

Communities

slacklist.info/

/r/startups/r/sideproject/r/apps

news.ycombinator.com/

helpareporter.com/

SocialRank.com

uberhunters.com/

Let’s review• Cut-out over half the development budget with no back-end• Outsource any server effort with MBaaS• Spend less time programming the plumbing• Spend more time making the app stand out• On-board tons of beta testers prior to launch to receive critical feedback• Generate buzz leading up to launch through influencers and free services• Bring the app to market quickly• Keep overhead to zero until reaching product/market fit• Iterate - learn, tweak, build, test

Launch party!

@craigpharessixoverground.com

github.com/sixoverground/bittypic-android/

Thank you!

Bootstrapping an App for Launch

top related