Aspect #1: The Application Startup
Everybody would agree that usability is an important factor of mobile applications, but probably not everybody would agree that optimizing the startup process is part of the usability effort. All mobile OSes will notify about startup events, and also have a set of other events around the application lifecycle. Typically, there's an event that fires only once for the initial loading of the application, and then a few other events subsequent to the application being paused and resumed. You should make clear which tasks to perform for each event. The golden rule is that the startup has to be the smoothest and quickest possible. This means, for example, avoiding setup questions except, perhaps, the first time the application is run. If users need to specify settings, reuse their latest choices to speed up the process. If the application is subject to licensing, avoid checking that at every startup and resort to checking it in advance and storing results. Also, define your policy for when connectivity is lost. Lengthy tasks should not belong to the startup process. If that's not possible at all, then provide feedback using a context-sensitive indicator: the sooner you display some UI, the better.
Did you recall how applications were written in the 1990s? Most of them were just based on a task-based main menu with a loop waiting for user input. It's the same pattern for mobile applications: Quick startup and a clear list of possible tasks.
Aspect #2: The Natural User interface
Desktop applications conquered the world with their graphical user interfaces (GUI); mobile applications are going to do the same thanks to their natural user interfaces (NUI). As the child of multi-touch capabilities, NUI is made of a number of gestures such as swiping the screen to scroll and pan, pinching/stretching to zoom, tapping to click, tapping-and-holding to get context menus, and shaking the device to do whatever makes sense for the application.
As long as your application provides features that map to the intended meaning of most gestures, you should go with NUI. Mobile platforms usually offer ready-made events and you should be using them whenever possible (as opposed to lower-level events such as button down, tap down, tap up, and the like). Custom and application-specific gestures are possible, especially multi-touch gestures that involve two or more fingers, but they are just custom gestures that may confuse users.
Aspect #3: Input Forms
Typing is evil for users of mobile applications whether or not the device has its own hardware keyboard. Of course, typing is just unavoidable for most applications. A good compromise is minimizing the pain by showing just the set of characters that will likely be used, using customized auto-completion, and treating numerical data appropriately.
Voice input is an interesting field, but its wide adoption is currently limited by the fact that very few languages are supported ,not to mention the quality of recognition and the time for training. A smooth combination of a classic keyboard and voice input is a good pattern to follow in scenarios where a lot of text has to be entered.
Another problem to be aware of is that the soft keyboard often ends up covering widgets and controls in a way that prevents or limits normal interaction. It is unpleasant, for example, when you must manually close the keyboard to be able to save what you just entered. Designing the UI of a form that considers the soft keyboard is a good example of maximizing usability.
Aspect #4: HTTP calls
Remote calls may cost money to a mobile user, but minimizing the number of remote calls is not a pattern that can, or should, be applied to just any application. For enterprise-class applications, designed for a business audience, this is probably just not an issue, as these users will probably have a flat fee with no significant limitation on traffic.
A more important aspect of HTTP calls is that they require connectivity and a mobile user doesn't always have it. A mobile application must always be ready to degrade gracefully if no wireless network is available or the user is in an out-of-service area. This usually means queuing outbound calls and showing cached data. It may also mean prefetching data, possibly in the background, to have more information available for display when connectivity is lost or missing.
HTTP calls, however, should move the least possible amount of information to save bandwidth and connection costs. This means having a mobile-specific service layer that exposes methods tailor-made for the requests of the mobile application. Just the implementation of the service layer — the list of HTTP endpoints invoked directly from the device — sets the difference between an effective application and a poor application.
Aspect #5: Navigation within Data
One of the most characterizing traits of iPhone has been its ability to pan content horizontally through a natural gesture. The limited real-estate of mobile devices requires thoughtful analysis of the data layout. Scrolling data is easy for the user, but heavy for the application that needs to cache and hold in memory much more data. Your effort should be focused on finding a good balance between the number of items the application logic requires to display and the actual number loaded and displayed.
Caching provides an intermediate storage layer where the application can fetch data, thus saving the user a remote call. Caching is tightly coupled to the capabilities of the device (i.e., SD cards) and platform (i.e., API) that manage external memory. In terms of algorithms, the Predictive Fetch (PF) pattern is a powerful tool, as it suggests which information to download in advance. In general, PF is a tricky pattern because there's always the risk of downloading data that is never used. In a mobile scenario, however, data that is not used in the current session can be cached and used later or during offline behavior.
Aspect #6: State Management
As you may have guessed already, mobile applications are all about saving resources: bandwidth, screen real-estate, memory, CPU cycles, data entry, even user gestures. It is key for a mobile application to stay in sync with the user and intelligently save context and any possible data entered or manipulated along the way.
A golden rule of real-time systems states that any data that you can prove certain must be saved. This holds true for mobile systems as well, though for different reasons. If the user completed an action successfully, you might want to learn from that and automatically reuse some of the settings or data for later use. How this happens depends on the application, but in general, you must be clear on the state of the application at any given time.
Moreover, mobile applications are subject to be interrupted frequently: an incoming phone call, the user starts another application, the screen gets otherwise engaged, a notification comes in, or the user that hits the Home or Back key. These are all examples of events that may originate a change of state in the application, and a well-made application is always ready to save its current state to some storage to retrieve it later. An application that goes to the background can be killed instantaneously: Persisting context is something you want to do in some way.
Speaking of client-side storage, each platform has its own solution. A common denominator, however, exists in SQLite. You won't be able to reuse the data-access layer, but at least the structure of the storage, schema, and queries are the same.
Aspect #7: Sensitive Data
Associating the words "security" and "mobile device" forms a bit of an oxymoron. We want privacy, but we don't mind loaning other people our devices for a quick phone call. We want to protect our private data, but we dislike retyping passwords all the time. We want privacy, but we run location-aware applications. Security for mobile devices is all about reaching an acceptable balance between permissions, checks, and restrictions.
As an application developer, you must be concerned about a few things: leveraging the permission model of the OS, certifying your application, and storing sensitive data (i.e., credentials) securely. Generally, the permission model of the OS associates each operation with a security level. If the application didn't manage to get authorization for that level, the operation is denied. In its simplicity, the model is quite powerful because it forces developers to declare explicitly what an application will do. Intentions are packaged with the executable and displayed to the user during installation. Getting an application from the platform application's store offers another level of warranty to users and it ensures that the application has been certified as safe to use. But this doesn't necessarily mean that non-certified applications (i.e., Android applications) are unsafe.
What about managing sensitive data? Anything that is stored can be discovered, but required data that is not stored must be reentered. With mobile applications, it is common that credentials are typed once and cached until the application is removed or the user explicitly logs out. The overall model is very similar to authentication cookies in Web applications. How this is accomplished depends on the platform. In iOS, you have a system-provided dictionary — the Keychain object — that saves sensitive name/value pairs in a location inaccessible by applications and ignored by backups. In Android and Windows Phone 7, you may use the native API (internal storage in Android and isolated storage in Windows Phone 7) to store data in a way that makes it unavailable to any other application on the phone. For Android devices, however, this is not guaranteed if the phone is rooted and applications are allowed to access every fold of it. For this and other reasons, it is preferable that you manage to encrypt sensitive data.
Aspect #8: Background processing
All mobile platforms allow only one application at a time to control the device. When the user starts a new application, the one previously in the foreground goes to the background, ready to be resumed if the user returns to it via the Back button or starts a new instance. With iOS and Android, applications in the background are still live applications and can be resumed instantly when the user navigates back to them. However, the operating system reserves the right to kill background applications at any time.
In multitasking systems such as iOS and Android, background applications can get extra processing time by using a system-provided API (iOS) or triggering a UI-less service (Android). Background processing capabilities, however, are just for applications that need to keep on working while in background, or that may find it useful to perform low-priority tasks when idle — for example, prefetching data to keep warm for later.
For long-lasting operations, you have just one option: running them in the background through a secondary thread. Threads are supported in iOS, Android, and Windows Phone 7 even though what happens if the application is dismissed may be different in the various platforms.
The Road Ahead
Writing mobile applications for multiple platforms is challenging at the minimum. It involves learning and using radically different languages, understanding and mastering different architectures, and even using different computers. Does it make sense to invest time to study a common SDK? Probably not, if you're a developer or a small team of developers.
Beyond the logic of the application, the aspects discussed in this article apply to nearly any mobile application. Simply addressing these aspects clearly in the analysis helps a lot. At a minimum, in fact, you know what to look out for in each project. If you can also manage to grab data in the right format from the server, and if you can delegate the hard work to the server, then you may find yourself up to the task.
Today's mobile programming reminds programming in the 1990s. And what I'm hoping for are some big libraries (remember MFC?) for each major platform. Things are changing very fast though and, who knows, someone could soon come up with a more powerful meta-language and a virtual machine running compiled code. For the time being, I just refer to the eight apects previously discussed and reconsider the best approach for each new project I take.