It can be tempting to assume someone else’s craft is simpler than it really is. My father always used to say, “If it was important, I would know it”.
To an outsider of software development, it can feel like all you need to do is come up with an idea, and then it’s just a case of throwing the app together.
But as is the case with many things in life, there are a lot of moving pieces needing to be managed, even when talking about the simplest of apps. With this in mind, we thought it would be helpful to provide a peek into what it takes to make a modern mobile app, breaking down some major challenges we encounter and how to go about solving them.
The client’s idea
So before we talk about development, it would be good if you actually knew what the project was about! Live Aurora Network came to us with a unique idea. They had a network of Sony cameras around Iceland constantly streaming, providing an incredible view of the northern lights. All they needed was a way to get these feeds to you.
That’s where we came in
We built a bespoke app which runs on all major mobile platforms allowing you to view the northern lights from the comfort of your home. Because they provide a real-time feed of when the northern lights are active, we were able to provide live notifications alerting you to open the app.
If you’d like to see more in person, you can get directions to the location, or book with one of the partnered Airbnb hosts.
How we made it
The simple answer would be that we threw some designs together, approved them with the client, and made an app. Often that’s how things start to feel when you reflect back after a few years. But just as we can describe a chef’s craft as “just cooking”, this too is an oversimplification.
To kick things off, we held a series of workshops with our client to define precisely what the app should do. We sketched screen layouts and carefully refined a ‘user flow’. We discussed how our users would operate the application, aiming to establish an engaging user experience.
Once we had agreed upon functionality and layout, our designers applied an aesthetic layer to the wireframe application. They made it look pretty. As a new company, Live Aurora Network had little in the way of existing visual brand guidelines. That meant we could have a little fun. We established a clear and classy visual style that wouldn’t distract from the main content. The design draws focus to the beautiful aurora streams while providing complementary information which doesn’t get in the way.
Planning out the components
Before delving into the code, we decided to ask ourselves two important questions:
What are the consistent components shared across the screens?
This can be anything from headings to a skip button. I’m sure it’s not hard to convince you of why this is a good idea. Write a component once and then use it everywhere else instead of constantly shooting yourself in the foot.
What are the common layouts?
This next one may be a little less obvious. We next like to look at the common positioning of components. So the idea is, if you notice a bunch of screens where you have a heading at the top and a bunch of things at the bottom, why not make a component that accepts a component to show at the top, and a list of components to show at the bottom?
Once we have those items planned out, we can move onto our first big decision. What will we build this app in?
For the curious, this is what our app directory ended up looking like:
When building anything, it’s important to consider what the best tool for the job will be. It’s always good to leave this decision for as long as possible as described by the wonderful Robert C. Martin in his book, Clean Architecture.
We came to the conclusion this app was UI heavy and the designs were bespoke and not platform dependent.
This led us to use React Native. It’s a framework which allows you to write cross-platform apps with a single code base. In addition, it also has a nifty feature called live reloading that allowed us to quickly iterate and explore much faster than you normally would with traditional app development. This opened up the Node JS ecosystem to us, which since 2017 has had the largest package repository in the world.
But every decision will always come with pros and cons, and a major hurdle for us to overcome was the map and usage of YouTube.
As a developer, you’re often going to use existing code someone else has written. This app needed to utilise YouTube which meant we had to use the only YouTube library for React Native. This is prudent as there are usually many intricacies you cannot foresee before delving into integrating a service (such as YouTube). Due to the support of this library, we were then forced to use an older version of React Native.
If you take a look at React Native on npm you’ll notice something interesting; it hasn’t hit version one yet. This means every time a minor version of React Native is released, everything brakes horribly. When you combine that with this statement from the React Native Maps package:
“Due to the rapid changes being made in the React Native ecosystem, we are not officially going to support this module on anything but the latest version of React Native.”
You can see why things get a bit tricky.
So how do you get an older version of a map to work the latest version of React Native? Well, you delve into their map code and fix it yourself. The biggest problem comes down to something called a ‘build process’. Most people think programmers write some code and then the computer runs those instructions. But the truth is there are a lot of little steps between having something a human can read, and having something a machine can read. And if there’s one law in the universe, it’s that nerds hate doing lots of repetitive tasks. That’s where the build process comes in. We write out a number of steps to turn the human-readable stuff into the boring machine-readable stuff. Again, why does this affect the map? Well calm down impatient reader, I’m getting to it!
If I want to use the maps package, I don’t simply get the code, I also get the build process needed to convert all that stuff. The problems start to happen when you’ve got a newer version of React Native that expects you to build things in one way, while the maps package you have has build instructions to do things in another way.
This is where things got boring. I mean really boring. Changing instruction after instruction, looking at what’s changed between the different React Native versions hoping to find the magic middle ground that will build both your app and your map. We, of course, managed to do this in the end — I wouldn’t be telling you about our app if we didn’t (stop being so presumptuous humble reader) — but it did take a lot of time.
Once we had the map and YouTube feeds in place we quickly realised we could convey a lot of fluid transitions between each screen. The idea was, we would share components between screens and rather than going straight to the next screen. We’d start the components in their old position and then move them to where they needed to be for the next. As stressed by Nick Babich from Shopify, the world is not stationary and things feel more natural to us when we see movement.
Knowing full well that this would be harder (and was not expected by the client) we did what any sane company would do in our position. We added them in any way. And it paid off. Each screen seamlessly transitions into next. And you barely even notice it.
Caching your stuff
The next thing we had to worry about was all the data we needed to send over to your device. We knew we were going to send weather forecasts, KP indexes, and so on but we didn’t want to throttle your device with a million requests.
And so we decided it would be a good idea to place our own server between your device and these requests. This server would make all the requests for you and condense everything into a single far more useful response. It would then also cache all these requests so we weren’t throttling all the other services too much.
If you ask for the weather and someone else happens to have done this half a second before you, the server would send you both the same results instead of making two requests to the openweather API we used.
We thought to ourselves, how likely is the weather forecast to change every few minutes? So we added caching to your phone so you don’t need to even ask the middleman server for anything when you don’t have to.
Once we were happy with the app, we sent it over to the client using private beta channels for both the App Store and Google Play. And very quickly with the app in hand, they realised all that could be achieved. So we didn’t stop there, we got more feedback, and began on another iteration until they had the best possible product they could have.
What did we learn?
The real gain of taking a step back is to see what we could have done better, and sometimes that can be tough. It’s not always easy to admit where we went wrong.
The elephant in the room is, of course, is if there was a lot to be gained from taking the React Native route. It did often feel like we ended up doing twice the work to get the app to build, a common complaint from the community.
It’s difficult to say for sure if this was the right path or not. On one hand, we only have to sort it out once, and we now have a single code base to work off. On the other hand, no project is static, and we may have the same problems to come.
Perhaps the only real take away we can say for sure is when considering which tech stack to use for a project, it is always good to be a little pessimistic. Don’t only think about the things you’ll gain from different approaches. Also, take a look at your hardest problems for the project and see what can go wrong with each stack.
And of course, it is also good to take a look at what went right. Both to motivate yourself and to replicate your success for future projects.
The biggest take away would be to never feel like the project you’ve agreed on is what you’re fully constrained to. Often there will be small crevices you can slip inspiration into. Even when it’s something as simple as getting from screen A to B, it can be worth finding the room to play and make your product a truly better one.
When all is said and done, you won’t remember what was difficult about your project a few years from now. But you will remember what you could have done better. And that’s why at Forge, we always try to push for that extra 10%. Because it’s not just about exceeding our client’s expectations, it’s about exceeding our own.