- Архитектура и дизайн Android приложения (мой опыт)
- Disclaimer
- Проблема: зачем нам нужна архитектура?
- Цель архитектуры и дизайна
- Решение
- Пример
- Введение в дизайн мобильных приложений
- Android против iOS
- Опирайтесь на соглашения платформы
- Проектирование и инструментарий
- Что происходит с инструментами для UX и UI-дизайна
- Особенности мобильного дизайна: помните об ограничениях.
- …и не забывайте о возможностях
Архитектура и дизайн Android приложения (мой опыт)
Сегодня я хочу рассказать об архитектуре, которой я следую в своих Android приложениях. За основу я беру Clean Architecture, а в качестве инструментов использую Android Architecture Components (ViewModel, LiveData, LiveEvent) + Kotlin Coroutines. К статье прилагается код вымышленного примера, который доступен на GitHub.
Disclaimer
Проблема: зачем нам нужна архитектура?
Большинство проектов, в которых мне доводилось участвовать, имеют одну и ту же проблему: внутрь андроид окружения помещается логика приложения, что приводит к большому объему кода внутри Fragment и Activity. Таким образом код обрастает зависимостями, которые совсем не нужны, модульное тестирование становится практически невозможным, так же, как и повторное использование. Фрагменты со временем становятся God-объектами, даже мелкие изменения приводят к ошибкам, поддерживать проект становится дорого и эмоционально затратно.
Есть проекты, которые вообще не имеют никакой архитектуры (тут все понятно, к ним вопросов нет), есть проекты с претензией на архитектуру, но там все равно появляются точно такие же проблемы. Сейчас модно использовать Clean Architecture в Android. Часто видел, что Clean Architecture ограничивается созданием репозиториев и сценариев, которые вызывают эти репозитории и больше ничего не делают. Того хуже: такие сценарии возвращают модели из вызываемых репозиториев. И в такой архитектуре смысла нет вообще. И т.к. сценарии просто вызывают нужные репозитории, то часто логика ложится на ViewModel или, еще хуже, оседает во фрагментах и активностях. Все это потом превращается в кашу, не поддающуюся автоматическому тестированию.
Цель архитектуры и дизайна
Цель архитектуры – отделить нашу бизнес-логику от деталей. Под деталями я понимаю, например, внешние API (когда мы разрабатываем клиент для REST сервиса), Android – окружение (UI, сервисы) и т.д. В основе я использую Clean architecture, но со своими допущениями в реализации.
Цель дизайна – связать вместе UI, API, Бизнес-логику, модели так, чтобы все это поддавалось автоматическому тестированию, было слабо связанным, легко расширялось. В дизайне я использую Android Architecture Components.
Для меня архитектура должна удовлетворять следующим критериям:
- UI — максимально простой, и у него есть только три функции:
- Представлять данные пользователю. Данные приходят уже готовые для отображения. Это основная функция UI. Тут виджеты, анимации, фрагменты и т.д.
- Реагировать на события. Здесь отлично помогает ViewModel и LiveData.
- Отправлять команды от пользователя. Для этого я использую свой простой framework, основанный на командах. Об этом чуть позже.
- Бизнес-логика зависит только от абстракций. Это нам позволяет менять реализацию произвольных компонентов.
Решение
Принципиальная схема архитектуры представлена на рисунке ниже:
Мы движемся снизу вверх по слоям, и слой, который находится ниже, ничего не знает о слое сверху. А верхний слой ссылается только на слой, который находится на один уровень ниже. Т.е. слой API не может ссылаться на домен.
Слой домен содержит бизнес сущности со своей логикой. Обычно здесь находятся сущности, которые существуют и без приложения. Например, для банка здесь могут находиться сущности кредитов со сложной логикой расчета процентов и т.д.
Слой логики приложения содержит сценарии работы самого приложения. Именно здесь определяются все связи приложения, выстраивается его суть.
Слой api, android – это лишь конкретная реализация нашего приложения в Android – среде. В идеале этот слой можно менять на что угодно.
Причем, когда я приступаю к разработке приложения, я начинаю с самого нижнего слоя — домена. Потом появляется второй слой сценариев. На 2-ом слое все зависимости от внешних деталей реализуются через интерфейсы. Вы абстрагированы от деталей, можно сконцентрироваться только на логике приложения. Тут же уже можно начинать писать тесты. Это не TDD подход, но близко к этому. И только в самом конце появляется сам Android, API с реальными данными и т.д.
Теперь более развернутая схема дизайна Android-приложения.
Итак, слой логики является ключевым, он и есть приложение. Только слой логики может ссылаться на домен и взаимодействовать с ним. Также слой логики содержит интерфейсы, которые позволяют логике взаимодействовать с деталями приложения (api, android и т.д.). Это так называемый принцип инверсии зависимости, который позволяет логике не зависеть от деталей, а наоборот. Слой логики содержит в себе сценарии использования приложения (Use Cases), которые оперируют разными данными, взаимодействуют с доменом, репозиториями и т.д. В разработке мне нравится мыслить сценариями. На каждое действие пользователя или событие от системы запускается некоторый сценарий, который имеет входные и выходные параметры, а также всего лишь один метод – запустить сценарий.
Кто-то вводит дополнительное понятие интерактора, который может объединять несколько сценариев использования и накручивать дополнительную логику. Но я этого не делаю, я считаю, что каждый сценарий может расширять или включать любой другой сценарий, для этого не нужен интерактор. Если посмотреть на схемы UML, то там можно увидеть связи включения и расширения.
Общая схема работы приложения следующая:
- Создается android-окружение (активити, фрагменты, и т.д.).
- Создается ViewModel (одна или несколько).
- ViewModel создает необходимые сценарии, которые можно запустить из этой ViewModel. Сценарии лучше инжектить с помощью DI.
- Пользователь совершает действие.
- Каждый компонент UI связан с командой, которую он может запустить.
- Запускается сценарий с необходимыми параметрами, например, Login.execute(login,password).
- Сценарий также с помощью DI получает нужные репозитории, провайдеры. Сценарий делает запрос на получение необходимых данных (может быть несколько асинхронных запросов api, да что угодно). Репозиторий выполняет запросы и возвращает данные сценарию. Причем у репозитория есть свои модели данных, которые он использует для своей внутренней работы, например, репозиторий для REST будет содержать модели со всякими JSON конверторами. Но перед тем, как отдать результат в сценарий, репозиторий всегда преобразовывает данные в модели данных сценария. Таким образом, логика ничего не знает о внутреннем устройстве репозитория и не зависит от него. Получив все необходимые данные, сценарий может создать необходимые объекты из домена. Выполнить какую-то логику на домене. Когда сценарий закончит работу, он обязательно преобразует свой ответ в очередную модель представления. Сценарий прячет уровень домена, он отдает данные, которые сразу понятны слою представления. Сценарий использования также может содержать в себе служебные сценарии, например, обработка ошибок.
- Сценарий вернул данные или ошибку в команду. Теперь можно обновить состояние ViewModel, которая в свою очередь обновит UI. Я обычно это делаю с помощью LiveData (п.9 и 10).
Т.е. ключевую роль у нас занимает логика и ее модели данных. Мы увидели двойное преобразование: первое – это преобразование репозитория в модель данных сценария и второе – преобразование, когда сценарий отдает данные в окружение, как результат своей работы. Обычно результат работы сценария отдается во viewModel для отображения в UI. Сценарий должен отдать такие данные, с которыми viewModel и UI ничего больше не делает.
UI запускает выполнение сценария с помощью команды. В моих проектах я использую собственную реализацию команд, они не являются частью архитектурных компонент или еще чего-либо. В общем, их реализация несложная, в качестве более глубокого знакомства с идеей можете посмотреть реализацию команд в reactiveui.net для C#. Я, к сожалению, не могу выложить свой рабочий код, только упрощенную реализацию для примера.
Основная задача команды — это запускать некоторый сценарий, передав в него входные параметры, а после выполнения вернуть результат команды (данные или сообщение об ошибке). Обычно все команды выполняются асинхронно. Причем команда инкапсулирует метод background-вычислений. Я использую корутины, но их легко заменить на RX, и сделать это придется всего лишь в абстрактной связке command+use case. В качестве бонуса команда может сообщать свое состояние: выполняется ли она сейчас или нет и может ли она выполниться в принципе. Команды легко решают некоторые проблемы, например, проблему двойного вызова (когда пользователь кликнул несколько раз на кнопку, пока операция выполняется) или проблемы видимости и отмены выполнения.
Пример
Реализовать фичу: вход в приложение с помощью логина и пароля.
Окно должно содержать поля ввода логина и пароля и кнопку “Вход”. Логика работы следующая:
- Кнопка “Вход” должна быть неактивной, если логин и пароль содержат менее 4 символов.
- Кнопка “Вход” должна быть неактивной во время выполнения процедуры входа.
- Во время выполнения процедуры входа должен отображаться индикатор (лоадер).
- Если вход выполнен успешно, то должно отобразиться приветственное сообщение.
- Если логин и/или пароль неверные, то должна появиться надпись об ошибке над полем ввода логина.
- Если надпись об ошибке отображена на экране, то любой ввод символа в полях логин или пароль, убирают эту надпись до следующей попытки.
Эту задачу можно решить разными способами, например, поместить все в MainActivity.
Но я всегда слежу за выполнением моих двух главных правил:
- Бизнес-логика не зависит от деталей.
- UI максимально простой. Он занимается только своей задачей (представляет данные, которые ему переданы, а также транслирует команды от пользователя).
Так выглядит приложение:
MainActivity выглядит следующим образом:
Активити достаточно прост, правило UI выполняется. Я написал несколько простых расширений, типа bindVisibleWithCommandIsExecuting, чтобы связывать команды с элементами UI и не дублировать код.
Код этого примера с комментариями доступен на GitHub, если интересно, можете скачать и ознакомиться.
Источник
Введение в дизайн мобильных приложений
Хотите создавать цифровые продукты для мобильных устройств? Вот что нужно знать в первую очередь.
Качпер Рудуха
(Kacper Ruducha)
Графический дизайнер из Варшавы. Рисовал с детства, но не понимал, что делать со своими рисунками, — пока не пришёл в графдизайн. Мечтает о своей дизайн-студии. Ведёт блог на Medium.
Перевожу, пишу, редактирую. Люблю живую речь.
Уважаю букву Ё.
Формализм мастдай.
Мобильность победила. Сотовых телефонов в мире намного больше, чем ноутбуков и десктопов, и они создают больше интернет-трафика. Ниже, на сравнительной диаграмме, отчётливо виден переломный момент, когда наступила так называемая эпоха пост-ПК:
На рубеже 2016 и 2017 годов мобильные телефоны вырвались вперёд, и в ближайшее время эта тенденция вряд ли изменится. На графике представлен только интернет-трафик, но есть ещё и нативные приложения. Поэтому можно сказать, что мобильник — король цифрового мира.
Android против iOS
Сегодня у нас дуополия (от латинского «два» и греческого «продаю». Ситуация, при которой есть только два продавца определённого товара, ведущие независимую друг от друга политику. — Ред.). Две главные мобильные операционки — Android от Google и iOS от Apple. По данным StatCounter Global Stats, на март 2019 года их доли на рынке составляют 75,33% и 22,4% соответственно:
Пока две собаки грызутся за кость, третья с ней убегает, не так ли? Не в этом случае. Никогда ещё положение остальных игроков не было столь плачевным. Два процента рынка — вот всё, что им осталось, и заманить к себе разработчиков будет непросто.
О чём нужно помнить дизайнерам мобильных приложений — неважно, работаете вы с Android или же с iOS?
Опирайтесь на соглашения платформы
Работа с приложениями должна быть привычной и интуитивно понятной даже новым пользователям, поэтому Google и Apple призывают разработчиков унифицировать интерфейсы нативных приложений. И дают рекомендации, как это сделать.
Для Android написан Google Material Design, а для iOS — Human Interface Guidelines. Непременно добавьте эти странички в закладки, вы будете часто возвращаться к ним при работе. Проштудируйте их, познакомьтесь с образцами нейминга, дизайна и юзабилити. Не забывайте, что документы эти регулярно обновляются, поэтому пересматривайте их время от времени, чтобы быть в курсе изменений.
Не считайте эти документы чем-то непреложным. Это просто рекомендации, а не строгие инструкции. Они вам в помощь, но не обязательно следовать им всегда и во всём. Можете даже смешивать рекомендации и применять элементы, характерные для одной платформы, на другой.
Если вы хотите разрабатывать для iOS, а раньше пользовались только устройствами на Android, очень вам советую походить с айфоном. Вы переключитесь, познакомитесь с яблочным интерфейсом и лучше поймёте его пользователей.
Проектирование и инструментарий
Создание мобильного приложения мало чем отличается от разработки других цифровых продуктов. Обычно всё происходит так:
- Озарение, или просто отправная точка. Это может быть идея инновационного продукта (ещё один убийца Facebook!) или просто сбор требований клиента.
- Моделирование. На этом этапе пишутся пользовательские сценарии и истории, а затем их представляют в виде блок-схем и рисуют малодетализированные каркасы графического интерфейса (low-fidelity wireframes). Есть множество инструментов, позволяющих вместе создавать такие схемы онлайн. Очень популярен RealtimeBoard, теперь он называется MIRO. Если нужно что-то бесплатное — выручит Freehand от InVision. Когда дело доходит до рисования каркасов, на ум приходят бумага и карандаш. Нужно что-то ещё? В мобильном приложении Marvel легко фотографировать свои рисунки и создавать интерактивные схемы.
- Макеты (мокапы). Визуальное представление вашего приложения. В начале эры цифрового дизайна правил бал Adobe Photoshop. Но он не был заточен под проектирование интерфейсов и постепенно сдавал позиции. Согласно отчёту Avocode Design Trend, в 2016 году старый добрый PS потерял пальму первенства. Теперь отраслевой стандарт для создания макетов — приложение Sketch. Благодаря своему огромному сообществу он обзавёлся расширениями и плагинами, а также интеграцией с уймой сторонних программ. Sketch — простой, но мощный инструмент.
- Прототипирование. С интерактивным прототипом можно взаимодействовать как с интерфейсом уже готового приложения. Его демонстрируют инвесторам, клиентам и разработчикам. Наиболее популярный инструмент — программа InVision. Очень часто её дополняет Craft, это набор плагинов для Sketch и Photoshop. Стоит упомянуть, что и сам Sketch недавно обзавёлся инструментами для создания прототипов.
- Анимация и микровзаимодействия 1 . Этот этап иногда пропускают — по крайней мере по трём причинам. Прежде всего, для стандартных компонентов iOS и Android варианты взаимодействия с пользователем уже предопределены. Во-вторых, сложная анимация может значительно затянуть разработку. Наконец — и это тоже важно — для создания анимации и микровзаимодействий нужны навыки, которые есть не у каждого дизайнера. Но и тут на помощь приходят инструменты. Для простых шаблонов хватает Flinto и Principle. Если вы создаёте что-то сложное — выбирайте Framer.
- Передача разработчикам. Чтобы реализовать проект, нужно как-то переадресовать дизайн разработчикам. Этот процесс и называется передачей (handoff), и для этого тоже есть приложения. Если ваша компания ещё ничего не выбрала, можете поиграть с Avocode, Sympli или Zeplin. Все они позволяют экспортировать ресурсы, проверять свойства дизайна и многое другое. Кроме того, эти приложения часто используются для общения внутри команды.
Части продукта, выполняющие небольшую конкретную задачу.
Что происходит с инструментами
для UX и UI-дизайна
С тех пор как цифра пришла на смену бумаге, инструменты для UX- и UI-дизайнеров развивались стремительнее всех прочих дизайнерских программ. И я вижу две основные тенденции.
Во-первых, пора монополий прошла: пока ещё легко выбрать предпочтительный инструмент для каждого этапа проектирования, но всё слишком быстро меняется. Например, дизайнеров всё больше привлекают приложения Figma и Adobe XD, бросившие вызов Sketch.
Во-вторых, инструменты становятся самодостаточными, а это значит, что вы можете охватить весь процесс разработки, используя только одно программное решение: просто взгляните на InVision Studio.
Особенности мобильного дизайна: помните об ограничениях.
Где-то я прочёл, что творчества без ограничений не бывает. Проектируя для мобильных телефонов, обратите внимание вот на что:
Меньший размер дисплея
На деле это означает, что на экране помещается меньше элементов. Привычная навигация по сайту тоже отменяется. Нужно иначе отображать содержимое и сократить путь пользователя.
Проектирование для сенсорного экрана
Забудьте про клавиатуру и мышку, теперь приложением управляют касания и жесты. Кликабельные элементы должны быть крупнее, чтобы в них легко было попасть пальцем.
Ограничения трафика и производительности
Остерегайтесь тяжёлых файлов и форматов мультимедиа, для которых нужно загружать много данных из интернета, — это может влететь пользователям в копеечку. Следите, чтобы количество обращений к API, отправляемых вашим приложением, не снижало общую производительность сервера.
…и не забывайте о возможностях
Мобильным приложениям доступно больше возможностей устройства, и они используют их лучше, чем традиционные настольные или веб-приложения. У вас есть прекрасный шанс погрузить пользователей в продукт, представляя программное и аппаратное обеспечение как единое целое.
- Подумайте о навигации жестами.
- Не забывайте, что почти у всех современных устройств есть камера и микрофон — это ваша альтернатива для ввода данных.
- Прикиньте, как перестраивать макет, когда меняется ориентация экрана: управлять приложением должно быть удобно в любом случае.
И ещё один общий совет. Если вы решили, что мобильное приложение станет частью вашей цифровой стратегии, сразу продумайте его роль в ней. От того, будет ли оно основной точкой входа для ваших пользователей или дополнением для другой площадки или сервиса, зависит общее направление проектирования.
Источник