The MVP Challenge - From 0 to MVP in 100 days: Using Expo

I want to make a software product, so back in May 2017, I decided I was gonna make a React Native App. Here are all the things I learned and, roughly, the workflows I use to make an app quickly. NB that it's barely an article, more of a summary for myself, decision and workflow-wise.

This article is part of a series on building an MVP of a Data-driven cross-platform app with the following stack: React Native, Apollo GraphQL, and on the backend Node JS with Express and a MySQL Database.

Coding style decisions:

I decided I was gonna code this way. I could also have chosen the more professional and more common approach used in the industry, but for a one-man-band, this is not necessary, in my opinion. Therefore I choose a style that makes developing quickly easy. Because for an MVP, you need to be quick, especially when bootstrapping!

  • Keep steps in this document and actual code very much aligned for better flow and not having to switch back and forth between functions, files, etc.
  • Sketch broad plan first, then fill in the blanks
  • Prioritise a small & stable codebase with lots of powerful functionality —> RN, Expo, Apollo
  • Boilerplate first for productivity, assuming I can need everything already the first day.
  • Flatten out file structure because it results in quicker building, easier overview… only create more files if they really feel too big and if you start getting redundant. I don't wanna waste time on imports and exports and finding where I put the code.
  • Heavily comment the code when doing a tutorial. First always sketch what I’m gonna code in the comments in the main file, and slowly split it up in other files.
  • Always stay in the editor. If I write notes in word, it will be a bigger threshold to go back to some psuedo-code or real code because word is not made for that.
  • Use flow or typescript, especially during the tutorial, but also for better understanding the code myself.
  • I like to always have a reason for doing something. Even for refactoring. So first start with an index and don’t use includes. Just do everything in one file. Then, when it gets too complex, or when I have to request the same thing twice, divide it up into multiple files. To summarise: show the refactoring and why. It’s important to show this process.
  • A terminal in the editor too
  • Shortcuts to the max
  • Measurement is WakaTime and Rescuetime
  • git init server and client separately. Git push every step. This makes it way easier to start somewhere in the middle any day by git clone & git checkout. However, always keep in mind that starting completely from scratch is better if I want to keep using the newest versions

Architecture and stack decisions:

There were some though choices. First of all I decided I wanted to go for Javascript 100% to keep the learning curve as small as possible. But then there ended up to be many many different libraries within Javascript! I won't go into detail of my choice for React Native and Node + Express and GraphQL. But there were some though choices I made.

  • MySQL or SQLite? SQLite just works. Simple. Efficient. I can create multiple files per game to make them work independently if one becomes corrupt. For example, when the chat gets corrupt it can easily create a new one. When users get corrupt the chat still could work. MySQL requires some more setup, but according to a later in-depth performance experiment, it turned out that MySQL can be a lot more performant on a higher scale. Therefore, I now decided to include MySQL into my codebase.

Work Ethic

It's very important to have good work ethic. If you are too chaotic, it's hard to steer your direction. These are some of my habits:

  • Before starting, write the day down on notepad so I can close my laptop & think! It's easy to get distracted if you don't know what you're doing. Prevent this by closing your laptop when you loose momentum.
  • When scripting, use local environment & don’t check the remote environment all the time. Big pitfall! It takes a lot of extra time especially if you're debugging and doing trial and error fixing.
  • Focus on creating functionality & seek reward by seeing good use & smiling faces at the end of the day.
  • Keep finding ways to simplify code while keeping functionality and learn new useful things (see sidesteps).

Practice the Cycle of persistent learning, every day:

  1. Learn something new
  2. Apply it multiple times while minimizing overhead of having to create other things that I already know first
  3. Insert it into the flow of 0 to MVP

Cycle of actionable planning & keeping plans in alignment with results:

  1. Create plan of execution on a notepad: actionable to-do list that can be accomplished today
  2. Take it up, put my mind to it, open laptop, start focused on this plan
  3. Close when done or consciously distracted
  4. Feel proud or change plan

Habit of sharing what I learn

