Текст книги "Программирование мобильных устройств на платформе .NET Compact Framework"
Автор книги: Иво Салмре
Жанр:
Программирование
сообщить о нарушении
Текущая страница: 13 (всего у книги 69 страниц)
Выбор коммуникационной модели, а также модели ввода-вывода определяет, каким образом ваше приложение будет связываться с ресурсами, хранящимися вне текущего процесса. В качестве таковых могут выступать либо локальные ресурсы устройства, например, хранящиеся на нем файлы и базы данных, либо ресурсы, являющиеся внешними по отношению к физическому устройству, например такие, доступ к которым осуществляется посредством связи через сокеты, или же такие, как файлы на серверах, Web-службы и удаленные базы данных. Выбор способов, используемых приложением для связи как с локальными, так и с удаленными ресурсами оказывает большое влияние на восприятие приложения пользователями, и поэтому занимает одно из ведущих мест в списке всего того, что должно быть включено в вашу методологию разработки.
Работа с локальными ресурсами устройства
Почти все приложения, способные предоставлять пользователю информацию, хранящуюся в течение длительного времени, обеспечивают эту возможность путем локального сохранения и извлечения информации на устройстве.

Рис. 4.4. Проектирование коммуникационной модели, ориентированное на достижение высокой производительности
Наиболее важными факторами, оказывающими влияние на работу с локальными данными устройства, являются формат данных и уровень абстракции программной модели, используемой для работы с этими данными.
Формат данных
Вообще говоря, формат, в котором хранятся данные, выбирается на основе компромисса между требованиями эффективности и удобства использования. Любые конкретные данные могут храниться в виде двоичных файлов, простых текстовых файлов, текстовых XML-файлов или в виде структурированных таблиц локальных баз данных. Требования эффективности означают минимизацию размера данных и обеспечение максимально возможной производительности приложения. К числу требований удобства использования относятся максимально возможное повышение производительности труда разработчика, улучшение условий сопровождения кода, минимизация объема необходимого тестирования, обеспечение возможности обмена данными между приложениями и гибкость формата, обеспечивающая возможность его последующего расширения.
Двоичные форматы хранения данных предлагают самые широкие возможности как в отношении снижения размера данных, так и в отношении повышения производительности приложения. По этой причине данные, характеризующиеся большой плотностью информации, например, изображения, чаще всего сохраняются в двоичных форматах. Потребности в сохранении данных изображения настолько специфичны, что для этого имеется целый ряд популярных форматов, каждый из которых предлагает свой вариант достижения компромисса между размером данных, производительностью и точностью передачи изображения. Каждый из двоичных форматов изображения отвечает определенным запросам. Двоичный формат может использоваться для хранения не только изображений, но и данных произвольной природы. Однако работать с двоичными данными труднее; если вы создаете собственные двоичные форматы, то у вас появятся заботы, связанные с необходимостью учета различий в версиях данных и обеспечением возможности использования этих данных другими приложениями.
Хранение данных в текстовых форматах значительно облегчает их использование и расширяет возможности их переноса в другие приложения, так как декодировать их легче. Однако размеры текстовых файлов больше по сравнению с их двоичными аналогами. Размеры XML-файлов оказываются еще большими, чем размеры обычных текстовых файлов, поскольку текстовые данные в них дополняются информацией о схеме данных. Эти дополнительные метаданные схемы значительно повышают гибкость данных в отношении учета их версий и переносимости в другие приложения, но требуют использования дополнительного пространства. Кроме того, при чтении и записи XML файлов их необходимо дополнительно пропускать через синтаксические анализаторы, что усложняет их обработку по сравнению с обычными текстовыми файлами, в которых для разделения данных используются запятые или символы табуляции. Отмеченная гибкость достается за счет дополнительных накладных расходов. Эти дополнительные расходы можно снизить, используя разумные стратегии реализации, но полностью избавиться от них невозможно.
Базы данных предлагают наивысшую степень организации данных, однако привносят с собой дополнительные накладные расходы, связанные с выполнением процессора базы данных.
Различные уровни абстракции программной модели
Обычно программные модели, предназначенные для работы с сохраненными данными, имеют несколько уровней. Так, для работы с файлами в .NET Compact Framework предлагаются следующие уровни абстракции, перечисленные в порядке их повышения:
■ Двоичные потоки.
■ Текстовые потоки.
■ Объекты однонаправленного чтения и записи XML.
■ Объектная модель документов (DOM) XML.
Каждый из указанных уровней предлагает все более высокий уровень абстракции для облегчения работы с данными, что связано с соответствующим увеличением накладных расходов. В некоторых случаях эти накладные расходы пренебрежимо малы и вполне оправдывают то повышение производительности труда разработчика и степени надежности, которое обеспечивают протестированные высокоуровневые API интерфейсы. В других случаях, особенно при работе с большими объемами данных, высокоуровневые абстракции выдвигают такие дополнительные требования к памяти и процедуре разработке, которые являются неприемлемыми. В подобных случаях разработчикам следует переходить на один уровень абстракции ниже в стеке API-интерфейсов и попытаться решить возникшие проблемы с использованием API-интерфейса более низкого уровня, который характеризуется меньшими накладными расходами. Важно уметь оценивать, какие накладные расходы связаны с применением того или иного уровня абстракции.
Выбор формата хранения данных и программной модели
Какой формат данных следует использовать для хранения данных – целиком зависит от целей вашего приложения; никакого универсального рецепта здесь не существует. Распространенной ошибкой тех, кто только приступает к разработке программного обеспечения для мобильных устройств, является допущение о том, что, поскольку в этом случае приходится иметь дело с ограниченными ресурсами, следует сразу же переходить на самый низкий уровень абстракции и использовать двоичные файлы наряду с потоковыми операциями файлового ввода-вывода. Иногда необходимость в этом действительно существует, но в большинстве случаев это просто означает выполнение ненужной работы, которая потребует дополнительного тестирования и, вероятно, приведет к худшему решению, не обеспечивающему достаточной гибкости. Общее правило заключается в том, чтобы использовать наивысший уровень абстракции, допустимый с точки зрения размера данных и достигаемой при этом производительности. Было бы неразумно изобретать собственный двоичный формат для данных сравнительно небольшого объема, поскольку при средних запросах памяти лучшего варианта, чем XML, не найти. С XML легко работать, он обеспечивает надежную работу с различными версиями данных и для него существует высокоуровневый API– интерфейс, упрощающий процесс программирования. Точно так же, в случае возникновения действительной необходимости в двоичном формате, например, для хранения больших объемов данных, описывающих изображения, гораздо предпочтительнее воспользоваться уже имеющимися и проверенными на практике форматами, если таковые имеются. Поскольку существует целый ряд хорошо зарекомендовавших себя форматов изображения, изобретение собственного формата будет, как правило, напрасной тратой времени. При любой удобной возможности старайтесь использовать уже существующие компоненты и форматы данных; изобретайте свои собственные форматы лишь в тех случаях, когда вы убеждены, что высокоуровневые подходы не сработают.
Работа с внешними по отношению к устройству ресурсами
Не считая простейших игр и элементарных приложений вспомогательного характера наподобие калькуляторов, большинство представляющих интерес приложений для мобильных устройств, так или иначе, взаимодействуют с данными, хранящимися за пределами устройств. Эти данные могут находиться в базе данных, реплицируемой на устройстве. Они могут содержаться в хранящейся на устройстве адресной книге, синхронизируемой с электронным почтовым сервером. Ими также могут быть изображения или музыкальные файлы, загруженные с Web или настольного компьютера или "полученные" от другого устройства через инфракрасный порт. Пользователи мобильных телефонов обмениваются SMS-сообщениями. XML-данные передаются Web-службам и принимаются от них.
Доступ к данным может осуществляться через сеть Wi-Fi, данные могут передаваться посредством флэш-карты, вставленной в устройство, пересылаться при помощи мобильных телефонов с использованием протокола GPRS, передаваться через инфракрасный порт или просто пересылаться по Ethernet-кабелю, подключенному к устройству. Короче говоря, существует множество самых различных типов данных, которыми устройства могут обмениваться, и средств, обеспечивающих передачу этих данных.
Остановив свой выбор на нескольких сценариях, выполнение которых будет обеспечивать ваше приложение, проникнувшись решимостью не забывать в процессе разработки приложения о необходимости обеспечения высокой производительности, подготовив прототипы пользовательского интерфейса, который предоставит пользователю возможность взаимодействовать с приложением, вы должны уделить внимание выбору коммуникационной модели.
В процессе разработки коммуникационной модели вы должны обязательно обратиться к имеющимся основным сценариям вашего приложения и определить, какие именно соединения потребуются для активизации этих сценариев. К числу вопросов, на которые вы должны дать ответы, относятся следующие:
■ Должно ли быть подключение к источникам актуальных данных постоянным или оно будет требоваться лишь время от времени?
■ Какие объемы данных потребуется перемещать? От ответа на этот вопрос могут зависеть другие ваши решения.
■ Каким образом будет осуществляться обмен данными? Посредством беспроводного сетевого соединения? Посредством лотка ПК? Посредством карты флэш-памяти?
■ Какова структура расходов на обеспечение соединений? Поскольку за использование сети Wi-Fi в составе интрасети ничего платить не надо, плата за использование мобильных сетей обычно взимается в соответствии с объемом передаваемых данных.
Производительность и надежность
Вы должны исходить из того, что в мобильных сетях соединения часто разрываются, и, как правило, это происходит в самый неподходящий момент. Даже если устройство подключено к сети непосредственно через кабель, все равно следует подумать о мерах предосторожности, заранее предполагая, что случиться может все что угодно: сервер может выйти из строя, кабель может порваться, прокси-серверы, преобразователи сетевых адресов, маршрутизаторы и брандмауэры могут внезапно "организовать против вас заговор", а некие противные маленькие злые гномики могут проникнуть в "железо" и атаковать ваши пакеты данных крохотными молоточками, чтобы не дать им дойти до пункта назначения. Разумная доля скептицизма, граничащая с паранойей, сторицей себя окупит. Заблаговременно предполагайте любые мыслимые и немыслимые ситуации, лишь бы ваше приложение было надежно защищено, и трезво подходите к реалиям работы в условиях сбойных соединений и возникновения непредвиденных затруднений.
Большинству из нас приходилось сталкиваться с тем, что выполнение приложения на сервере или настольном компьютере на некоторое время приостанавливается из-за недоступности сетевого ресурса. Обычно такое приложение либо зависает, либо не подает признаков жизни в течение времени, которое тянется целую вечность, пока, наконец, управление не будет вновь возвращено пользователю. В случае мобильных устройств ситуация заведомо худшая. Поезда заходят в туннели, а двери лифтов захлопываются, в результате чего сигналы, которые до этого были доступными, блокируются, но никаких предупреждающих сообщений об этом выполняющееся мобильное приложение получить не может. Пропадает связь между отдельными ячейками сотовой связи, отключаются базовые станции сетей Wi-Fi, и вообще, иногда бывает так, что что-то просто идет наперекосяк по каким-то необъяснимым причинам.
Надеюсь, я был достаточно убедителен, чтобы вы прониклись убежденностью в необходимости написания соответствующих кодов, защищающих приложение от подобных неприятностей. Существуют способы, которые облегчают решение этой задачи:
■ Выполняйте все сетевые операции в асинхронном режиме, что позволит сохранить постоянную готовность пользовательского интерфейса к отклику и предоставит пользователям возможность в необходимых случаях отменить запрос и заняться другой работой.
■ Поместите все процедуры доступа к сети в блоки try/catch (то есть организуйте структурную обработку исключений). Исходите из того, что время от времени будет выполняться каждый из этих catch-блоков, и имитируйте эти ситуации в процессе проектирования и тестирования приложения, чтобы проверить, правильно ли реагируют на возникновение исключений предусмотренные для них обработчики. Целесообразно предусмотреть, чтобы исключения возбуждались при любых периодических нарушениях связи; точно так же, целесообразно перехватывать подобные исключения и обрабатывать их так, чтобы это облегчало работу пользователя.
Доступ к сетевым ресурсам намного расширяет возможности мобильных приложений, но при этом неизбежно привносит в ваше приложение элементы, контролировать которые вы не в состоянии. Очень важно, чтобы мобильное приложение могло надежно вести себя в тех весьма реальных ситуациях, когда попытка получения доступа к внешним ресурсам оказывается неудачной или может быть завершена лишь в течение недопустимо длительного времени. Если вы предусмотрите корректную обработку ситуаций подобного рода, то ваше приложение от этого значительно выиграет, и будет не только отлично работать, но и лучше восприниматься пользователями. Пользователи будут благодарны вам или, по крайней мере, не будут честить ваше имя при появлении сообщения наподобие "соединение с сетью отсутствует".
Уровни абстракции программной модели
Как и в случае локальных данных устройства, при работе с сетевыми ресурсами также используются несколько уровней абстракции. Так, в .NET Compact Framework предлагаются следующие уровни API-интерфейсов для работы с сетевыми данными:
■ Сокеты, использующие потоки.
■ Запросы/ответы HTTP.
■ Механизм SOAP.
Каждый из этих уровней абстракции, перечисленных в порядке их повышения, последовательно предлагает все более удобную и надежно протестированную инфраструктуру. Как и в случае локального обмена данными на устройствах, вы всегда должны выбирать наивысший из приемлемых для вас уровней абстракции и переходить к более низким уровням лишь тогда, когда убеждены, что более высокие уровни не в состоянии удовлетворить ваши запросы. Использование более низкоуровневых программных моделей означает более непосредственный контроль над тем, что происходит, и обеспечивает максимальную гибкость, но это достается за счет увеличения сложности кода, уменьшения возможностей переноса приложения на другие платформы и необходимости выполнения более тщательного тестирования. Вы также должны знать о том, что даже нижайшие уровни абстракции не предоставят вам возможности полного контроля; ваше приложение всегда должно будет каким-то образом справляться со сбоями в сети, а на низких уровнях абстракции это часто сделать сложнее. Должны же иметься веские причины того, что во всех случаях, кроме самых специальных низкоуровневых задач, разработчики вместо языка ассемблера используют языки более высокого уровня, и точно так же должны рассуждать и вы, выбирая коммуникационную модель для своего приложения. Выбору более высоких уровней абстракции следует отдавать предпочтение почти во всех случаях.
При необходимости вернитесь к шагам 0, 1, 2 и 3Современная разработка является итеративным процессом. Это особенно справедливо в отношении разработки приложений для мобильных устройств. Исходя из своей квалификации и опыта, вы принимаете первоначальные решения, которые кажутся вам наилучшими, и при необходимости впоследствии пересматриваете их. Наличие опыта проектирования приложений для мобильных устройств поможет вам принять лучшие решения, но никогда не сделает их идеальными. Всегда вкрадется какая-нибудь непредвиденная проблема, которая вынудит вас заново пересмотреть свой проект и внести в него небольшие уточнения или, как это часто случается, радикальные изменения. Значительное место в оставшейся части книги отводится тому, чтобы научить вас с самого начала принимать наилучшие решения и одновременно привить необходимые технические навыки, которые позволят оставить открытыми двери для пересмотра проекта, если это потребуется.
Хороший проект мобильного программного обеспечения должен в обязательном порядке предусматривать обнаружение проблем, появления которых вам не избежать, уже на самых ранних стадиях разработки и ориентировать на создание кода, обладающего достаточно модульной и гибкой структурой, чтобы при необходимости в него можно было внести изменения, не рискуя безнадежно запутаться.
Приступив к проектированию и тестированию коммуникационной модели, вы можете обнаружить, что в проекте были допущены существенные просчеты. Может оказаться, что расходуемый объем памяти слишком велик, а это означает, что либо количество данных, одновременно хранящихся в памяти, слишком большое, либо их хранение организовано недостаточно эффективно. Вероятнее всего, изменение модели данных окажет влияние на коммуникационную модель, управляющую тем, как именно будет осуществляться обмен данными с долговременным хранилищем. В свою очередь, внесение изменений в модель данных и коммуникационную модель может повлечь за собой необходимость пересмотра пользовательского интерфейса. Возможно, при внесении этих изменений вам придется учесть тот факт, что количество данных, одновременно находящихся в памяти в любой момент времени, превышает то, которое допускалось ранее, или же что для обеспечения желаемой степени интерактивности пользовательского интерфейса способ извлечения данных должен быть изменен по сравнению с первоначально предполагаемым. Наконец, в ходе этого процесса вы можете обнаружить, что некоторые из целей приложения, предусмотренные проектом, должны быть изменены. Возможен и другой вариант, когда в результате использования и тестирования приложения обнаруживается, что состав его проектных целей должен быть расширен. Современная разработка приложений носит итеративный характер. Поскольку мобильные устройства представляют собой новый и еще не до конца исследованный мир, они потребуют еще большего итерирования.

