Mobile startups all face the same problem: how do you balance growth with app stability? After all, everyone wants more users, but when that hockey stick growth finally happens, unless your company is prepared, your end user experience might suffer.
This post is part of a series about problems you’ll encounter when scaling a mobile application. Future entries will cover tools, infrastructure, and the team. Here, we’re addressing the architecture, including:
- Adding New Features
Organized code allows developers to find specific functionality quickly. They can build features that reference logically-separated pieces of code. This reduces the chance that any individual change will break code in several different parts of the application at once.
Tracking down bugs becomes much easier as well. Instead of searching through several thousand lines of code, developers might have their search radius confined to a few hundred.
Let’s say your current mobile team consists of one iOS engineer and one Android engineer. They might not view refactoring code as a priority because they are the only ones interacting with it. But as your app scales, you might hire additional developers. Without proper code organization, the onboarding process could take a lot longer than expected.
Here are some great questions to ask your mobile teams when it comes to how your code is organized:
- Can multiple people work on the project at the same time?
- Can you ramp up remote engineers at the same pace as on-site?
- Is specific functionality encapsulated in a separate module?
- How much time do you spend documenting your code?
A well-organized code base pays dividends to current and future developers, allowing them to move fast without breaking things.
The key question here is, “Can your code accomplish its intended purpose efficiently?” Apps vary in the amount of data they send and receive. An app that streams video has different requirements than one that allows users to play offline games.
If your app falls into the heavy data category (e.g. real-time functionality, streaming video, location-based features like ride-sharing), it might work well when the user base is small. Once the user base grows, network bottlenecks might appear, signaling performance shortcomings. In the end, the user experience suffers because your backend cannot handle the increased traffic.
Also, think about how much data your app sends to the backend. Sending every single log as an individual HTTP request might work fine when you have 1,000 users making 100 requests a day. But what happens when you suddenly have 1 million users sending 100 requests a day?
We’ll discuss infrastructure in a later post, but there are considerations at the app level that will bring big performance gains without requiring rebuilding your entire backend:
- How much can you cache data to reduce the number of network calls your app makes?
- Can you combine multiple requests into fewer ones?
- Are you making too many network calls at startup, impacting the user experience?
- Are you making sure to release memory when it’s no longer needed?
- Are you writing code that uses fewer CPU cycles?
Adding New Features
As your app scales, you’ll want to add new features. One of the biggest ways this can slow down your release cycle is when developers have to spend a lot of time ensuring new features don’t break existing functionality. As we mentioned before, having a clean code architecture helps ensure you don’t have duplicated code that can cause unintended behavior when building off previous code.
Another thing to keep in mind is planning for future additions in your user interfaces. The UI will need complete overhauls from time to time, but incremental changes shouldn’t be perpetually bogged down by constant UI rewrites. It helps to keep future changes in mind when designing user interfaces. This can save time and money by simply dropping new features into interfaces that were already ready for them.
Developers must also keep in mind how data flows into and throughout their app. Will your data be kept in a global store and pushed to different parts of your app? Or will individual views be responsible for their data? By inspecting how data moves around your app, you can find improvements and consolidations. Also, plan from the beginning where your app will break from scaling. If you know where these breaking points are ahead of time, you can put queues or other async systems there from the very start. It’s much easier to improve the data flow when a scaffolding is set up to handle it.
This all comes back to how important a good architecture is for scaling an app. Without it, you limit your company to just on-site, full time hires. With a good architecture, you open your company up to other scaling strategies, like contract or remote teams. Those strategies are too expensive on a brittle code base.
Some good questions to ask your team include:
- Can you improve the way data flows through your application?
- How much time do you spend making sure new features don’t break existing functionality?
- How often do you refactor code to keep it dry?
Writing tests is very important, as they can help developers know whether a change they are making will work as it is supposed to and not break existing functionality. But writing extensive test coverage takes a lot of time, and sometimes there just isn’t enough of it.
If you don’t have time to write all the tests you would like, then write integration tests. Use a mock server like GCDWebserver or anything else to capture the objects your app posts and supply your app with realistic responses. Run your app against that server manually if you have to. You can populate the server by capturing response payloads with something like Charles Proxy. This is the lowest effort way to get decent test coverage. Next, you can dig into unit testing specific core components, but by starting with integration tests, you at least get the inputs and outputs covered.
Some good questions to ask your team about testing include:
- Where are you missing test coverage?
- How can you make testing a part of your workflow?
- Have you seen the tests fail? (If you haven't seen them fail, you should assume they don't work and are always passing.)
- What issues have hurt you in production recently, and can you write tests for them?
Summing It All Up
Scaling a mobile application is incredibly difficult. It’s important to set your company and your employees up for success by implementing and enforcing processes that empower them to handle the challenges that scaling brings.
Your architecture can help if you build a good system. Good systems tend to describe themselves, and don't need as much documentation and support. If a developer can make their way around your code base with minimal assistance, then you know you’ve built a good architecture.
We’ve covered a few main areas: organization, performance, adding new features, and testing. These are just a few of the ways that having a good architecture will help when your app scales.
Who We Are
Embrace is a mobile monitoring and developer analytics platform. We are a one-stop shop for your mobile app’s performance and error debugging needs. If you’d like to learn more about Embrace, you can check out our website or visit our docs!