In october until december 2017 I took time-lapses or screenshots as social proof. If I am confident enough, I can create a course and sell it on some platform. But for now, I uploaded everything to YouTube to prove that I did a lot of work (and maybe to help some people too). In the end it gave me a few dozen subscribers, so some people must've learned something.

This is what I wanted to show in the average video. NB: Not every video ended up to be that way! Making videos is quite hard!

  • Pick a piece and write a short plan. [Talk about it.]
  • Start with pomodoro & music, and the first point of the plan
  • If I exactly know what to do, film it.
  • Write down solutions after long research in comments
  • Keep status in sticky note on screen all times
  • After I figured out what I need to know, summarize it in the comments
  • After I figured out the bug, summarize the error, the process, the bug, and the fix in the comments
  • Speak my mind
  • After every pomodoro is finished speak about the progress

- Invite to do the challenge with me (using same techniques): minimum one hour a day & film the process - Give reason for that - Create a list of people doing the challenge with me in the same languages.

This is what I did and posted on my Youtube Channel. It ended up to be great for social proof and social accountability, so I certainly recommend it. You can see 46 videos about this on my youtube channel! I don't recommend watching it all, but there actually is some useful stuff in there. I wish there was an easy way to edit and distill the videos to more time efficient ones.

The Workflow

Challenge 0 = Project definition

The CS Way:
1. Requirements
2. Possible techniques
3. Design (structure, techniques)

Challenge I: Setup server

1) add name servers of preferred domain pointing to cloudflare (dana&
2) setup CloudFlare DNS
- Point CNAME record www and @ to - Point A record to server IP - Crypto —> Origin certificate, save these values!

3) use any static website project but probably the React Bootstrap App theme that I modified, build it, and upload it using “surge ./build/”

4) setup a server with Ubuntu 16.04 and Nginx that has this in /etc/nginx/sites-enabled/default

server { listen 80;
listen 443 ssl;
ssl_certificate /ssl/cert.pem;
ssl\_certificate\_key /ssl/key.key;
access_log /var/log/nginx/nginx.vhost.access.log;
error_log /var/log/nginx/nginx.vhost.error.log;
location /appname {
proxy_pass http://localhost:3456/graphql; } }

5) Make sure the process indeed runs on this location and port using pm2
6) For more info see notepad

Challenge II: Expo Setup

Challenge III: Creating UI
Currently, my UI will consist of screens and components. Repeatedly iterate between these things.

  1. Create overview and decide which external components to use
  2. Create screens & components using docs, memory and hot-reloading & chitshit

- It seems that hot reloading is a little bit buggy. It doesn't always refresh. Why? Pay attention - “[exp] [React Transform HMR] Patching HomeScreen” appears in console, but it doesn't refresh the app in the simulator - React native debugger works & simulator works, but the remote RNDebugger doesn't work with hot reloading. If I need hot reloading (useful for UI), use ‘exp start’ (normal debugger). If I need the Remote RNDebugger, use live reloading.


No styled components. I decided to work without styled-components because it is an abstraction and hides real function too much and it is not supported well enough by all kinds of things. It changes the code a lot but it isn’t the most reliable thing. Things can easily break with it.

Jest - read up on documentation and some medium articles like this one
- try snapshot testing - I may not need this at all. It is a huge burden to have to write tests all the time, so I don’t see the reason yet. If I go into production I might start to see a reason for it, but if I type everything strongly too, it won’t break any time soon! - it’s not certain if I want to include them by default because it increases boilerplate a lot. It’s probably not necessary for BETA, but it probably is for production.

Typescript: - try to use it for now, but if it seems that it takes longer and doesn’t help much, revert back to normal JS

Babel & prettier: - The way I do it now seems to work correctly - Previously had a problem of conflicting rules and it didn’t work well with styled components - Create a habit of setting it up in the project seperately every time (except for VSCode plugin settings) - Put as much as possible everything in package.json, not in separate files

Intellisense - Use this as much as possible because the autocomplete and type introspection gives me less reason to go to docs!

Dependencies - use react-native, react and expo as much as possible! - Use as little other dependencies as possible!

