#19 build an app from scratch
What do you do when you need to build an app and you don’t have the funds to hire a developer? You do it yourself!
This took me way longer than it would have done for an experienced developer, because I was trying every step for the first time, without a clear view of the steps to follow and how to complete them. Honestly, at first it was pretty painful. While there are a lot of tutorials online, I found most of these seemed to be missing one element or another, or weren’t specific enough for a total newbie like me. As a record of everything I learned I created the below checklist for anyone else starting this process for the very first time. The best tutorials I found were from Vadim at Not Just Dev, which I’d highly recommend if you’re also learning app development from scratch.
I had some pretty clear pre-requisites for this:
We wanted to use AWS as the backend, since that’s what Spotty’s ML is built in and where all our existing DBs were, and it would make it easier to manage all our cloud costs in one place
It needed to be mobile native because of the camera functionality, but easily transferred to the web as well for a desktop version (in a later release)
We both did some research and figured using AWS Amplify would be the easiest starting point; from there it became clear we’d also need to use React Native. I’m sure there are other ways we could have done this but this is attempt 1 for our MVP based on our limited front-end experience. We kept things fairly simple for now since our aim is to release as soon as possible to start getting user feedback.
Since Eddie is focused on the ML and backend functionality and I had already designed part of the front-end in Figma, it made most sense for me to try and kick off the build. It’s been a steep learning curve but with the help of YouTube tutorials and GenAI tools, we have now been able to build a first MVP in just a couple of months with zero front-end programming experience.
Set up
Install the tools you’ll need and set up environments (this took me 2 days and was probably the most confusing part)
N.B. make sure to refer to the package documentation for up to date information, as this information will inevitably change with new releases.
For React Native using Expo:
Open a new terminal window
Install Homebrew
Use Homebrew commands to install Node.js and Watchman
Use npm commands to install React Native CLI globally
For iOS, install XCode from the App Store and make sure this includes an emulator/simulator
Open XCode and navigate to settings > locations > set command line tools to the most recent version of XCode and make sure the file path is specified underneath
Run XCode/Simulator and make sure the simulator is using an up to date / the right device
For getting started, we used the Expo framework including Expo Go for initial rapid testing. However to run a development build you’ll also need cocoapods CLI. This should be installed the first time you run expo run:ios but may need some additional troubleshooting.
When you’re ready to run a development build using Expo, there may be some additional installs required e.g. the expo-dev-client to build on cloud.
For Android, install Android Studio
For AWS backend:
Set up AWS account & log in to the AWS management console (in browser)
Install & configure AWS Amplify CLI in the terminal
If you encounter EACCES issue, can resolve using sudo
Create a new React Native or Expo project (in terminal)
Run command in mac’s terminal to initialize a new app
Use cd to navigate to the directory where you want to create the new project, then run the init with your project/app name
You can init a new Expo project directly with npx create-expo-app, including using various templates to help get started
This should create a whole bunch of folders & files for the basic structure of the app (node modules, assets, config files, etc.)
Open your new project in your code editor of choice, e.g. VS Code
Follow the prompts to open up the file directory in VS Code
Begin working on the UI
Set up your folder and file structure within code editor
Delete node modules folder and package-lock.json file, then run npm install again to get latest versions of dependencies
Create a folder within the app folder structure in VS Code called ‘src’ or ‘source’ and subfolders within this for components, screens, and APIs
You can start with either front or back end depending on personal preference. I preferred to create the visual front end first, then link it to the backend. I found this easier for testing layout etc without having to manage the dependencies of backend providers.
Initialize AWS Amplify within the project (you can do this in mac’s terminal or within VS Code)
This will trigger various config questions incl. authentication method, region, etc.
I used AWS access keys, to do this go back to the AWS Console and navigate to the IAM service, select the relevant user (that you should have set up during the Amplify CLI installation) and create access keys for this user. You can download them as a CSV to use in future.
Once all config completed, this should trigger creation of additional folders in the directory
UX & Front-End Design
Define high-level features and flows/journeys
We knew the Spotty app needed to have a few key screens and front end features, and a few key integrations/backend features:
DB of aircraft types
API to fetch nearby aircraft when the camera is opened
DB of user data, incl. basic aircraft statistics (counts, sums, etc. to feed into leaderboard)
Functions to link these frontend queries with backend algorithms
It’s much quicker to define these and mock them up in a tool like Figma to provide direction when building, and you can use images/screenshots of the designs with code generation tools to accelerate the process.
Create front-end components in VS Code using React Native and Expo, incl. navigation, styling, and any static elements like headers
Break down the front end designs into the components that make them up (e.g. headers, posts, cards, that kind of thing)
Determine which components are repeated within or across screens
Start building custom components based on this breakdown
A component is simply a function which you define, which is built up into more complex components as the app grows
Start with small reusable components and build up complexity
I found it helpful to do front end functionality first to make sure it was working, then limited styling, then backend integration, then refine the front end styling
To accelerate this process, genAI tools like ChatGPT and Claude can draft the code for you, and even create code based on screenshots. However while this massively accelerates the development process (and learning!) you still need to understand the component structure to make sure all the files are set up and linked correctly
Navigation
Install Expo Router (I tried both React Navigation and Expo Router and found Expo Router much easier to work with as a newbie)
Set up the tabs you want as different files
Import styling e.g. Expo’s Google Fonts, icon libraries
This requires you to install your fonts from Expo’s Google Fonts before you can import them into your code
Data Science & ML
If you want to use things like machine learning in an app, we found the easiest way was to create our own API endpoint that could be called from the front end.
Since we used Python scripts for much of our key functionality, to use these within the app and within the AWS ecosystem we used a combination of Lambda functions, DynamoDBs, and S3 storage
We used REST APIs to pass app input to the backend functions; the app calls our API on a specific action (e.g. a button press or when a particular component mounts), sending real-time data from the app
The final output is marked up and returned to the app, where it renders on the screen for the user
The data is also stored in a database table which is accessed via the GraphQL API (more detail below)
From a front-end perspective, the key tasks are to:
Capture the required data from the mobile device (from device sensors, location, etc.)
Define the API call (endpoint, parameters, etc)
Create the function that passes the data as parameters and invokes the API call
Parse the response received and render the relevant information on screen
Backend services & integrations
Assuming you’ve already created your AWS account and configured the CLI per the set up steps, you can handle the backend build in a few different ways:
Using Amplify Gen 1, you can use commands in the terminal and Amplify’s CLI to configure services incl. authentication. You can also visually configure this in a browser window, then pull the backend into your app via the CLI
Using Amplify Gen 2, you almost entirely use Typescript hooks. Gen 2 came out while I was working on this, so we continued with mostly Gen 1
I found starting with visual browser config easiest, then switched to updating my schema locally once I had the main structure in place.
Log into AWS console and navigate to Amplify
Create a new app, selecting ‘build’ not ‘host’
Set up your first service, e.g. authentication
Run the ‘amplify pull’ command to pull this configuration into your local project
Install required libraries (see Amplify documentation for full list but it will be things like the below):
npm install aws-amplify
npm install aws-amplify @aws-amplify/react-native @react-native-community/netinfo @react-native-async-storage/async-storage react-native-get-random-values
Add Amplify to the frontend code (as early as possible in the app flow, e.g. root layout or app.js file)
import { Amplify } from 'aws-amplify'; import amplifyconfig from './amplifyconfiguration.json'; Amplify.configure(amplifyconfig);
Authentication
If you’re using Amplify’s default screens for auth, you’ll need to add another library for the UI
expo install @aws-amplify/ui-react-native react-native-safe-area-context
Add the code to wrap your app in authentication
If using an Expo app with Typescript, this should be done in the _layout file for the screens you want authenticated (e.g. if you want the whole app authenticated, add it to the root layout. If you have some public or onboarding screens, add it to the layout file within the relevant folder encapsulating all your authenticated screens)
In your app entry point for authenticated screens, you will need to import the withAuthenticator hook from the UI library
You can also create custom auth screens; we plan to do this but have kept our MVP with the default while we focus on user testing
Create a lambda function to add new users to a database when they sign up to the app, and any other lambda functions you might need for your app
Data
Using Amplify, you can create a data model / schema of the fields and tables your app will need, and Amplify will trigger creation of all the relevant DynamoDB tables and AppSync environments which allows you to interact with it using GraphQL APIs. Using the Amplify pull command in a terminal, Amplify will update your project directory and create the relevant folders and files (e.g. the GraphQL schema file). Step by step…
Navigate to Amplify Studio (if using Gen 1) and to the ‘Data’ tab
Use the visual interface to create the tables and fields you need
Set the data types and requirements for each field
Press deploy and wait for Amplify to do its thing (this can take a while depending on complexity)
Once the data model has been deployed, return to your code editor and open a terminal, then run amplify pull (you’ll need to do this any time you amend, save and deploy anything in the browser)
You should see folders created under the amplify folder and several additional config and json files
To interact with this in Typescript, we need to generate the types for all the queries, mutations and subscriptions. Run amplify codegen in the terminal and follow the prompts - this should create a file called API.ts which has all the Typescript types for your tables (magic!)
You can also run codegen to create a starting point of GraphQL queries and mutations for these tables, e.g. to list all items in a table, get(fetch) specific data, etc.
Create data:
In Amplify Studio (Content tab), generate data for your tables to work with. You can do this manually or auto-generate dummy data.
This means you should be good to go for testing queries and mutations, and with the dummy data you can test if the queries are working to return the expected results
You can also test queries in the AppSync console directly, which I found helpful to validate that the queries in the app were returning the expected results
Other Integrations & APIs
If using external packages or APIs (e.g. location services, camera functionality, etc.) which involve accessing the user’s private information, you need to get the user’s permission. This requires some config in the app.
Install the relevant libraries
Import them into the app in the relevant place
Update the app.json file in the plugins section to add the plugin name and permission string and, if you’re building natively for iOS, update the info.plist file (avoid this if using Expo)
Deploying & user testing
There are two main options for deploying an Expo app for testing and review. Either you can follow the native routes and deploy via the App Store and/or Android Studio, or you can use Expo Application Services (EAS) to create cloud builds and publish for you. Neither option is free: if using Apple, you’ll need a paid up Apple developer account (but you’ll need this to publish to the App Store anyway), and if using EAS, you are charged based on usage.
I found EAS a little confusing and I had several issues that needed troubleshooting, so including the steps here and some resources.
You’ll need an Expo account so if you don’t have one already create one now
If you want to test with Apple or Android, you’ll need the aforementioned paid-up Apple Developer account or Android developer account first. If you’re doing this as an individual it’s straightforward, but as a business you’ll need a D-U-N-S number and for Apple to validate your business, which can take a while
Install the EAS CLI globally
Configure the EAS build (follow the EAS docs)
Update the EAS.json file to specify the simulator and/or devices you want to build on for the version (e.g. development vs preview vs production)
Run the build - this should create a new build hosted in the cloud
We’ve been testing the builds as we go in simulators and on our own physical devices, but now with a cloud build we’re testing with a small group of friendly users. This is a critical stage to gather feedback and no doubt our product will evolve significantly. The key is to get something out there early on and iterate quickly - there are so many other features we want to include and we know the experience can be even better, but we’d like to get user input as we start prioritising what to do next.
Watch this space - hopefully the Spotty app will be available to download soon!