Признак плохого дизайна №1: Наличие объекта бога с именем, содержащим «Менеджер», «Процессор» или «API».
Ведущий iOS-разработчик Redmadrobot Егор БепТеп Тафланиди рассказывает о том, как добиться гармоничного архитектурного дизайна мобильного приложения, используя классические шаблоны проектирования и логическое разделение исходного кода на модули.
Все архитекторы, с которыми я встречался, в разной степени имели одинаковую профессиональную деформацию характера: в своей речи они старались избегать конкретики.
Этот подход легко понять, ведь суть гибкости любой системы заключается в абстрагировании от конкретных решений.
Чем дольше решение может оставаться отложенным, тем более гибкой будет система.
Если UI достаточно абстрагирован от модулей уровня хранения данных, то чтение файла с жесткого диска можно легко заменить загрузкой той же информации из серверного API. И все же, давайте попробуем разобрать архитектуру типичного приложения для iOS. Я опишу глобальный подход к разделению логики приложения на уровни и слои, а также приведу конкретных участников тех или иных процессов, каждый со своими обязанностями и взаимодействием с окружением.
Монтаж
TL;DR: ПРОГРАММИСТЫ ТАКЖЕ ЯВЛЯЮТСЯ ИССЛЕДОВАТЕЛЬСКИМ ПЕРСОНАЛОМ Студенты высших учебных заведений изучают естественные науки, изучают менеджмент, получают знания по прикладной психологии и т. д. Каждая наука несет с собой обязательный багаж накопленной информации - академические знания, без которых продвижение самой науки было бы затруднено.Без этого фундамента наука не имела бы практической пользы: технологу производства гораздо выгоднее использовать проверенные временем подходы, гарантированно дающие результат, чем придумывать что-то свое.
Естественно, сам этот фундамент постоянно развивается и пополняется новой информацией и практиками.
За программированием стоит точно такая же строгая наука, как, например, за процессом производства аспирина.
Информатика, как типичный представитель формальных наук, имеет тот же набор и структуру.
формальные методы , использует проверенные, проверенные подходы к изучению нового, и, естественно, имеет собственный багаж академических знаний.
Научный подход гарантированно приведет к качественному результату, а знание и применение основных принципов проектирования программного обеспечения гарантированно облегчит поддержку продукта.
Книга Кристофера Александера «Язык шаблонов», давшая толчок использованию шаблонов в программировании, вышла в свет в 1977 году, а паттерн Модель-Представление-Контроллер был описан в 1979 году.
Вооружившись опытом разработки программного обеспечения и облачившись в белый халат теоретика, попробуем построить типовой проект приложения для мобильной платформы.
Н.Б.
Скорее всего, в реальной жизни (с учетом бизнес-требований к системе и с учетом сроков разработки) ваш проект будет выглядеть несколько иначе.
Однако можно с уверенностью сказать, что за таким продуктом стоит не просто ваше изобретение, а вполне обоснованный комплекс решений.
Данный
СФЕРИЧЕСКАЯ СИСТЕМА В ВАКУУМЕ Итак, у нас есть: сервер с документированным API от нескольких веб-сервисов; клиентское приложение и несколько типов устройств, которые это приложение должно поддерживать: планшеты, телефоны, часы и т.д.; макеты того, как должен выглядеть интерфейс приложения; набор пользовательских историй, описывающих, как должно вести себя приложение; список нефункциональных требований, которым должна соответствовать система.
Модель песочных часов
ВСЕГДА ЕСТЬ ДВА СИТХА: ОДИН СТРОИТ СЕРВИСЫ, ДРУГОЙ СТРОИТ НА НИХ пользовательский интерфейс.Первый шаг — отделить модель от контроллер И представление , выделяя таким образом два уровня приложения: «нижний» смотрит на мощности сервера, «верхний» смотрит на пользователя.
Слои в проектах мобильных приложений контроллер И представление , как правило, вполне органично может быть разработан одним человеком, а остальную бизнес-логику, касающуюся персистентности и обработки данных, можно смело доверить второму разработчику.
Таким образом, мы сразу распараллеливаем процесс производства ПО на два независимых потока.
Мы будем придерживаться классического принципа, который гласит, что уровни приложения общаются друг с другом посредством модельные объекты — классы с «прозрачной» реализацией, состоящие исключительно из аксессоров и мутаторов (методы get и set; фактически класс будет включать только свойства).
Такие классы не несут в себе никакой логики и предназначены только для хранения и перемещения данных.
Центральной сутью приложения — «шеей» песочных часов — будет объект, иначе называемый «инвертор зависимостей».
Он станет единственный синглтон-класс, и его единственной обязанностью будет обеспечение «верхних» уровней приложения.
Услуги .
Услуги
ИСТОРИЯ РАЗЪЕМНОГО СОЕДИНЕНИЯ Как создаются обычные серверные приложения? Очень просто.Всегда существует какая-то база данных (а может быть и несколько), в которой есть таблицы.
Таблицы состоят из записей.
Каждая запись содержит набор полей, в которых хранится информация.
Записи представлены в виде моделировать объекты с полями , тем самым создавая логическое разграничение типов данных в приложении: одна таблица — один тип данных.
Таблица «Пользователи» — тип данных «Пользователь» (поля: ID, ФИО, адрес).
Таблица «Сообщения» – тип данных «Сообщение» (поля: Идентификатор, Тема сообщения, Тело сообщения, Кому, От, Дата).
И так далее.
Таким образом, вся логика вращается вокруг таблиц и типов данных: 1. Объект модели , представляющий тип данных.
2. Сериализация модельный объект чтобы сохранить его в таблице.
3. Десериализация модельный объект из базы данных.
4. Преобразования модельный объект : расчет некоторой статистики, сортировка данных, поиск данных и т. д. 5. Сериализация модельный объект передать его по сети.
6. Десериализация модельные объекты , пришедший по сети.
7. Веб-сервис, доступный в сети, соответствующий этому типу.
данные.
Все это встроено в своего рода куча , а само серверное приложение состоит из нескольких таких независимых стопки , каждый из которых соответствует определенному типу данных.
Грубо говоря, если по спецификации API у вас есть веб-сервис api.domain.com/1-0/messages с классическим интерфейсом CRUD — это означает, что за ним стоит вышеупомянутый «стек» для типа данных «сообщение».
С Reate = POST; р читать = ПОЛУЧИТЬ; ты pdate = ПУТЬ; Д удалить = УДАЛИТЬ.
Н.Обычно сервер поддерживает стандартизированный набор запросов, отличающихся суффиксами URL-адресов соответствующего веб-сервиса: {api}/messages/{id} — операции с сущностью по заданному идентификатору; {api}/messages/{id}/{property} — операции с полем {property} сущности с ID = {id}.Б.
Существуют разные интерпретации операторов POST и PUT. В некоторых реализациях POST отвечает за создание сущностей, в других — за обновление.
К сожалению, канонической интерпретации нет, но беспокоиться не о чем.
ОБЩИЙ: Осталось сделать вилку для розетки.
А именно: 1. Подать заявку транспортный уровень приложение в виде объекта, который будет инкапсулировать HTTP-соединение вместе со всеми его настройками (включая безопасность, таймауты и т. д.).
• Интерфейс объекта должен быть точно таким же CRUD, как и веб-сервис, представленный в Интернете.
Если есть доступ к адресу {api}/messages, должны быть соответствующие четыре метода; если у вас есть доступ к GET {api}/messages/{id}/{property} - сделайте отдельный метод, который будет получать данные из этого {property}.
• Объект должен быть модульным.
Если в какой-то момент ваш замечательный веб-сервис {api}/messages перестанет функционировать, вам нужно будет реализовать только один объект, который копирует интерфейс.
транспортный уровень , но беря данные из файловая система.
2. Подать заявку парсеры И сериализаторы , который будет генерировать объекты модели и, наоборот, преобразовывать их в форму, подходящую для вашего транспорт уровень.
• Парсеры И сериализаторы нести знания о том, как преобразовать модельные объекты в словари типа JSON или XML. Не пытайтесь привязать это знание к себе.
модельные объекты - они не имеют никакого отношения к другим слоям приложения.
• Есть русскоязычный термин «топографический преобразователь», который мог бы заменить англоязычные «парсер» и «сериализатор», но сам термин почему-то не прижился.
3. Спроектируйте сущность, которая будет отвечать за кэширование.
• Сущность должна просто иметь возможность поточно-безопасно предоставлять доступ к полученным данным, перезаписывать и обновлять эти данные более свежими.
4. Спроектируйте саму «службу» — организацию, которая будет отвечать за координацию.
транспортный уровень , парсеры , сериализаторы И кэш .
• Интерфейс службы должен полностью соответствовать бизнес-требованиям уровня пользовательского интерфейса.
Если пользовательскому интерфейсу необходимо получить какую-то сущность, должен быть метод получения этой сущности.
Если пользовательский интерфейс требует сохранения сущности с определенными параметрами, у сервиса должен быть метод с этими параметрами.
Если пользовательскому интерфейсу требуется массив объектов заданного типа, отсортированный по какому-либо критерию, сервис должен предоставить соответствующий метод, который будет возвращать отсортированный массив.
• И да, не забывайте классический принцип: уровни приложения взаимодействуют друг с другом через модельные объекты .
Использование словарей/карт для передачи данных недопустимо – только строгая типизация.
Таким образом, мы фактически делаем свой стек, соответствующий серверному, но действующий в противоположном направлении.
Вот как будет выглядеть последовательность шагов, которые необходимо пройти данным, чтобы попасть из центрального хранилища к конечному пользователю:
Существует столько же типов данных, сколько и услуг.
Эту цифру довольно легко вычислить по спецификации API.
Н.В этом нет ничего плохого, это только твое парсеры И сериализаторы должен адекватно воспринимать такого рода вложенность и генерировать объекты соответствующих типов.Б.
«Чистые» услуги не так уж распространены в природе.
Бывает, что тот или иной сервис обслуживает сразу несколько типов данных.
Это связано с тем, что сущности модели могут быть вложены друг в друга: одна сущность может нести в себе массив объектов другого типа или иметь в качестве свойства похожий объект.
Сервисы должны быть максимально автономными, что не мешает вам выстраивать между ними логические зависимости.
Например, вполне логично, что в приложении есть сервис, отвечающий за авторизацию и поддержание сеанса с сервером, и от него зависят другие сервисы — они используют предоставленный им токен для формирования запросов.
Н.Уровень здания модель аналогично суть реализации паттерна многоуровневая архитектура с пересекающимися идеями Сервис-Ориентированная Архитектура .Б.
Каждый из сервисов так или иначе будет иметь CRUD-подобный интерфейс, построенный вокруг типа данных, обрабатываемых этим сервисом.
Это может стать отличным поводом изолировать абстрактный сервис с помощью абстрактного CRUD-интерфейса для последующего наследования от других сервисов, что обеспечит высокую степень повторного использования кода.
Мы не изобрели ничего нового.
уровень пользовательского интерфейса
ВРЕМЯ ДЛЯ ЗАМЕЧАТЕЛЬНЫХ ИСТОРИЙ Итак, вы пришли на проект, скачали из репозитория исходный код разрабатываемого приложения.Как проще всего понять, что делает это приложение? Верно! Запустите его! Здесь привычные таблицы с ячейками, стилизованные кнопки, катушки с датами, навигация, имена экранов.
Теперь задача: как соотнести все это с исходным кодом, который разбросан по нескольким сотням файлов, маячащих перед вами в IDE? Мы уже изолировали один из уровней приложения — по сути модель теперь может действовать как полностью независимый модуль, который можно повторно подключить к другому проекту, использующему тот же серверный интерфейс.
Или даже повторно использовать его для другого серверного интерфейса, если вы следовали всем принципам проектирования и поддерживали определенный уровень абстракции.
Но вот в чем проблема: у нас по-прежнему два (!) слоя, и единственным указанием на то, что и где находится в исходниках, является само работающее приложение, работающее на устройстве или в эмуляторе.
Вот тут они и приходят на помощь пользовательские истории.
Если ваше приложение хоть сколько-нибудь соответствует здравому смыслу, оно будет следовать определенным пользовательские истории , в которых объявляются сценарии, необходимые для реализации того или иного действия.
Самым классическим примером является истории регистрация и авторизация.
При регистрации пользователь вводит некоторые персональные данные, эти данные проверяются на адекватность, устанавливаются логины и пароли, все это может быть дополнено мерами безопасности в виде СМС и так далее.
Соответственно, в приложении есть целый история относительно регистрации.
Следуя логике, чтобы облегчить себе жизнь, самым очевидным решением будет следовать этим пользовательские истории при построении структуры уровней пользовательского интерфейса.
Более того, SDK приложений для iOS предоставляет для этого все необходимые инструменты: нужно просто создать для каждого история свою раскадровку — и разделите структуру проекта так, чтобы все классы строились вокруг них.
истории .
Кроме того, эти раскадровки можно даже динамически связывать друг с другом с помощью простые библиотеки , но это уже детали реализации.
В конечном итоге у вас получится структура, разделенная на модули по историям, каждый модуль будет свой.
представление И контролеры с занятиями- коммунальные услуги , и вы можете легко перемещаться по этой структуре, основываясь только на том, что происходит на экране вашего устройства/эмулятора.
Н.Вы можете набросать приблизительную диаграмму классов:Б.
И да, конечно, не будем забывать о классических принципах дизайна.
Мы применяем ТВЕРДЫЙ , СУХОЙ , ЦЕЛОВАТЬ И Ягни в полном объеме, главное не лениться, и разделять сущности в соответствии с ответственностью, которую они несут. Остальное вам подскажет опыт.
Естественно, нет предела совершенству, и этот подход не претендует на звание стандартного.
Заключение
РЕЗУЛЬТАТЫ И ОБСУЖДЕНИЕ Мы кратко рассмотрели, как можно создать целостный архитектурный проект мобильного приложения.Для этого мы применили сочетание классических шаблонов проектирования (MVC, SOA и многоуровневая архитектура), а также прибегли к логическому разделению исходного кода на модули, основанные на пользовательские истории .
А теперь небольшой вопрос к сообществу: Кто-нибудь использовал архитектуру на боевых проектах? В взгляд- я антактор- п ресентер- ? нты- р внешний, и как было достигнуто повторное использование объекта/шаблона Router? Как избежать роста маршрутизатора? Теги: #iOS #разработка iOS #Разработка мобильных приложений #разработка мобильных приложений #архитектура приложений #проектирование и рефакторинг
-
Что Лучше Dsl Или Кабельное?
19 Oct, 24 -
Причины Выбора Django Для Разработки Сайтов
19 Oct, 24