#flutter #clean-architecture
Вопрос:
Узнав о чистой архитектуре на Flutter благодаря замечательному руководству ResoCoder, я пытаюсь преобразовать свой побочный проект в чистую архитектуру.
Мое приложение состоит из теста скорости и пользовательского интерфейса, оно отображает:
- «Speed-O-Meter», как и любое приложение для тестирования скорости, с датчиком, некоторыми ключевыми маркерами скорости и стрелкой. Пожалуйста, обратите внимание, что датчик не является линейным, поэтому для вычисления иглы потребуются разные формулы, основанные на скорости и этих маркерах,
- и метка, указывающая пропускную способность в единице, установленной пользователем (по умолчанию в Мбит / с).
За капотом, когда пользователь запускает тест скорости, приложение загружает файл с URL-адреса (но не сохраняется). По мере загрузки вычисляется пропускная способность и вычисляется угол наклона иглы, оба в режиме реального времени.
Итак, как мне определить мою функцию тестирования скорости? До сих пор я намеревался использовать следующие варианты использования:
- один для загрузки файла, обработки потока и любых ошибок ввода-вывода,
- один для вычисления пропускной способности в определенной единице
- один для вычисления угла наклона иглы на основе вычисленной полосы пропускания
Мне нравится такой подход, поскольку каждая проблема хорошо разделена. Но должен ли я использовать один вариант использования? Но тогда это означало бы, что есть только один репозиторий> источник данных, который будет выполнять загрузку, вычислять пропускную способность и вычислять угол. Не нарушит ли это принцип единой ответственности SOLID?
Но если я использую все три варианта использования, это будет означать следующие потоки:
- Пользовательский интерфейс> Событие блока> проверка скорости запуска > загрузка файла> загруженный фрагмент файла> Состояние блока> Пользовательский интерфейс
- затем пользовательский интерфейс> Событие блока> вычислить пропускную способность> измеренная пропускная способность> Состояние блока> Пользовательский интерфейс
- затем пользовательский интерфейс> Событие блока> вычисление угла иглы > новый угол> состояние блока> Пользовательский интерфейс
Это правильно, правильный путь?
Вы также можете видеть, что в каждом потоке результат полностью возвращается к пользовательскому интерфейсу (через состояния блока), только для того, чтобы пользовательский интерфейс запускал новые события, чтобы запросить больше материала. Это тоже правильно или блок должен сделать это сам и перенести конечный результат (измеренная полоса пропускания угол иглы) в пользовательский интерфейс? Может ли блок принять такое решение или это должно быть решение пользовательского интерфейса?
Основываясь на этом последнем вопросе, я хотел сказать, что есть кое-что еще, чего я не понимаю в чистой архитектуре: кто обладает полномочиями в отношении поведения функций? Возьмите эти настройки, о которых я упоминал ( один):
- единица измерения, в которой отображается пропускная способность
- формулы для вычисления угла наклона иглы, поскольку датчик не является линейным и
- частота обновления скорости для правильного пользовательского интерфейса и использования ресурсов устройства.
Честно говоря, где мне определить и записать в коде эти настройки / правила? Я бы поставил внутри варианта использования, потому что я там прочитал:
Программное обеспечение на этом уровне содержит бизнес-правила, специфичные для приложения.
Но … что касается пользовательского интерфейса, означает ли это, что вариант использования должен указывать, как должен выглядеть пользовательский интерфейс? Или наоборот? Например, должен ли он указывать пользовательскому интерфейсу, как должен быть построен датчик со всеми ключевыми маркерами скорости под определенными углами? Это кажется запутанным…
Так много вопросов… Я надеюсь, вы понимаете, и вы можете мне помочь! Заранее большое спасибо.
Ответ №1:
При принятии решения о том, как структурировать вашу бизнес-логику в различных вариантах использования, рекомендуется следовать SRP. Это может привести к множеству небольших вариантов использования. В чистой архитектуре нигде не указано, что варианты использования не могут быть объединены для реализации большего варианта использования (рабочего процесса). Таким образом, нет необходимости выполнять циклические переходы к пользовательскому интерфейсу для реализации полной функциональности.
Что касается вашего последнего вопроса: все ваши бизнес-правила, любые формулы и код принятия решений должны быть расположены на уровне прецедентов. Уровень варианта использования определит единицу пропускной способности (возможно, на основе некоторой конфигурации), докладчик преобразует ее в строку, и представление, наконец, просто покажет эту строку.
Макет (расположение экрана) и стиль (например, цвета) пользовательского интерфейса, конечно, определяются на уровне пользовательского интерфейса.
Для более подробного объяснения вариантов использования в чистой архитектуре, пожалуйста, ознакомьтесь с моим сообщением в блоге: http://www.plainionist.net/Implementing-Clean-Architecture-UseCases /
Комментарии:
1. Большое спасибо, что нашли время прочитать и дать очень интересный ответ. Я также с некоторым интересом прочитал ваш блог. Ваша идея иметь UseCase (или Interactor в вашем случае) представляет собой хорошее решение, которое сохраняет мои взгляды и докладчиков немыми. Так что я последую этому примеру! И подтвердит ваш ответ соответствующим образом 😉
2. Спасибо за ваши отзывы! Пожалуйста, не забудьте принять мой ответ 😉