Writing Mobile Code Essential Software Engineering for Building Mobile Applications [Electronic resources] نسخه متنی

اینجــــا یک کتابخانه دیجیتالی است

با بیش از 100000 منبع الکترونیکی رایگان به زبان فارسی ، عربی و انگلیسی

Writing Mobile Code Essential Software Engineering for Building Mobile Applications [Electronic resources] - نسخه متنی

Ivo Salmre

| نمايش فراداده ، افزودن یک نقد و بررسی
افزودن به کتابخانه شخصی
ارسال به دوستان
جستجو در متن کتاب
بیشتر
تنظیمات قلم

فونت

اندازه قلم

+ - پیش فرض

حالت نمایش

روز نیمروز شب
جستجو در لغت نامه
بیشتر
لیست موضوعات
توضیحات
افزودن یادداشت جدید











Solve Problems in the Right Order; Go Back If You Need To


Everything 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 Application


This 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 Else


If 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 Specification


Poor Example

Good Example

Banking Application

"Make the Web functionality of MyBankFoo's Web banking available online and offline for users with mobile devices."

This example does not specify what the most important functionality is. Is it the ability to check one's balance? Bill payment? Transition history? Transfers? Point-of-purchase transactions? Getting car loans and mortgages? What are the main things the user will need to do from a mobile device?

Banking Application

"1. Users should be able to access their bank balance from a mobile phone using one hand and in fewer than five clicks.

2. The user should be able to pay for and confirm purchases from vending machines using the device's infrared port in fewer than three clicks."

We have identified the two key scenarios we want to enable.

Survey Taking

"Replace using paper and clipboard for taking public surveys and manually keying in results."

What kinds of questions will be asked? When will the data be synchronized?

Survey Taking

"The application should enable users to collect public survey information onto a Pocket PC. Questions will be asked as multiple choice or simple numeric input and will be cached locally and sent to a server when the device is placed into a PC cradle. Up to 20 questions can be asked in a survey, and the results of up to 1,000 survey responses need to be stored on the device. No manual text entry will be required."

We have specified what kinds of questions the application needs to handle and we have specified how the device will be synchronized. (Importantly, when drawing up the list of scenarios, we don't care specifically how results are stored locally or what the specific synchronization mechanism is as long as the scenarios workthis will be important to our implementation but the end user does not care.) We have also specified what the application need not do well (that is, deal with free-form text).

Inventory Tracking

"A version of the desktop inventory tracking system will be made available for on- and offline mobile devices."

Porting a desktop or web-application's full functionality will almost never result in a satisfactory outcome.

Inventory Tracking

"The application is intended for use inside a warehouse with intermittent access to a Wi-Fi network.

"Inventory tracking information for up to 5,000 products must be stored for offline use on the device.

"Item IDs can be scanned in via a bar code reader.

"Items can be added and deducted from inventory.

Devices will synchronize using the Wi-Fi network when prompted by the user.

"Live, up-to-date access to a back-end database is required on demand.

"Key scenario: Scan in a box, specify whether the item is being added or deducted from inventory by clicking a button. Scan in a purchase order number from a form to associate with an inventory item.

"Key requirement: If bar code scanning does not work, the user must be able to quickly key in the numbers manually using touch screen and stylus. Failure of bar code scanning should be logged for performance and reliability tracking purposes."

We have specified what the key requirements are as well as the main scenario in which the application will be used.

Game/Learning Application

"Build a mobile device application that teaches users foreign language vocabulary."

What kind of dictionary capacity is required? What will the basic user experience be?

Game/Learning Application

"The application is a game that will test user's foreign language vocabulary skills.

"Users will be given multiple-choice questions on vocabulary that they can answer by clicking the screen.

"Up to 1,000 different vocabulary words can be stored on the device.

"Example sentences of all words must be stored on the device as well."

These are reasonable expectations for a learning game. We'll need to explore more about how the game will work, but we have the high-level input/output model defined and the data capacity specified.

Travel Application

"Store and manage all of the user's travel information and make it available offline on a mobile phone."

This is not specific enough about what the application will do or how the user will use the application.

Travel Application

"The user will be able to access e-ticket airplane reservations stored on the device. Reservation number, flight number, flight time, and airport information will be available on his mobile phone and will be able to be navigated to within three clicks. This information is intended to be quickly called up and handed to a worker at a check-in desk."

Step 1: Start with Performance, Stay with Performance


After 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]

