Last friday at PyGrunn (a local Python conference here in Groningen), I did a short presentation about the architectural choices you should and could make during development of mobile applications.
Some of the people in the crowd asked me if I could summarize them in a post for future reference, so here we go:
Should we treat mobile clients different then normal “wired” clients?
Yes… With mobile clients we have five key points which are different opposed to a “normal” web client:
- Data Access;
When we look at mobile clients, we have two kinds:
- Native applications
- Mobile Web applications
Users of the second kind of applications (mobile web) will expect the same functionality as on traditional web clients: you load, you post, you wait and you load. If the connectivity fails, you get an error and you reload and send again. All in all a “traditional” synchronous approach of sending and receiving.
The first kind of applications, is completely different; the native applications.
While using native applications, users generally just want to get things done. They want to send a mail, tweet or photo without any pop-ups nagging about lesser connectivity. They just want to press send, lock the phone and go on with their normal flow.
Because multiple tasks can be done on modern phones, the user generally doesn’t wait until the message is send and doesn’t want any error messages of a mail app to pop-up while playing Angry Birds.
This creates a more asynchronous approach in the behavior of the application: the users doesn’t wait to receive status messages and often queues multiple messages at a time for the server to handle.
In overall, in mobile architectures, performance best practices are generally the same as opposed to traditional web(service) architectures. Your architecture should scale vertically and horizontally when needed to create optimal response times.
There is one big difference between a normal web-service and one suited for mobile applications:
Make your server work.
Don’t do number crunching or large data calculations on your clients. As opposed to normal clients, mobile clients have limited CPU power and memory. Next to that, heavy calculations will drain the battery quick and will leave your users without power.
Because network activity is costly on battery and CPU, when you can:
Push from your servers
Most mobile devices already have a service running, which enables you to push information or tasks to the client. This saves battery and resources because the device only has to manage one outgoing “socket”.
For usability, connectivity and performance sake:
Store data, retrieved from you servers, locally for offline access or slow access.
Requests are costly, so it is better to pull as much as possible (text) data in to serve out of the cache then to pull every item from the server when the user needs it.
Refresh that data periodically or on user requests. Try to postpone periodical refreshes until the user has a better connection.
Expire and delete not-used or old information both on the client as from the stream a client pulls in… Even if the user only follows 4 users, tweets from 4 months ago generally aren’t that relevant anymore.
Queue and combine requests as much as possible, send less important non-realtime requests (like a “like” on Facebook”) together with high priority stuff.
Concatenating messages will reduce the requests you send to a server and will limit the problems you have with latency.
If a connection fails when sending, wait… Reconnecting on a bad wire is costly (and will generally fail anyway). Storing the queue and waiting for a better connection reduces data and battery usage.
If you don’t use it or need it, don’t push or pull it…
Only send information to the client which he actually uses. If you don’t use the tags of a news post in your application, strip them from the serialized objects.
Make you payloads tiny, use JSON over XML and GZIP all possible content!
Do payload adaption
Adapt the content you send to the connectivity of the user. When loading news items for instance, only send the full-fleged article with 4 photos and video to users with a WiFi connection. Send items with 1 image to 3G users and send text-only articles to users with GRPS connections.
Doing this, don’t get usability in the way… Support it: let the content load as fast as possible and let the users decide to wait on rich content.
Feels like 2005 saying this, but: No more direct database access
Do what everyone should do (and hopefully is doing right now), create a API!
Having a API gives you the possibility to:
- Switch server architecture (OS, Database etc.) without updating the app;
- To do number crunching and caching on you servers;
- To distrust your users.
Never trust API input
Your application isn’t the only one which can talk with your servers. You should perform simple validation on your client for usability and performance. But should always check server side, for validation, authorization and logic.
When it comes to man in the middle attack, clients have never been as vulnerable as mobile clients. With user hopping from WiFi spot to WiFi spot, data is easily sniffed and misused.
So, encrypt your data streams… Use HTTPS when possible and encrypt secret stuff with techniques like private => public key encryption.
Store your secret stuff well, client-side caching makes your data reside on both servers as clients. But don’t safe too secret stuff on clients, reverse engineering of your app probably already finished yesterday!