Рис. 4.5. Пересмотрите предыдущие шаги проекта, если это необходимо для устранения проблем производительности
В попытках согласовать между собой результаты, получаемые на различных стадиях разработки, легко потеряться где-то посередине и начать писать код, значительная доля которого, связывающая его отдельные части между собой, будет походить на запутанный клубок спагетти, а необходимые проектные изменения будут выглядеть как заплаты. Вы должны избегать подобного соблазна и использовать собственные контрольные этапы, которые помогут вам сохранить целостность процесса проектирования. В явном виде определите критерии завершения таких этапов, что позволит рационализировать процесс проектирования. По завершении контрольного этапа разработки вы должны дать ответы на следующие вопросы:
■ Остаются ли в силе намеченные вами первоначальные ключевые сценарии и набор возможностей приложения или они должны быть переопределены?
■ Способен ли пользовательский интерфейс точно представлять указанные сценарии, и дает ли он пользователям возможность выполнять наиболее распространенные операции при минимальном количестве манипуляций вручную? Сохраняет ли пользовательский интерфейс способность в любой момент реагировать на действия пользователя? Соответствует ли пользовательский интерфейс форм-фактору устройства, являющегося целевым?
■ Работоспособна ли базовая модель данных, в соответствии с которой объекты загружаются в память и выгружаются из нее? Обеспечивает ли она масштабирование до тех реальных объемов данных, с которыми столкнутся ваши пользователи? Будет ли эта модель вести себя достаточно стабильно в процессе того, как пользователь своими действиями заставит приложение побывать во всех возможные состояниях, запросит дополнительные данные или запустит приложение, предоставив ему возможность выполняться непрерывно в течение многих недель?
■ Удовлетворяет ли коммуникационная модель мобильного приложения вашим требованиям? Используете ли вы наивысший из уровней абстракции API– интерфейсов и форматов файлов, который является для вас приемлемым?
В основе всех ваших проектных решений должна лежать философия, в которой во главу угла ставится достижение высокой производительности приложения. Если какой-либо из пунктов проекта вашего приложения не в состоянии обеспечить выполнение этого требования, прекратите дальнейшее написание кода! Прекратите написание кода! Прекратите написание кода! Затем немедленно займитесь выяснением того, какие именно факторы приводят к снижению производительности, и, прежде чем двигаться дальше, решите связанные с этим проблемы. Это замечание играет важную роль на любой стадии проекта, но его необходимо обязательно учитывать на завершающей стадии и во всех контрольных точках проекта, которые вы для него определили. По мере приближения процесса разработки приложения к своему завершению внесение изменений должно требоваться реже, да и делать это уже будет труднее, поскольку между написанными к этому времени модулями кода установятся всевозможные зависимости. Предусмотрите в своих планах, что на ранних стадиях проекта вы будете множество раз возвращаться к критическому пересмотру принятых ранее решений и вносить изменения, тогда как по мере прохождения вашим проектом контрольных точек и приближения кода к его окончательному виду необходимость в таких изменениях будет постепенно уменьшаться.