In many cases, performance problems are systematic and application wide. Some systematic causes of poor performance are the ways data is moved into and out of memory, the number of resources held in memory at any given time, or the way the user interface draws and updates information on the screen. These kinds of performance problems are usually caused by fundamental design choices that can only be satisfactorily addressed early in the design and development process. The cost of moving on to "code compete" and later needing to re-architect your data-access strategy, redesign your memory usage model, or move work onto a background thread to speed up user interface responsiveness is huge. Even if you get late design changes to application code working, you will end up with messy spaghetti code. Real performance is built from the ground up.

Count on the fact that your application will continue to get bigger and more complex as you go along. You will write more code, create more objects, and have more components fighting for a finite pool of resources. If your mobile application has performance problems you do not address when they arise, they will get worse, not better, as your code base continues to grow. Moreover, as you add more code, additional dependencies will be introduced into the data model, the memory usage model, the user interface model, the communications model, and other logic you have written. You will be painting yourself into a corner.

A common, plausible, but deeply mistaken rationalization is, "I need to get all the code written before I can understand which parts of my application need to get tuned." This is badly flawed because it assumes that the separate parts of your application are somehow not interdependent. After you have written all of your application's code, you will have introduced a great many explicit and implicit dependencies between different systems and will very likely only be able to make incremental improvements without radical redesign. Even if you have taken pains to try to encapsulate your application design, this will inevitably be the case. More code equals more interdependencies; try to avoid this through good design, but also count on it being a fact of life. The time to address performance problems is when the code base is still fluid and open to re-architecture. The best time to do this is when the code is first written.

When a performance problem arises, stop and assess the situation and find out what is going on. Is the user interface being updated in an inefficient way? Is your application holding too much data in memory so that the garbage collector is constantly running? Is the processing you are doing of inherently long duration and a good candidate to be moved to a background thread so it can run asynchronously to the user interface? Are you working with a large amount of data using a higher-level stateful object model when a lower-level stateless programming model would be better? Identify the root causes of the problem and re-architect your code to fix these before writing more code that will depend on the assumptions you have made.

The result of adhering to a disciplined and performance-focused development process is that your application's code, data, and memory usage models will stay lean and the user interface design will stay clean and efficient.

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.


An Example of a Performance-Dictated User Interface


Both ActiveSync and Internet Explorer for Pocket PCs and smart phones offer user interface elements dedicated to keeping the end user informed of asynchronous requests that they have initiated. These keep the user interface responsive and the user engaged.

ActiveSync may need to initiate a phone call or other high-latency data connection to synchronize calendar information with a back-end Exchange. When it does so, the device's user interface shows a label that contains the current state of the communications attempt. The label shows text such as "Dialing phone ...," "Connecting to server," "Synchronizing schedule," "Downloaded 12 of 20," and so on. This simple user interface notification element offers no absolute performance gain, but it does keep users assured that progress is being made on their behalf and thus discourages users from aborting the request out of frustration.

Pocket Internet Explorer may also need to establish data connections, look up the IP addresses of URLs, and other tasks when downloading a Web page. When performing these latency-prone tasks, the browser window's caption is updated with text describing the communication's state. In addition, an animated Windows flag is displayed when Web content is being downloaded. Both actions keep the user informed that progress is being made.

In both cases, the user interface is kept responsive and users are offered the option to cancel the operation if they want to. Offering the option to cancel makes users feel empowered, and showing incremental progress makes them less likely to cancel. Certainly it would be best if these tasks could be made to happen instantaneously, but when this is not possible keeping the user interface responsive and keeping the user informed of progress is a good second best.

Step 2: Design the Right User Interface


As 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]

Designing the right user interface is the next on the stack of importance. Just as good performance is tailored to human perceptions, good user interface design is specific to the device being targeted. The optimum user interface for one class of mobile devices will not be the best user interface for another class. It pays to get specific.

Be prepared to iterate on the user interface's designparticularly if you are new to mobile device user interface design or if you are working with a new class of device that has a form factor different from other devices you have developed for in the past. As you gain experience working with a given device class, the user interface design process will become faster but you will still find the need to iterate to get things to look and feel right.