Challenge IV: Component Data Population

  1. Populate UI/UX with Apollo Data:
  2. Populate UI/UX with Real Mutations
  3. Populate UI/UX with Redux Store
  4. Make sure to be smart about sending functions to components and reuse the declarations

Challenge V. Add permissions & sensors

Every app needs a lot of permissions. Expo does this automatically, so no need to worry if you use that. Sometimes you need some certificates, but the documentation is almost always excellent in my experience.

Challenge VI: Alpha Testing with Expo App & friends
Exp publish & open on android + iPhone

Make & Fix Often-Made Mistakes:

Challenge VII: Beta Testing with Standalone App & ideal customer

Based on and my own findings (23 October 2017).

Step 1. Initial build for getting credentials:

- create android project in google play console

- Add reverse DNS value (com.progenworks.appslug) to ios.bundleIdentifier and android.package - iOS: App Icon 1024 x 1024 non-transparent —> put in assets/icon.png - Don’t forget name, description, slug, splash - Add notification settings:

"notification": {
  "icon": "./assets/notifications_icon.png",
  "color": "#000000",
  "androidMode": "collapse",
  "androidCollapsedTitle": "#{unread_notifications} nieuwe meldingen"

exp start —> exp build:android —> wait 2-5 minutes —> exp url:apk

exp start —> exp build:ios —> wait 2-5 minutes —> exp url:ipa

NB: since exp v50 you can automate this with a script because it will wait until the build is finished. use something like this to download the file from the URL you get from exp url:ipa/apk: P.s. I haven't tested this yet! Let me know if it works.
standalonedir="/Users/progenworks/2018 code/Communify/standalone/" && exp start && exp build:ios && urlios = "exp url:ipa" && wget -O $standalonedir "$urlios" && exp build:android && urlandroid = "exp url:apk" && wget -O $standalonedir "$urlandroid"

NB: Don’t put files in expo folder, not even under assets, or build will fail!

NB: I let expo handle certificates for the time being, but it's questionable whether this a good idea when your app starts to make money, because they kind of own the app, right? It saves a lot of time though, but I become completely dependent on their online services because I can’t update the app version without a certificate.
Also, once you want more functionality in your app like payments, you will have to detach, so then you can't let expo do the certificates anymore. You'll have to do it yourself!

More Info here and here

Todo before uploading build:

Make sure to go through these steps. Every time you forget something, you'll end up having to rebuild and wait so long that your teeth fall out.

  • Android: up the version number
  • iOS: up the version number
  • icon without tranparency and without alpha channels (use alpha-channel-remover to remove alpha-channels from png)

Install Google:

Install Facebook:

Then build again -_-

NB: This is what I did in november 2017. But there are other ways that are more eficient to do Facebook and Google login.


Insert package names into review variables in import.
Change credentials in constants (import.C) for google oAuth and stuff like that

Fill in store listing with descriptions and assets:
Create screenshots of app from android simulator and iOS simulator (And tablets both platforms optionally)
Hi-res icon 512 x 512 32-bit PNG (with alpha)
Feature graphic 1024 w x 500 h JPG or 24-bit PNG (no alpha)
Privacy policy: or better

  1. Make sure to set the right permissions under the android key! Otherwise expo will define defaults which are a lot of permissions.

Upload failed

Your APK's package name must be in the following format "com.example.myapp". It may contain letters (a-z), numbers and underscores (_). It must start with a lowercase character. It must be 150 characters or fewer. <——— It’s not possible to call it com.progenworks.10g. It should start with a lowercase character, so probably com.progenworks.app10g would be ok.

- Configure app.json more, depending on what you need. This is also for permissions etc. See - in RN to keep statusbar text color the same as in expo on iOS (iOS standalone has different default than Expo)

What now?

Drag and drop the .apk into your Android emulator to see if the build was successful.

To run it on your Android device, make sure you have the Android platform tools installed along with adb, then just run adb install app-filename.apk with your device plugged in.

To run it on your iOS Simulator, first build your expo project with the simulator flag by running exp build:ios -t simulator, then download the tarball with the link given upon completion when running exp build:status. Unpack the tar.gz by running tar -xvzf your-app.tar.gz. Then you can run it by starting an iOS Simulator instance, then running xcrun simctl install booted and xcrun simctl launch booted . Another alternative which some people prefer is to install the ios-sim tool and then use ios-sim launch .

  1. Android Developer Console to upload APK to Android to BETA test it

  1. TestFlight to test app for iOS
  2. Add new app in iTunes connect
  3. xCode —> dev tools —> application loader —> select & upload IPA —> Wait 15 minutes

Check this on the Apple submission form because of segment
1. “Attribute this app installation to a previously served advertisement” 2. “Attribute an action taken within this app to a previously served advertisement” 3. “I, YOUR_NAME, confirm that this app, and any third party…”

Fill in everything in iTunes Connect and wait 1-2 days for manual review.

Make sure to add login credentials! Create some fake google or facebook account and provide these as login credentials (or create an account on your platform for them if you also support normal sign up)

  1. Updates?
    There are only a couple reasons why you might want to rebuild and resubmit the native binaries:

    If you want to change native metadata like the app’s name or icon.
    If you upgrade to a newer sdkVersion of your app (new React Native version, which requires new native code)

    If you do this, also update the binary’s versionCode and buildNumber in app.json

Good to know: Note: Updates are handled differently on iOS and Android. On Android, updates are downloaded in the background. This means that the first time a user opens your app after an update they will get the old version while the new version is downloaded in the background. The second time they open the app they’ll get the new version. On iOS, updates are downloaded synchronously, so users will get the new version the first time they open your app after an update.

- How to turn off dev mode? Or is it already off? Production optimisations react native apps should be checked - app size: can I make it smaller? - permissions: can I change them to necessary only?

:Epic Fails:

ERROR ITMS-4238: "Redundant Binary Upload. There already exists a binary upload with build version '1' for train '2'" at SoftwareAssets/PreReleaseSoftwareAsset

Challenge VIII: Web stuff as funnel to app (Landing page + Blog + FB + Youtube + React Native Web?)

Create as many secure blog sites as you want for 5$ a month total using Ghost CMS
- Why Linode, NGinx and Ghost? - Setup a Linode server with Nginx and Node JS - Point a domain at the Linode server - Install Ghost using ghost-cli on the server using Nginx and by specifying the port - Installing SSL on a domain. Understanding NGinx, DNS and SSL - Install ghost locally in development mode - Go editing a theme and test by running locally - Setup newsletter using MailChimp - Start blogging and cross publish on sites like Medium and LinkedIn - Finish it up, summarise & show result

Challenge IX: Share

The most important haha.
ProductHunt, relevant communities, news sites, people, friends, etc…
See what @levelsio has to say about this! He recently created a book Make.

Challenge X: Profit, invest, automate, repeat

Inner cycle: Learn —> Improve core product + Actionable plans ——> Improve core product
Outer cycle: Network, Share, Teach & Sell ——> Find collaboration ——> Create prototype & Beta ——> Test product market fit ———> if yes, finalise into monetizable production-ready MVP ———> Automate & Move on ———> Network, Share, Teach & Sell

The Inner cycle is a daily thing. I repeat this every day and don’t have to plan ahead much.
The outer cycle is a bi-weekly thing. There will be events and I can organise meetings & classes to grow my network. This is my social time so it shouldn’t interrupt work. Then I create a prototype & beta by transforming my core product. This can be done within a week. I also need a week for more general purpose learning, improving and maintaining. That makes it two weeks for a beta. The testing takes some waiting, so in the testing phase the product is on hold. There can be small improvements I have to make. After it is thought to have reached PMF, I kind of enter the second phase: make it an production ready MVP, automate all workflows, and move on. This may take another two weeks or so. This means that I’m able to create a startup in a month. It is very important for apps to get traction. I have a system for that of some key elements that always have to be there. Most of them are automatically present by app design.. Sometimes I need good partnerships… If they don’t get traction they fail because I move on.