ПРОМО 1 млн.руб. грантами для стартапов! Перейти 

BackendMobile

Flutter в большом проекте

MWWM компонент

Критерии качества ПО определяются 6 пунктами: функциональность, эргономичность, надежность, эффективность, модифицируемость, мобильность (переносимость). Это возможность в дальнейшем, когда один человек написал какой-то код, а другой человек может его прочитать, или зайти в проект, в котором он не работал ранее и сразу найти нужное место, может фиксить баг, если в тикет системе что-то пришло, может какой-то функционал дописать, то есть он не должен задумываться и искать где вообще происходит это. Для этого у нас есть следующий инструментарий – два пакета в pov.dev. Первый пакет это MWWM, и второй пакет, который его очень хорошо дополняет – Relation. MWWM позволяет для StatefulWidget создать экземпляр класса компаньона, в которой инкапсулируется вся бизнес-логика, то есть вся логика, которая происходит в виджете полностью сосредоточена вот в этом отдельном объекте.  При этом сам виджет фактически является шаблоном, он просто смотрит за теми объектами состояния, которые лежат в виджет модуле и не делает ничего кроме как отрисовывает их текущее состояние, что они ему как бы поручают. Пакет Relation, предоставляет удобные объекты этих стримов состояний и стримов пользовательского взаимодействия, которые передаются в бизнес-логику. 

Область применения

Либо целиком какой-то экран, либо какой-то изолированный виджет, который в себе содержит свою собственную бизнес-логику. Хороший пример, кнопка в корзину, когда мы кладем товар в каком-то магазине в корзину, нажимаем на кнопочку, она соответственно меняет свое состояние, потому что она смотрит фактически через свою виджет модель на состояние интер акта или сервиса корзины. Она показывает стоимость товарной позиции и количество этих товаров в корзине. То есть эта одна кнопочка уже может быть MWWM компонентом. Как работает MWWM компонент. Во первых нужно сказать о том, что MWWM компонент это всего навсего state full вижн. То есть он унаследован от state full widget и расширен дополнительными возможностями. И первая возможность, которую он реализует это то, что в конструкторе виджета, до того как будет создан виджет state. Он создает виджет модель, как раз этот объект компаньон для бизнес-логики. Следующая функциональность – связывается жизненный цикл widget state и жизненный цикл виджет модели, то есть бизнес компаньона. В него передаются два вызова: вызов метода onLoad и вызов метода onBind. Оба вызываются из метода initState. Разделены они не просто так. То есть семантически сделана привязка, что в onLoad привязывается к внешним данным, а в onBind привязывается именно к состоянию пользовательского ввода, к состоянию самого виджет State. То есть эти два метода, по дефолту реализованы в виджет модели и если их переопределить в них можно добавлять какой-то свой вызов какой-то дополнительной бизнес-логики. Последняя функциональность, которая реализована по дефолту, это вызов dispose. Соответственно чтобы освободить ресурсы, причем он происходит автоматически и подписки все освобождаются.

Пакет Relation содержит следующие основные компоненты. В первую очередь это два State: StreamedState – некоторый объект, внутри которого постоянно лежит какое-то значение и вот на это значение стримит State Builder, находящийся в виджет стейте, подписывается на этот Стримед стейт и рендерит данные, которые в данный момент находятся в этом стейте. Следующий полезный объект – EntityStreamedState. Этот объект имеет 3 фиксированных конечных состояния: состояние загрузки, состояние наличие в нем контента и состояние ошибки, с лежащей внутри ошибкой, которая произошла. Последний блок – это Actions. Тоже стримы, через которые передается пользовательское взаимодействия из виджета в виджет модель, это могут быть нажатие кнопок, или это может быть передача табов, которые кликнул пользователь, или странички на которые пользователь перешел, или соответственно отступ скрола.

Три типичных кейса. Первый кейс, когда открываем страницу  детального представления какого-то товара, то есть каких-то данных. Второй кейс – страничка авторизации. Третий кейс, это бесконечный скролл, с подгрузкой дополнительных данных при достижении конца скролла.

Как это работает.

При открытии детального экрана первое состояние, которое показывают пользователю, это состояние загрузки. И дальше из этого состояния загрузки он может перейти, либо в состояние ошибки, если он не смог достучаться до сервера или вообще запросили данные, которых больше нет в сервисе. Либо получив данные, может их отрендерить, показать. 

Как это реализуется. Самый простой кейс – это полностью весь экран является представлением EntityStateBuilder, типизированным теми данными, которые должны получить чтобы отрисовать контент. EntityStateBuilder подписан на контент стейт объект типа EntityStreamedState, который находится как раз в виджет модели. Сам по себе EntityStateBuilder содержит внутри себя 3 метода билдера. Первый метод называется Builder, он рендерит какой-то виджет, который отображает контент с данными. Второй билдит какую-то заглушку для loading. И третий, это виджет, который рендерит некоторый виджет, который показывает конкретную ошибку, которая произошла. То есть это либо данных нет, либо интернет пропал попробуйте позже перезагрузится. И в свою очередь пользовательский ввод, если попали в состояние ошибки, то есть показываем пользователю почему произошла эта ошибка. И здесь помещается кнопка. Эта кнопка, при клике на нее, вызывает передачу события в объект reload error action, на который мы в свою очередь подписываемся в методе onBind. 