It is always a good design practice to separate your application logic from your presentation logic so that changes in user interface design do not ripple and cause the need for modifications to your application logic. This is doubly true for device design. If you can abstract your application logic from your presentation logic, you will be in a strong position to both (1) iterate and improve the user interface design for the device you are presently targeting, and (2) port the application to new classes of devices quickly. Today's handheld PDA application can easily be tomorrow's smart phone application if the user interface code is not woven deeply into the core of the application logic. Keeping application logic and user interface logic cleanly separated will pay great dividends both in code maintainability and code portability.

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 Right


Your 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]

Mobile devices have traded large memory pools and memory paging files for small size and low power consumption. The application running on a mobile device is no longer living in a large mansion but in a stylish condominium. The sport utility vehicle that your desktop applications are used to driving around in has been traded in for a motorcycle. Thinking of your application as living in a much smaller physical space is a good analogy to keep in mind as you are designing your mobile application's data and memory model.

To a large extent, desktop application programmers, other than those dealing with huge in-memory resources (for example, complex painting programs often work with huge matrices of data), tend not to think about memory models. For this reason, desktop applications tend not to do much systematic and proactive housecleaning with the data and resources they hold in memory. Whatever data is needed is eventually loaded into memory and very little is proactively discarded. Data and resources are kept loaded in memory out of laziness or just in case they may be needed by the user. If your application has gone to the trouble of downloading some data or images from a network resource, why not keep them around just in case the user wants to access them again? To a large extent this makes sense for desktop applications; in-memory data that is not used is eventually paged out of physical memory and onto the hard drive, and it is much quicker to page this data back in than it is to go to the network again and re-request it. The application has a huge house to work in, and unused things just get moved into the attic somewhere.

As discussed earlier in this book, the situation is markedly different for mobile devices. Given the finite-sized memory available and the dearth of secondary storage to page memory out to, developers must be mindful of the memory and resources they are using. It is imperative that mobile application developers have an explicit model that decides how much to keep in memory and when to discard things to be garbage collected. On devices, it is often the right strategy to discard data from memory or explicitly place it onto a flash storage card and reacquire the data into memory as needed.

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 Right


Your 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 Device


Almost 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 Format


Choosing 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 Abstraction


Programming 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 streams

Text streams

XML forward-only readers and writers

XML 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 Model


Which 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 Device


Other 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 Reliability


You 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 Model


As 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 streams

HTTP request/response

SOAP 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 Necessary


Modern 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]

An important part of good mobile software design is finding ways to discover the design problems that will inevitably crop up as early as possible and also designing your code in a modular and flexible enough way that it can accommodate needed redesign without becoming hopelessly tangled.

When designing and testing your communications model, you may uncover core problems in your design. You may discover that too much memory is being utilized, meaning that too much user data is being held in memory at one time, or the data is being held in an inefficient way. If you change the data model, it will likely have effects on the communications model that controls how data is brought into and out of longer-term storage. Data model and communications model changes may in turn necessitate design changes in the user interface. These changes may need to account for the fact that the amount of data in memory at any given time is different than previously assumed or that the way in which the data needs to be retrieved must be done differently than assumed to ensure a responsive user interface. Finally, in doing all of this learning, you may discover that some of the design objectives of the application must change. Alternatively, you may discover additional design objectives that have emerged through the use and testing of your application. Modern application development is iterative. Because mobile devices are brave new world to explore, expect to iterate more.

With all of these interrelationships between design stages, it is easy to get lost somewhere in the middle and just write a lot of spaghetti code to tie it all together and make patch-up design changes as required. You should avoid this temptation and use your own defined product milestones to keep the design process honest. Make it an explicit exit criterion for each milestone to rationalize your design. When exiting a development milestone, you should answer the following questions:

Are the key scenarios and features originally specified still valid or do they need to be redefined?

Does the user interface cleanly represent the scenarios and enable users to perform the most common actions with a minimum number of manual steps? Is the user interface highly responsive to the user? Is the user interface appropriate for the form factor of the device you are targeting?

Is the underlying data model for bringing objects into memory and discarding objects sound? Will it scale to the real-world data your users will use? Is it stable over time as the user brings the application through all of the possible states, requests additional data, or runs the application for weeks at a time?

Does the mobile application's communication model meet your needs? Are you using the highest level of abstraction that you can in your APIs and file formats?


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 Installation


For 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.


/ 159