Which features make an app expensive to develop?
Published on September 27, 2019
There is no question more frequently asked in mobile app development than: "How much does it cost to build an app?"
The tried and true, industry-standard answer is, of course, "it depends." Software developers frequently struggle with accurately estimating how long a project will take to complete. The longer a company operates in this space, the easier it is to rely on past experience when generating an estimate on a new project.
As the great 18th century polymath Benjamin Franklin once said: time is money.
There is some productized consistency in software development, and for the sake of transparency (one of our core values), we have a Pricing page on our website that breaks down the costs of:
- How to get started building an app (Validation, Prototype, & Roadmap)
- Building custom software (Single and dual platform apps, custom CRM/CMS, full-time development resources, hourly rates by service, & more)
- Supporting custom software (Server Management and Code Maintenance)
But in this article, we will take you through several commonly-requested features which are complex (therefore, time-consuming) to build to give you an understanding of why these features are complex to develop.
We'll also give you some ways to ship your first mobile app as quickly and as inexpensively as possible.
Games are one of the frequent types of apps we receive requests to build, and to this date, we still haven't released a game as a company. This is because games are incredibly difficult not only to build, but to turn a profit.
Let's take a popular game like Angry Birds, for example. On the surface, the game seems simple. You fling a bird across the screen and knock over pigs. Easy, right?
Well, consider what it takes to get to that point:
- A team needs to develop the backstory of the "bird vs. pig" concept
- An architect needs to establish the rules which govern the world (the physics, the points, the obstacles, etc.)
- A designer needs to draw the graphics
- A developer needs to take the backstory, rules, and graphics, and express all of that in code
- A tester needs to find all the ways where a user could break the rules
That's just to get to the point where you have one screen and one fling-able pig. You also need to factor in multiple levels, multiple types of birds, multiple sizes of pigs, and so forth.
Now that you have a full fledged game, you have to worry about marketing that game. Most estimates these days indicate that if you're looking to get in the Top 20 games on the App Store, you're going to need a budget of around $500,000 per year for just marketing.
And this is just for a game like Angry Birds. Take a look at Wikipedia's list of most expensive games to develop.
The most expensive game as of writing, Call of Duty: Modern Warfare 2, took $50 million just to develop. Grand Theft Auto V cost $137 million to develop. Then there's the cost to market the app. Once you account for marketing, even the simplest of games would still require a six-figure budget.
There are certainly exceptions to the rule, as some games are easier to develop than others. Grand Theft Auto V has an incredibly rich, complex world that you can freely roam in. Checkers, on the other hand, is a pretty straight forward game with far fewer rules.
Of course you should be able to log in to an app on one device, make some changes, and see those changes on another device.
However, getting data to correctly sync across multiple devices is one of the more challenging tasks you will encounter when building an app from scratch.
Let's say you're building a reminder app. The assumption is that if you create a reminder to "bring the garbage out" on your iPhone while you're at the store, it will be on your iPad when you get home.
But what would happen if you are in a store with horrible signal? How can you be certain that the reminder would make it up to the cloud?
You would need to account for the device having some kind of "retry" feature built in where it keeps trying to get in touch with the cloud, and once it can make a connection, then it should send up that reminder.
That's an easy example, so let's ramp up the complexity.
Say you and your wife are building a shopping list together on separate phones. You add "cheese" to the list and sync it to the cloud. You head out and take the underground subway to the store, which knocks your phone offline.
Now, let's say your wife is reviewing the list and sees "cheese" but wants to be more specific. She changes it to "muenster cheese" and saves it up to the cloud.
While you're on the train, you pull out your phone and review the list. You notice "cheese" isn't well specified, so you change it to "provolone cheese."
Once you get off the train and walk to the store, your device sees that you changed "cheese" to "provolone cheese," so it tells the cloud to make that change. However, the "cheese" entry was already changed to "muenster".
Your app's server infrastructure (also known as "the cloud") now must make a choice:
- Erase "muenster cheese", replace it with "provolone cheese" (which would make the wife angry)
- Keep "muenster cheese", erase "provolone cheese" (which would make the husband angry)
- Keep "muenster cheese", create an additional item called "provolone cheese" (which would lead to twice as much cheese purchased)
Nobody is going to cry over too much cheese (which I can attest to, as a man happily married to a Wisconsin-ite), but if you applied this basic principle to something more serious, like two doctors updating your medical record, you can see why this problem requires thoughtful attention.
At its core, the "cheese" problem is an ethical one. Computers are great at making simple choices, but they are not so great when it comes to making even basic ethical decisions.
As you add more and more variables to the data you are syncing, your developers need time to give the computer better ways to deal with cases like the "cheese" example.
(If you're interesting in learning more on the topic of ethical computing, take a peek at the trolly problem, which is becoming more relevant as we approach the age of self-driving cars).
As with syncing data, search has become one of those features we all take for granted. (Thanks, Google.)
If you have an app which provides a list of the restaurants in your area, of course you should be able to type in a few characters and get back a list of restaurants.
But like sync, while the concept of search is simple, the execution is complex.
Let's say you are looking for a restaurant called "The Chef & The Cow". You open your app and type in "The Chef and The", and... nothing appears.
Why is that? Because in the database, you have the restaurant listed with an "&" instead of the word "and". Computers are pretty dumb. They can only do what they're told, and nobody told your system that the word "and" is the same thing as the ampersand symbol.
Let's take this a step further and say that "The Chef & The Cow" is a successful nationwide chain. Now, when I am in Saint Paul and type in "The Chef & The Cow", I get a list of all their locations, but... it's sorted alphabetically by city! It does you little good to see the Anchorage location, and you begrudgingly scroll down all the way to the bottom to find your beloved Saint Paul location.
What gives? Well, if we want to have that list sorted by proximity to you, we'll need to add geo coordinates (a latitude and longitude point) to each location in the database. Then, we'll need to have the app give us the user's latitude/longitude, do the query for "The Chef & The Cow", then sort it by distance from the user's location.
You can see with these two simple cases how fast search can get complicated.
We mentioned Google above. They made their billions because they were able to take an insane number of variables, process it all, and spit out the thing for which you were looking in a crazy fast amount of time.
Spinning up a rudimentary searching algorithm takes no time at all. It is much more time-consuming to build an app which provides your user with the exact information they are seeking right when they need it.
The previous two features are easy to develop initially but become more complex as your project grows.
These next two features are ones which start out complex but become easier once the framework is in place.
Push notifications require a tightly-integrated system between your server and your apps. Let's dissect the flow of a typical push notification in an app like Instagram.
Once I download the app on my iPhone and launch it, Instagram asks me if it is alright to send me push notifications. If it is, Apple generates a unique token which Instagram stores on their backend infrastructure (server) for future use.
A few days later, I'm at a brewery with my wife and daughter, enjoying a delicious brew, and I simply must take a photo. (Oh look, I have a sample photo right here!). I open up the Instagram app and snap a picture.
Later that evening, you start scrolling through your timeline and stumble across this unbelievably epic photo that I took. Your fingers reflexively, and without any hesitation, leave a comment about how cute my family is.
Instagram sends a note to the server saying "user
X commented on photo
Y". The server saves that information in its database, then tells its push notification system to let me know that you commented on it.
The push notification system first needs to determine if I have an iOS or Android device. Since we sent up an iOS token earlier, Instagram knows it needs to use Apple's Push Notification Service (APNS) to deliver the notification. It packages up some information about the notification (the message that shows up on the screen, along with a few pieces of information which will let the app open to the correct screen) and sends it up to APNS.
APNS then takes that information and sends it down to my device. My device then populates the system's notification center with the notification information.
Once I tap on the notification, the Instagram app opens up and recognizes that it became active due to a notification. Since this notification is about a certain photo, it routes me right to the same photo that you just commented on.
This process all happens typically within a second or two. While it seems straight forward, the whole push notification system is surprisingly complex and requires the development of several small pieces in order for it to work as one cohesive unit.
Before you can send any push notifications, you need to get your server set up to handle saving the token information to the user's profile. One complexity here is that many users have more than one device (for example, I have Instagram on my iPhone and my Android tablet), so you need to be able to associate multiple tokens of differing OS types to a single user's account.
After you get that set up, you need to get the server talking with both APNS and with Google's Firebase Cloud Messaging (FCM). Despite being incrementally improved over the past several years, this process can be pretty annoying and time-consuming.
The final piece of the server setup pie is being able to take a user action and translate that into an actionable notification. In that "user
X commented on photo
Y" example, once a user comments on a photo, you need to bundle up photo
Y's unique ID and user
X's unique ID, along with a default message (such as "
X commented on your photo."), and send it up to APNS or FCM.
And that's all it takes! Sounds pretty simple, right?
Not only do you need to worry about integrating push notifications the first time, but you also need to deal with the minor updates Apple and Google make to their side of things. Nearly every single yearly major OS release has included changes to the framework. This means that for every version of iOS or Android you wish to support, you also need to write unique code to handle push notifications depending on what device your user is using.
Implementing push notifications is not all gloom and doom. Like we said up top, once you have this system built out, it's pretty easy to quickly add new notifications for new features. The big bummer is that push notifications are so useful, you almost have to include them right out of the box when you're building an app from scratch.
Just like push notifications, setting up in-app purchases (IAP) can be an exercise in restraint (as in, your developers will need to restrain themselves from smashing their laptops against their faces while implementing them).
We preach to our clients about the necessity to make money when you launch an app, and research indicates that in-app purchases are one of the best ways to do so.
The process for implementing in-app purchases is as nuanced as push notifications, but with the added benefit that if you screw something up, it will actually cost you money.
In order to understand the complexities around IAPs, let's discuss how an in-app purchase functions from start to end.
Say you're building a puzzle game, and you want to offer your customers the ability to purchase hints to your game. We call these types of IAPs "consumables", and they grant your user the ability to do something one-time in your app like get hints, buy in-game currency, or get extra health points.
Lucky for you, these are the easiest types of IAPs to implement. Again, using Apple and iOS as an example:
- Your user taps a button that says "Take my money and give me extra health points."
- You send a message up to Apple saying "This user wants to purchase more health points; is that OK?"
- Apple then pops up a dialogue to the user saying, "Are you sure you want to spend money on this thing?"
- Your user says, "Yes, please take my money."
- Apple handles the credit card transaction, and then says "Okay, app, your user just gave me X dollars for Y feature, and here's a receipt."
- You take that receipt, make sure it is a legit receipt, and then you give the user their health points.
Like I said, these are the easy ones to implement. Because you are performing a one-time transaction, you don't need to do anything with that receipt. You gave the user their health points, and now they can continue to play the game.
But what if you have an app which displays advertisements on the bottom of the screen, and you want to give users a way to pay a few bucks to remove those ads?
Enter the "non-consumable" IAP.
In order to implement a non-consumable IAP, you follow most of the same steps as above. The big difference is that a non-consumable IAP is everlasting. If your user drops their phone in the toilet and buys a new one, they must be able to recover that purchase on their new phone.
But how can you determine if a user purchased your app in the past? Why, receipt validation, of course!
Receipt validation occurs in two ways: either at the time of purchase, or when a user taps the required "restore purchases" button inside your app. If a user taps "restore purchases," you need to ask Apple for a copy of their receipt and make sure it is a valid receipt.
The receipt validation is something you need to incorporate on your server. This feature isn't a challenging piece to implement, but it is certainly something that takes time.
Another time-consuming task with incorporating IAPs into your app comes from testing your implementation. By introducing a split based on whether or not a user paid for your app, you now need to split your code into two sections. You also need to spend time building screens prompting your user to pay, and you need to block off features for those who have not paid.
Putting it all together
When you are coming up with the next great app idea, you certainly aren't thinking about the algorithm your search feature will use or the way you will handle data collisions on sync.
More likely than not, you are thinking about a feature from a higher level, like "a feature where users can have a conversation in Facebook Messenger."
Communicating with users inside your app is a great way to demonstrate several of the items we discussed above working together to perform a single task.
Adding a chat component to your app requires the following 3 services (at a minimum) to work in concert with each other:
1) Data Sync
When I send a message to you, that message needs to appear instantaneously on all of your devices.
If I'm trying to find you in order to communicate with you, I either need to provide your phone number/user name to the system or search for your first and last name.
Searching by first and last name is easy when there's a small number of users with unique names. But if you have a hundred users named Joe Smith, how can you sort that list so the relevant Joe Smith shows up first?
3) Push Notifications
As soon as you receive a message, you should also receive a push notification on all of your logged in devices.
How to Lower Your Development Costs
We've spent most of this article explaining what makes some features difficult and time-consuming to build. So now that you have a good understanding of those features, how can you save money when you are first building your app?
1) Keep your feature list simple.
When you're building out the first version of your app, we recommend taking a hard look at the features you want included and keep them as simple as possible.
- Does your app need in-app messaging?
- Can your users get by without a profile?
- Would your users stop using the app if they weren't prompted with push notifications?
It sounds obvious, but the smaller your initial scope of work, the faster your development team can finish it.
2) If a feature is big enough to be its own app, try skipping it.
Take messaging, for example. There are thousands of apps in the app store whose sole purpose is to help two people hold a conversation. Odds are that you have at least 2 on your phone right now.
If there are already a thousand places where your users can hold a conversation, why would they have to have that capability in your app?
If an entire company is already built around a single feature that you want to have as a small part of your app, you might want to just punt the user to one of those services and focus your efforts on the features which make your app unique.
3) Use third-party solutions to take care of hard problems.
Instead of rolling out a feature from scratch, check and see if it would be more efficient to use a pre-built solution instead.
Looking to process credit cards? Don't roll out your own payment gateway, just incorporate Stripe. Need to create user accounts and let them log in? Try Firebase.
One caveat here: don't outsource core features of your app. If you are building a video streaming service, for example, don't rely on YouTube as your host. Every feature for which you depend on another company to provide is a liability for your own company because they can always change their terms, get shut down or acquired, or simply not like what you are doing and terminate your access.
4) Move work to a future phase.
Software is a constant series of iteration. Even if you don't change your app, outside forces will act on your app. Apple will launch a new iPhone. Google will launch a fresh version of Android. These changes alone require you to perform regular upkeep on your app.
The bar is certainly high for new apps. Users have high expectations for what a piece of software should do for them.
However, above all else, people download apps for one reason: to get a task done. If your app cuts out all the cruft and lets them get their job done, you will have a much easier time finding long-term, satisfied customers.
Wondering how long a feature might take to build out? We'd love to tell you! One of the key advantages of working with an app development shop like The Jed Mahonis Group is our vast experience with mobile app development. Because we've been around the block so many times, we know which features are easy to quickly implement, and which features simply take a long time. Get in touch with us today!