Как выглядит виджет модель целиком, она состоит фактически из трех частей. Первая часть, это контракт виджет модели. Здесь описываются все стримы и все состояния, которые вообще есть в виджет модели. В ней фактически задокументированы все состояния, которые могут влиять на данный экран. Вторая часть, это подписка на потоки событий и данных. Подписываемся методом Subscribe, он по дефолту реализован виджет моделе. Метод Subscribe при каждой подписке кладет эту подписку в список подписок виджет модели, и когда виджет будет закрываться он автоматически полностью все эти подписки завершит.

Следующий пример, это условно экран авторизации, здесь 2 стейта. Первый стэйт PassObscureState. Это состояние показываем ли мы сейчас символы пароля или нет. Второй это LoadingProceedState, то есть находится ли у нас сейчас этот экранная форма в состоянии сетевого запроса к серверу, когда мы запрещаем пользовательское взаимодействие, и с полями ввода, и с кнопкой авторизоваться, чтобы не спамить сервер. Соответственно здесь создаем контроллер текстового ввода для логина и пароля и здесь же лежат ключи для формы и скаффолда для того, чтобы показать снейк бар. И последний объект кнопка чтобы авторизоваться и ее стрим acceptAction.

Метод подписки на события. Подписываемся на стрим потока нажатием на кнопку acceptAction. Метод accept будет выглядеть следующим образом, мы проверяем состояние лежащий в loadingProceedState, то есть смотрим не идет ли уже сетевой запрос, может быть и не нужно второй раз запрашивать. Потом валидируем форму, затем переводим форму в состояние загрузки и все это сделано в очень простом императивном виде. Когда это все наглядно и все лежит конкретно таким методом, и ничего больше вокруг нет, не верстки, не каких-то получений зависимости, это все в очень декларативном виде, то есть только концентрированная бизнес-логика и ничего больше.

Последний пример, это бесконечный скролл. Первое что создаем в виджет моделе это скролл контроллер. Естественно мы будем подписываться на изменения, все это в нем. Дальше dataListState, фактически список айтомов, которые находятся в этом списке в данный момент, то есть мы туда будем подкидывать дополнительные данные. В случае, если при первой попытке загрузить данные, сразу же произошла ошибка, то есть данных никаких еще нет, то экран будет целиком падать в состояние ошибки. И последний стейт – это стейт подгрузки дополнительных данных, это ошибка, которую показываем в конце списка, тоже как элемент списка, где кнопочка появляется, что какой-то причине произошла ошибка попробуйте подгрузиться еще раз, например, когда установится соединение с интернетом. Последний стейт служебный, на него в виджет стейте никто не подписан, это page фильтр. Стейт в нем лежит состояние текущего указателя на ту страницу, которую в данный момент последнюю загрузили, то есть там лежит офсет погруженных элементов сервера. 

В целом этот подход имеет как минимум 2 недостатка. Сам пакет Relation зависит от RxDart. И второе это многословность, то есть приходится писать больше букв, больше строчек кода. В данном случае это обоснованно по той причине, что в основном весь этот дополнительный код, это именно документирование, структурирование. Из преимуществ очевидно, что он получается автоматически документированный. То есть все стейт имеют док коммент, очень легко отлаживать. В любой момент можно остановить выполнение и посмотреть, какие конкретно состояния данных лежат в каждом из стейтов, и почему наш экран в данный момент падает именно в такое состояние, в такое место приходит из какого состояния, какие входные данные, все их можно просмотреть и все понять, потому что все стейты доступны. Также чтение логики облегчаются по той же самой причине. Последнее преимущество, это то что виджет стейт шаблонный, это просто кусок верстки без ничего. Часто бывает, что мы начинаем разрабатывать проект, когда еще не готов сервер или доступа к какому-то банковскому серверу нет, то можно все заранее сверстать, а виджет модель с данными потом уже дописать поверх, дополнительно к этому. 

Похожее по теме
BackendRuby

Ruby Meetup: Распределенная модель данных

Распределенная модель данных Модель данных начала свою эволюцию как монолит (монолитная бизнес логика и монолитная модель данных). Здесь у нас появляется большое…
BackendPHPБез рубрики

PHP и QA. Практические примеры поддержания качества продукта

В статье рассмотрим практические примеры поддержания качества продукта из реальных проектов, вместе со Skyeng сделаем обзор частых грабель, на которые наступают команды…
BackendFrontendMobile

Android vs iOS vs Flutter. Mobile

Константин Горничнов,  iOS и андроид-разработчик из компании FunBox Flutter — это мультиплатформа на Фреймворк. Он не использует нативные компоненты, а отрисовывает всё…

Добавить комментарий

Ваш адрес email не будет опубликован. Обязательные поля помечены *

4 × один =