Solve Problems in the Right Order; Go Back If You Need ToEverything is important, but some things are more important than others. In the mathematical analysis of functions, there are first-order effects, second-order effects, third-order effects, ..., nth-order effects. The lower the order, the more effect the term has on the behavior of the system; higher-order effects can often be discarded. So it is with mobile application development; you cannot concentrate on everything, so learn to concentrate on the things that matter most.Below are listed steps that show how to approach the most significant aspects of your mobile application's design. They are listed in order. As you make changes and iterate on your design, it is important to revisit the lower-order steps to make sure that the changes you make to solve specific problems do not cause unacceptable regressions. For example, it is possible to solve a communications problem in a way that affects the way users interact with data in the user interface; this may or may not be appropriate. If you change the communications model of your mobile application, it is important to examine how these changes affect the fundamental aspects that drive the end user's perception of your application. Step 0: Before You Start, Decide On the Scope of Your ApplicationThis is Step 0 because it really precedes the design and development work. Before you start drawing up plans and building software, you need to have a fundamental idea about what the result is going to be.A desktop application is like a wide-angle lens in that it typically shows a great deal of information and enables the user to explore a wide space. In contrast, a mobile application is like a magnifying glass or zoom lens. It enables the user to quickly zoom in on specific details, to enter and access a narrower range of data quickly, or to make decisions on a real-time basis. Mobile applications tend to represent a focused subset of the scenarios possible in a comparable desktop application. It is important to be specific about what scenarios your mobile application is going to zoom in on.Before starting the real application development, decide what your application is going to do and what it is not going to do. If you are creating the mobile version of a desktop application, define the subset of functionality that the user will be able to access quickly and in a mobile way. If you are building a new application that does not have a desktop analogue, write down the key scenarios users will perform with the application and how they will experience them through a mobile device. Drawing pictures or creating prototypes often proves helpful in fleshing out these scenarios. If there is a specific group of end users in mind, spend time with them and have them work with the mock-up applications to get you feedback. The Right Subset of Features Governs Everything ElseIf you clearly identify the key scenarios and features of your mobile application, it will guide the rest of your development. Having an explicit statement of how end users will use your application and a detailed understanding of the experience they should have will be invaluable in guiding the performance tuning as well as the design of the user interface, communications system, and memory model.If you do not specify the top scenarios and features, you will end up with a hodgepodge of features mixed into an application. Because the primary functions of the application have not been listed or prioritized, the user interface will not be optimized to perform the key tasks properly. For example, if entering dates is a key thing the user will need to do, you should optimize the user interface to make this as fast and reliable as possible. Conversely, if dates are rarely required to be entered, an unoptimized user interface for date entry may be acceptable and design and development resources should be expended elsewhere. Unless the most important scenarios are identified, listed, and agreed upon by the development team, the application's performance will not be tuned for these and features may well be cut that are important to the end user.To set up for success, write down the key requirements and features and make it the first section of your design document. Examples of Good and Poor Scenario SpecificationStep 1: Start with Performance, Stay with PerformanceAfter identifying the key features and scenarios for your application, your main concern should be the end user's experience when using your mobile application. This means designing and coding for performance and responsiveness.You should define general responsiveness metrics for your application. For example: "Bringing up a dialog should never take more than 0.5 seconds" or "A visual response to clicking a control should appear instantaneously" or "Expanding tree-view nodes should never take longer than 0.15 seconds." These are all good metrics to strive for.You should define specific metrics for your key scenarios. For example: "Loading inventory data should never stall the user interface for more than 0.2 seconds without bringing up a wait cursor" or "In no case should loading inventory data take more than 3 seconds." Test your assumptions in real-life usage scenarios. Even without real data or code in place, it is easy to put wait states into your application's skeletal user interface to test the effects of delays when the user performs common tasks. It is important to get a good feel for what is an acceptable wait time and what is unacceptable. Applications should always strive to offer immediate acknowledgement that an action is underway, even if the action cannot be completed immediately. Work can also be pushed to background threads if the work will take a long or indeterminate amount of time.As you are developing your application, use realistic sizes of data that reflect or exceed the likely usage by end users. A very common mistake developers make is using a small sample of data during development only to find out that the application performs terribly when used with actual amounts of real-world data. The sooner you can move to testing with real-world data, the sooner these problems will surface and the better the chance you can address and mitigate performance problems.Figure 4.1 shows a flowchart for mobile application development. If you hit a performance problem, stop! To restate this, when you hit a performance problem in your design and development, stop adding new code immediately! All too often, developers will continue coding, wanting to reach "code complete," with the promise of fixing performance problems afterward. This strategy is risky at best! It is rarely successful in desktop and server development and is usually quite painful; the results will be worse on devices. The reason for this is that performance problems are often not the result of a discrete algorithm that can simply be tuned or optimized without effects on other parts of the system. Until you can diagnose the problem in detail and prove that an alternative solution will fix it, you really have no idea how much redesign may be required to address the issue. You might get lucky, but luck has a way of running out pretty quickly for engineers who depend on it. Figure 4.1. A performance-driven methodology.[View full size image] ![]() Good Performance Allows a Good User Experience (Bad Performance Means None of the Subsequent Steps Will Matter)If you build a beautiful and intuitive mobile user interface, a clean and robust communications model, and a nice object-oriented data model but your application behaves poorly, end users will be frustrated. The very nature of mobile devices means that end users expect responsiveness. People carry them in their pockets and expect on-demand usage.It is important to understand that all performance is subjective. The user does not care how long it took to get the data, he only cares how long it appeared to take and what happened in the interval. This can be used to your advantage when designing applications. Long-duration operations are not necessarily bad as long as the application behaves in a way that makes users feel like they are in control and the application is responsive. The proof of performance is in real users' perceptions.Make the user's perception of performance your mobile application's primary development goal. It should come even before user interface design because important aspects of user interface design will be dictated by performance needs. For example, assume your application has a user-requested operation that will take 20 seconds to complete. Because 20 seconds is a long time for a user interface to remain unresponsive, your mobile application should probably push this work into a background thread so that the user interface remains interactive while the request is being processed. If this is the case, you may want to devote a portion of the user interface real estate to giving your users status information on the ongoing operation so that they know the request is underway and is progressing. Step 2: Design the Right User InterfaceAs discussed above, before commencing a mobile application's design it is important to identify the key scenarios and features that define the scope of the application. Following this committing to a performance-oriented development process will ensure you do not code yourself into a corner. If you cannot make the scenarios and features you have chosen perform well, it is back to the drawing board. Figure 4.2. Performance-driven user interface development[View full size image] ![]() A Good User Interface Means Happy Users (A Bad User Interface Means Growing Frustration Daily)The keys to user interface design are end-user productivity and responsiveness. It is important that the primary scenarios of a mobile application can be accomplished quickly by users. For example, if calendar dates need to be entered frequently by end users, this should be made as quick, simple, and as predictive as possible. Alternately, if users commonly need to be able to select an item from a large list of related items, the quickest way may not be to place all the items in a single ListBox but rather to design a custom graphical user interface that helps guide users as quickly as possible to the right item. A list of car parts may benefit from a graphic of a car that the user can tap on. Similarly, a medical application may benefit from a human body graphic that users can select body locations on. The correct user interface is dependent on the task at hand and the specific device on which the application is being run. This is why the "write once, run anywhere" user interface concept tends to fall short on devices. "Write once, run anywhere" approaches are just not focused enough to provide a great experience on a broad set of devices that have different display and input capabilities.Closely related to productivity is responsiveness. The user interface for a mobile device must respond crisply. This is not to say that the user cannot be left waiting; this is sometimes unavoidable. However, the user should never be left guessing whether the action they just requested is underway or if they need to try again. A sluggishly behaving handheld device can be a frustrating thing to use because there is a great psychological expectation that things will happen when you push buttons, tap screens, or otherwise interact with something that fits in your hand. Step 3: Get Your Data and Memory Model RightYour mobile application's data and memory models determine how the objects and resources that are currently held in memory are managed. Conversely, these models also determine how your application discards data and resources to allow space to be reclaimed for application usage. Mobile devices differ markedly from their desktop counterparts in the need for efficient data and memory management. Figure 4.3. Performance-driven data and memory model design[View full size image] ![]() A Good Data Model Means Good Performance and Flexible Design (A Bad Data Model Means Locked-In Bad Performance)If there is a specific art to building great mobile applications, this is an important part of it. Being a good memory and resource manager means three things: (1) the learned ability to cleverly keep what is vital and immediately useful in memory, (2) finding ways to cache important data on the device but out of active memory, and (3) relegating the rest of the data to storage off the device. If you can acquire the ability to do these three things, you will be well along the road to designing great performing applications that users love to use. Step 4: Get Your Communications and Input/Output Models RightYour communications and input/output models determine the way in which your application communicates with resources outside of its process. These can be either resources local to your device, such as on-device files and local databases, or resources residing external to your physical device, such as those accessed via sockets-based communication, files on servers, Web services, and remote databases. How your application communicates with both local and remote resources will have a great effect on users' perception of your application and so ranks high on the list of things to incorporate into your development methodology. Figure 4.4. Performance-driven communications design[View full size image] ![]() Working with Resources Local to Your DeviceAlmost any application that maintains long-term information for the user does so by storing and retrieving information locally on the device. The most important considerations for working with device local data are data format and the level of programming abstraction used to work with that data. Data FormatChoosing the format to store your data in is generally a balance between efficiency and convenience. Any given data can be stored in binary files, plain-text files, XML text files, or in the structured tables of a local database. Efficiency means minimizing size and maximizing performance. Convenience means maximizing developer productivity, code maintainability, minimizing the testing burden, enabling data interoperability between applications, and maintaining flexibility for augmenting the data format in the future.Binary storage formats offer the greatest possibilities for both size reduction and performance. For this reason, dense data such as images are most often stored in binary formats. So specialized are the needs for storing image data that several popular image formats are available that each offer trade-offs with size, performance, and fidelity. Each binary image format is geared toward a specific set of needs. Beyond images, any data can be stored in a binary format. However, binary data is hard to work with; if you are creating your own binary formats, both data versioning and interoperability with other applications will be problematic.Text storage formats offer the greatest ease of use and interoperability potential because they are readily decipherable. However, text files are verbose compared to their binary counterparts. XML is even more verbose than simple text because it adds schema information to the text data. This added schema meta data greatly increases versioning and interoperability flexibility, but at the expense of using more space. In addition, XML requires more processing to parse in and write out compared to simple comma- or tab-separated data in text files. Flexibility has a cost. This cost can be reduced by using intelligent implementation strategies, but it cannot be eliminated.Databases offer the highest amount of data organization but bring with them the overhead of a database engine. Levels of Programming Model AbstractionProgramming models for working with stored data usually are available in several layers. For example, when working with files in the .NET Compact Framework, the following increasing levels of abstraction are offered:Binary streamsText streamsXML forward-only readers and writersXML Document Object Model (DOM) Each of these layers offers an increasing level of abstraction to make working with data easier, but does so with increased overhead. Sometimes this overhead is negligible and well worth the developer productivity and robustness that high-level pretested APIs provide. Other times, particularly when working with large amounts of data, the higher-level abstractions introduce added memory and processing requirements that are unacceptable. In these cases, developers should go one level lower in the API stack and try to solve their problems using a lower-level API that has lower overhead. It is important to understand the overhead associated with each increasing level of abstraction. Choosing the Right Storage Format and Programming ModelWhich data format to use for your data is entirely dependent on the goals of your application; there is no universal right answer. A common mistake developers make when approaching mobile device development is to assume that because resources are more limited they should jump right to the lowest level of abstraction and use binary files and stream-based file I/O. In some cases, this may indeed be required, but in most cases it is just taking on unnecessary work that will require additional testing and probably yield an inferior and inflexible result. A general rule of thumb is that you should use the highest level of abstraction that you can afford size and performance wise. For relatively small amounts of data, it is foolish to invent your own binary format because XML is a fantastic choice for moderate storage needs. XML is easy to work with, is robust for versioning needs, and good higher-level APIs exist to make programming easy. Similarly, if a binary format is truly needed, such as for the storage of large image data, there is great benefit in using an already existing and well-proven format if one exists. Because there are several well-proven image formats, it would generally be a waste to invent your own. Reuse and utilize existing components and formats whenever possible; invent your own only when you have proven that higher-level approaches will not work. Working with Resources External to Your DeviceOther than simple games and basic productivity applications such as calculators, most interesting mobile device applications have some interaction with data that is off of the device. This data may be in a database that is replicated onto the device. It may be an on-device address book that is synchronized with an e-mail server. It may be images or music that are downloaded from the Web, from a desktop PC, or "beamed over" from another device. SMS messages arrive on mobile phones and are sent by them. XML data is pushed to and pulled from Web services. Data may be accessed over a Wi-Fi network, transferred via a flash memory card plugged into a device, sent over a GPRS mobile phone connection, beamed via infrared, or just plain sent over an Ethernet cable plugged into a device. In short, there is a great variety in the types of data that can be communicated and the means by which it can be transferred.Having decided the set of key scenarios your mobile application is going to enable, having dedicated yourself to be performance driven in your development, having prototyped the user interface that will enable the user to interact with the application, consideration must then be given to the communications model.Of greatest importance to defining the communications model is to look at the scenarios you have defined and determine what communication is required to enable these scenarios. Some key questions to ask include the following:Is a connection to live data required all the time or only intermittently?How much data needs to be moved around? This may affect your other choices.How will data be moved back and forth? Via a wireless network connection? A cradle to PC connection? A flash memory storage card?What is the cost structure for the communication? Whereas Wi-Fi on an intranet costs nothing, mobile network usage is usually billed by metering the size of the data transferred. Performance and ReliabilityYou should assume that mobile network communication will fail often and at the most inconvenient time for users. Even if the device is plugged into a network directly with a cable, it is appropriate to take a defensive approach and assume that the server will go down; the cable will get cut; proxy servers, NATs, routers, and firewalls will randomly conspire against you; and that little gremlins sit in the hardware and will attack your data packets with tiny hammers to prevent them from getting to their destination. A healthy dose of skepticism bordering on paranoia will be rewarded. Assume anything that will make you design defensively and deal robustly with the reality of intermittent communications failures and unexpected problems.Most everyone has seen desktop and server applications occasionally stall because a needed network resource was unavailable. Usually the application in question either hangs or sits stuck for what seems an interminable amount of time before it finally times out and returns control to the user. In mobile devices, the situation is invariably worse. Trains go into tunnels and elevator doors shut blocking previously available signals without warning the running mobile application. Phone calls get interrupted between cell towers, Wi-Fi base stations get unplugged, and sometimes things just plain go wrong for reasons that often remain unfathomable.Hopefully I have made some progress in convincing you that defensive coding is in order. The ways to facilitate this are as follows:Perform all network-oriented operations in an asynchronous way that allows the user interface to remain responsive and enables users to cancel the request and move on with their work.Wrap all network access routines in try/catch blocks (that is, structured exception handing). Assume that all of these catch blocks will get run occasionally, and simulate this situation in your application's design and testing to see how your error handling code responds. It is appropriate that an exception should get thrown when a network connection intermittently fails; it is equally appropriate that your code should catch these intermittent exceptions and deal robustly with them on the user's behalf. Accessing networked resources makes mobile applications vastly more powerful, but also inherently introduces elements that are outside your control into the application. It is fundamental that your mobile application deal robustly with the very real likelihood that any external access will fail unexpectedly or will take an unacceptable amount of time to complete. Dealing with these situations gracefully will go a long way into making your mobile application look and work great. Your end users will thank you or at the least will not curse your name when "the network goes down." Levels of Abstraction in the Programming ModelAs with local device data, several layers of abstraction exist for working with networked resources. For example, the .NET Compact Framework offers the following layers of APIs for working with networked data:Sockets with streamsHTTP request/responseSOAP engine Each of these levels of increasing abstraction offers successively more convenience and the robustness of pretested infrastructure. As with device local communication, you should choose the highest level of abstraction that you can afford and only move to lower levels of abstraction when you prove that the higher levels cannot be adapted to meet your needs. Using lower-level programming models means more explicit control over what is going on and the maximum flexibility, but this comes at the cost of complexity, interoperability, and the need for more dedicated testing. Know also that even the lowest levels of abstraction will not give you full control; your mobile application will always have to deal with network failure, and often this can be more complicated when working with lower levels of abstraction. There is a reason why developers have moved from assembly language to higher-level languages for all but the most specific low-level tasks, and this same line of reasoning should apply to your choice of communications programming model. More abstract is almost always better. Go Back to Steps 0, 1, 2, and 3 As NecessaryModern development is an iterative process. This is particularly true for mobile device development. Based on your level of skill and experience, you will make the best initial decisions you can and you will revise them as needed. Experience with mobile development will make your initial decisions better, but it will not make them perfect. There will always be one more unanticipated design problem lurking that will force you to reevaluate your design and make tweaks or in many cases radical changes. Much of the rest of this book focuses on giving you the knowledge and insights necessary to make the best possible initial design decisions while giving you the engineering skills that allow you to leave the door open to revising designs as needed. Figure 4.5. Revisit your previous deign as needed to address performance concerns[View full size image] ![]() All of your design decisions need to be grounded in a fundamentally performance-oriented design philosophy. If your application is not meeting performance requirements at any point in its design, stop coding! Stop coding! Stop coding! And immediately work to understand what the performance bottlenecks are and resolve them before moving on. This is important at any stage of the design but should be mandatory at the end of any of the coding milestones you set. As your application development proceeds toward its completion, design changes should become less frequent and will become harder to make because of inherent interdependencies between code modules that have been written. Plan on lots of early iteration and early design changes and fewer and fewer changes as your design moves through different milestones and the code becomes more mature. Step 5: Packaging Your Application for InstallationFor mobile devices, packaging and installation is often referred to as provisioning. This step should be listed under the category heading of "last but certainly not least" because like the other steps it will require iteration to get it right. Thought must be given to what pieces need to be deployed for your application to run on its target devices, how users will accomplish this, and how the application will be updated in the future. Here are a few important design questions for thinking about your mobile application's provisioning strategy:What gets deployed with your application? Is the application a single binary executable file or does the application have additional data files that get installed with it such as images, text files, database files? Should and can any of these files be folded into the application's binary file as resources to simplify deployment? Does the application require other runtime libraries or components to be installed with it onto the device?How does the application get deployed onto a device? Is the application installed directly onto a device via a networked connection? Is the application installed via a desktop PC with the device tethered to it via a cable? Is the application installed onto a device via a storage card that is inserted into the device? Is the application beamed from one device onto another via an IrDA port, facilitating peer-to-peer distribution?Who will be deploying the application? Will it be end users? Are the end users familiar with the target devices and their installation procedures? Will corporations be deploying the application on their employees' devices? Will the application be deployed by a mobile telephone operator or downloaded from the Web?How will the application be versioned? Will the application itself periodically check for new versions from a network location? Will a server scan devices to see whether they need a new version installed? Will new versions be installed when the device is placed into a cradle?Are there security implications? In any widely deployed application, there are always security implications that need to be considered. Does the application need to get signed? Does the data that the application works with need to be secured in some way? What happens to the data on a device if the device is lost or stolen? Due to the large variety of mobile devices and networking models for devices, there is no single right answer. The best solution will depend on the type of the device, how it connects with the network, what the desired user experience is, and what the policies the network operators that may control access to the device may have.A provisioning plan for your application should be written down on paper and added to your application's scenarios list. It is also highly desirable to place the development and testing of real-world packaging and install into an early development milestone for your application. Modern development environments do a great job of installing your application right onto the device for testing, but end users will usually not be using your development tool to install their application. Practical experience has shown that end-user deployment is always an issue. |