#кейсы
Вопрос:
Есть RecyclerView с различными разнообразными ViewHolder. В одном item списка может быть семь EditText, в другом - другие компоненты. У каждого item своя логика валидации и прочее. Возникает риск распухания ViewHolderов и намешивания в них бизнес-логики.
Ответ:
Советуем посмотреть в сторону решения, описанного в http://hannesdorfmann.com/android/adapter-delegates.
Там вводится новая сущность - делегат. Делегат позволяет разгрузить ваши адаптеры и вьюхолдеры, а также сделать их максимально переиспользуемыми, если списков в приложении много.
В делегаты вы можете инжектить Презентеры, через которые провайдите действия пользователя.
Однако бывают случаи, когда один item переиспользуется много где, и этот item отвечает, например, за "like". Инжектить Презентер бывает не очень удобно, так как тогда возникает дублирование кода и протягивание лишних зависимостей, чтобы в конце концов выполнить нужный юз-кейс.
Поэтому можно заинжектить в данный делегат специальный Интерактор, который как раз и выполняет юз-кейс нажатия на like.
Вопрос:
Есть RecyclerView с различными разнообразными ViewHolder. В одном item списка может быть семь EditText, в другом - другие компоненты. У каждого item своя логика валидации и прочее. Возникает риск распухания ViewHolderов и намешивания в них бизнес-логики.
Ответ:
Советуем посмотреть в сторону решения, описанного в http://hannesdorfmann.com/android/adapter-delegates.
Там вводится новая сущность - делегат. Делегат позволяет разгрузить ваши адаптеры и вьюхолдеры, а также сделать их максимально переиспользуемыми, если списков в приложении много.
В делегаты вы можете инжектить Презентеры, через которые провайдите действия пользователя.
Однако бывают случаи, когда один item переиспользуется много где, и этот item отвечает, например, за "like". Инжектить Презентер бывает не очень удобно, так как тогда возникает дублирование кода и протягивание лишних зависимостей, чтобы в конце концов выполнить нужный юз-кейс.
Поэтому можно заинжектить в данный делегат специальный Интерактор, который как раз и выполняет юз-кейс нажатия на like.
Hannesdorfmann
Joe's great adapter hell escape
AdapterDelegates, a library to build RecyclerView Adapter easily on Android by following the principle of favor composition over inheritance and delegation.
#статьи
В статье автор пытается разобраться с понятием Inversion Of Control и дать более менее формальное определение понятию.
На примере, написанном на псевдокоде, рассматривается система с прямым потоком управления, после эта же система, но с применением иневерсии потока упраления. Показав систему до и после и проанализировав изменения, автор, на мой взгляд, неплохо раскрывает тему IoC.
Статья читается тяжеловато, много сложной терминологии (автор дает определения), но рекомендую к прочтению, особенно, если вы путаете понятия Inversion of Control, Dependency Inversion Principle, Dependency Injection и хотите разобраться с теоретической стороной вопроса.
Хотя для некоторых понятий в статье дается несовсем полное определение, которое верно в контексте статьи, но может запутать, если вы только знакомитесь с тематикой, например, Dependency Injection — это функция, которую может выполнять IoCContainer. Все верно, но помните, что Dependency Injection прекрасно существует без IoCContainer и эта штука хоть и очень полезная, но опциональная. В общем, читайте аккуратнее!
https://rsdn.org/article/ioc/Inversion%20of%20Control2.xml
В статье автор пытается разобраться с понятием Inversion Of Control и дать более менее формальное определение понятию.
На примере, написанном на псевдокоде, рассматривается система с прямым потоком управления, после эта же система, но с применением иневерсии потока упраления. Показав систему до и после и проанализировав изменения, автор, на мой взгляд, неплохо раскрывает тему IoC.
Статья читается тяжеловато, много сложной терминологии (автор дает определения), но рекомендую к прочтению, особенно, если вы путаете понятия Inversion of Control, Dependency Inversion Principle, Dependency Injection и хотите разобраться с теоретической стороной вопроса.
Хотя для некоторых понятий в статье дается несовсем полное определение, которое верно в контексте статьи, но может запутать, если вы только знакомитесь с тематикой, например, Dependency Injection — это функция, которую может выполнять IoCContainer. Все верно, но помните, что Dependency Injection прекрасно существует без IoCContainer и эта штука хоть и очень полезная, но опциональная. В общем, читайте аккуратнее!
https://rsdn.org/article/ioc/Inversion%20of%20Control2.xml
www.rsdn.org
Так всё-таки, что же такое Inversion of Control?
Почему происходит уменьшение связанности при использовании Inversion of Control? Какова область применения Inversion of Control? Бывают ли случаи когда без Inversion of Control не обойтись? Является ли событийная модель синонимом принципа Inversion of Control?…
#кейсы
Вопрос:
А как правильно реализовывать логику выбора данных из кэша или из сети? Что если иногда надо брать из кэша, а иногда из сети? Правил но ли делать в репозитории методы типо getfromnetwork и getfromcache? Например в случае если пулл ту рефреш то это обязательно из сети, а в каких-то других случаях можно и из кэша взять. Или
например есть ситуация: есть обьект, мне сначала нужно сделать бизнес-операцию над ним, далее показать, паралельно отправить запрос в облако, для обновления данных об обьекте, и когда запрос выполнится, отобразить актуалные данные из сети. По сути мне нужно знать об существовании разных источников данных на уровне бизнес логики. Тогда какая часть должна быть в репозиторие?
Что предлагаем:
Логика получения данных, в общем случае, хранится в специальном классе в уровне модели. Далее возможно иметь 2 кейса:
1) Менеджер источников данных (например, SmthDataStoreFactory) инжектится в SmthRepository и сам решает, как вытаскивать данные - из сети или кэша.
2) В случае, когда бизнес логике важно, чтобы данные пришли свежими, отправляется специальный флаг типа "needFreshData", его получает менеджер и понимает, что кэш в данном случае не прокатит, делает запрос на сервер. Если нужна более гибкая настройка, можно использовать различные стратегии для выборки данных, FirstCache, NoCache и т.д.. В репозитории будут методы с сигнатурой, getUser(int id, boolean needFreshData) или getUser(int id, CachePolicy policy).
Методы, вроде getfromnetwork и getfromcache использовать можно, у такого подхода есть плюс, по сравнению с подходом, когда используется менеджер источников данных (SmthDatatStoreFactory) - не будет заглушек вроде UnsupportedOperationException на методы, которые актуальны для одних источников, но не поддерживаются в других. Из минусов, Не получится, поменять источник данных, незатронув при этом реализации зависящих классов.
Вопрос:
А как правильно реализовывать логику выбора данных из кэша или из сети? Что если иногда надо брать из кэша, а иногда из сети? Правил но ли делать в репозитории методы типо getfromnetwork и getfromcache? Например в случае если пулл ту рефреш то это обязательно из сети, а в каких-то других случаях можно и из кэша взять. Или
например есть ситуация: есть обьект, мне сначала нужно сделать бизнес-операцию над ним, далее показать, паралельно отправить запрос в облако, для обновления данных об обьекте, и когда запрос выполнится, отобразить актуалные данные из сети. По сути мне нужно знать об существовании разных источников данных на уровне бизнес логики. Тогда какая часть должна быть в репозиторие?
Что предлагаем:
Логика получения данных, в общем случае, хранится в специальном классе в уровне модели. Далее возможно иметь 2 кейса:
1) Менеджер источников данных (например, SmthDataStoreFactory) инжектится в SmthRepository и сам решает, как вытаскивать данные - из сети или кэша.
2) В случае, когда бизнес логике важно, чтобы данные пришли свежими, отправляется специальный флаг типа "needFreshData", его получает менеджер и понимает, что кэш в данном случае не прокатит, делает запрос на сервер. Если нужна более гибкая настройка, можно использовать различные стратегии для выборки данных, FirstCache, NoCache и т.д.. В репозитории будут методы с сигнатурой, getUser(int id, boolean needFreshData) или getUser(int id, CachePolicy policy).
Методы, вроде getfromnetwork и getfromcache использовать можно, у такого подхода есть плюс, по сравнению с подходом, когда используется менеджер источников данных (SmthDatatStoreFactory) - не будет заглушек вроде UnsupportedOperationException на методы, которые актуальны для одних источников, но не поддерживаются в других. Из минусов, Не получится, поменять источник данных, незатронув при этом реализации зависящих классов.
#статьи
https://plus.google.com/+DianneHackborn/posts/FXCCYxepsDU
Пост инженера Гугла о том, о чем мы все очень любим говорить (чем грешу и я) - Андроид мешает нам жить!
На самом деле Android SDK - это просто API, по которому приложение общается с ОС и другими приложениями через ту же ОС. Всё! И более ничего.
Далее рассматриваются ключевые компоненты SDK и их истинное предназначение.
Activity - это не только View, а прежде всего это системный компонент. Он помогает сохранять состояния при убийстве процесса, восстанавливать его, пермишены там разные получать и т.д. На фрагменты да, вы уже можете вешать ответственность "только View".
BroadcastReceiver. Используйте его только для получения каких-либо системных событий. Внутри приложения общение между компонентами можете организовывать как угодно, но желательно не через BroadcastReceiver, чтобы не получить потенциальные дыры.
Service. Started services. Для запуска долгоиграющих задач. Например, проигрывание музыки.
Service. Bound services. Для общения между процессами. Не более. В рамках одного процесса вообще не имеет смысла запускать.
ContentProvider. Самое интересное, как по мне. ContentProvider - это просто специальная возможность публиковать данные со своего приложения куда-либо еще. Это никакая ни абстракция для БД, сети или еще чего-либо.
А хотите там архитектур всяких красивых - думайте сами!
https://plus.google.com/+DianneHackborn/posts/FXCCYxepsDU
Пост инженера Гугла о том, о чем мы все очень любим говорить (чем грешу и я) - Андроид мешает нам жить!
На самом деле Android SDK - это просто API, по которому приложение общается с ОС и другими приложениями через ту же ОС. Всё! И более ничего.
Далее рассматриваются ключевые компоненты SDK и их истинное предназначение.
Activity - это не только View, а прежде всего это системный компонент. Он помогает сохранять состояния при убийстве процесса, восстанавливать его, пермишены там разные получать и т.д. На фрагменты да, вы уже можете вешать ответственность "только View".
BroadcastReceiver. Используйте его только для получения каких-либо системных событий. Внутри приложения общение между компонентами можете организовывать как угодно, но желательно не через BroadcastReceiver, чтобы не получить потенциальные дыры.
Service. Started services. Для запуска долгоиграющих задач. Например, проигрывание музыки.
Service. Bound services. Для общения между процессами. Не более. В рамках одного процесса вообще не имеет смысла запускать.
ContentProvider. Самое интересное, как по мне. ContentProvider - это просто специальная возможность публиковать данные со своего приложения куда-либо еще. Это никакая ни абстракция для БД, сети или еще чего-либо.
А хотите там архитектур всяких красивых - думайте сами!
Google Plus
"How should I design my Android application? What kind of MVC pattern should I use? What should I use for an event bus?" We often see questions from ...
#статьи
Шпаргалка по SOLID принципам. Для каждого принципа есть краткое описание, примеры нарушения и версии принципов с приставкой Anti-, такие как DI-головного мозга, Принцип тысячи интерфейсов и т.д. Так же вы можете ознакомиться с каждым из принципом более подробно, в конце статьи есть ссылки на цикл статей по SOLID принципам.
Особенно рекомендуется к прочтению статья "Критический взгляд на принцип инверсии зависимостей", в которой автор делает анализ примеров, приведенных в статье и книге Дядюшки Боба и приходит к интересным выводам.
http://sergeyteplyakov.blogspot.ru/2014/10/solid.html
http://sergeyteplyakov.blogspot.ru/2013/04/blog-post.html
Шпаргалка по SOLID принципам. Для каждого принципа есть краткое описание, примеры нарушения и версии принципов с приставкой Anti-, такие как DI-головного мозга, Принцип тысячи интерфейсов и т.д. Так же вы можете ознакомиться с каждым из принципом более подробно, в конце статьи есть ссылки на цикл статей по SOLID принципам.
Особенно рекомендуется к прочтению статья "Критический взгляд на принцип инверсии зависимостей", в которой автор делает анализ примеров, приведенных в статье и книге Дядюшки Боба и приходит к интересным выводам.
http://sergeyteplyakov.blogspot.ru/2014/10/solid.html
http://sergeyteplyakov.blogspot.ru/2013/04/blog-post.html
Blogspot
Шпаргалка по SOLID принципам
S – The Single Responsibility Principle Название : Принцип единственной ответственности. Определение : У класса/модуля должна быть лишь од...
#презентация
Доклад "Чистая архитектура. Погружение" (Евгений Мацюк и Александ Блинов).
В pptx + keynote.
https://drive.google.com/drive/folders/0B5fMdvXec3eyMVNnNHNIY3kwZ28?usp=sharing
Доклад "Чистая архитектура. Погружение" (Евгений Мацюк и Александ Блинов).
В pptx + keynote.
https://drive.google.com/drive/folders/0B5fMdvXec3eyMVNnNHNIY3kwZ28?usp=sharing
#статьи
Наверняка, частенько бывало такое, что выделив интерфейсы для всех ваших зависимостей и прокинув их пачкой через конструктор к потребителю, вы становились абсолютно спокойным за свой дизайн. Так как, вы не завязаны на конкретную реализацию, формально есть DIP (вы зависите от абстракций), у вас есть Dagger, который соберет все в кучу. Но все ли так хорошо на самом деле? И что такое франкен-код или франкен-дизайн? В этих вопросах поможет разобраться статья про управление зависимостями.
https://habrastorage.org/web/f85/ee5/aeb/f85ee5aeb3e84d758f60d9efcf015868.jpg
http://sergeyteplyakov.blogspot.ru/2012/11/blog-post.html
https://plus.google.com/u/0/+SergeyTeplyakov/posts/gRaqrqaiGbe
P.S. На изображении Сергей Шкредов рассказывает про систему управления зависимостями в .NET продуктах JetBrains. IntellisenseManager - реально существующая сущность, кажется в плагине для VS Resharper. Не забывайте, что в статьях скорее всего речь идет о больших десктопных приложениях, которые вероятно сложнее и крупнее мобильных, но материал конечно актуален и для мобильных приложений тоже.
Наверняка, частенько бывало такое, что выделив интерфейсы для всех ваших зависимостей и прокинув их пачкой через конструктор к потребителю, вы становились абсолютно спокойным за свой дизайн. Так как, вы не завязаны на конкретную реализацию, формально есть DIP (вы зависите от абстракций), у вас есть Dagger, который соберет все в кучу. Но все ли так хорошо на самом деле? И что такое франкен-код или франкен-дизайн? В этих вопросах поможет разобраться статья про управление зависимостями.
https://habrastorage.org/web/f85/ee5/aeb/f85ee5aeb3e84d758f60d9efcf015868.jpg
http://sergeyteplyakov.blogspot.ru/2012/11/blog-post.html
https://plus.google.com/u/0/+SergeyTeplyakov/posts/gRaqrqaiGbe
P.S. На изображении Сергей Шкредов рассказывает про систему управления зависимостями в .NET продуктах JetBrains. IntellisenseManager - реально существующая сущность, кажется в плагине для VS Resharper. Не забывайте, что в статьях скорее всего речь идет о больших десктопных приложениях, которые вероятно сложнее и крупнее мобильных, но материал конечно актуален и для мобильных приложений тоже.
#кейсы
Вопрос:
Мне необходимо загрузить список (есть local и remote data source). Т.о сначала необходимо отобразить данные из local, и потом делать запрос к серверу. Является ли это бизнес-логикой, или эту логику необходимо вынести в Repository?
Что предлагаем:
Зависит от требований к приложению, глобально есть два подхода:
1) умный кеш (тогда это на уровне репозитория, а интерактор только просит данные)
2) глупый репозиторий (репозиторий только знает как достать данные, а интерактор сам говорит откуда и когда)
Вопрос:
Мне необходимо загрузить список (есть local и remote data source). Т.о сначала необходимо отобразить данные из local, и потом делать запрос к серверу. Является ли это бизнес-логикой, или эту логику необходимо вынести в Repository?
Что предлагаем:
Зависит от требований к приложению, глобально есть два подхода:
1) умный кеш (тогда это на уровне репозитория, а интерактор только просит данные)
2) глупый репозиторий (репозиторий только знает как достать данные, а интерактор сам говорит откуда и когда)
#кейсы
Вопрос:
После некоторого действия пользователя показывается SnackBar с кнопкой Отмена. Если успеть ее нажать, то действие надо отменить. Как лучше это сделать.
Что предлагаем:
Презентер сообщает действие интерактору только по событию: "SnackBar скрылся", то есть только после того как пользователь решил не отменять действие. Важно: надо заранее учесть, что пользователь может сразу после действия выйти с экрана или приложения. Тогда надо принять решение - либо также передать действие интерактору при деттаче вью, лтбо считать такое поведение пользователя тоже отменой действия.
Вопрос:
После некоторого действия пользователя показывается SnackBar с кнопкой Отмена. Если успеть ее нажать, то действие надо отменить. Как лучше это сделать.
Что предлагаем:
Презентер сообщает действие интерактору только по событию: "SnackBar скрылся", то есть только после того как пользователь решил не отменять действие. Важно: надо заранее учесть, что пользователь может сразу после действия выйти с экрана или приложения. Тогда надо принять решение - либо также передать действие интерактору при деттаче вью, лтбо считать такое поведение пользователя тоже отменой действия.
#кейсы
Вопрос:
Есть список элементов. По клику открывается информация о конкретном элементе.
Можно ли передавать элемент через параметры нового экрана или надо в параметры класть только Id.
Что предлагаем:
Правильнее передавать параметром только Id, а сами элементы будут закешированы в репозитории.
Так как в этом случае мы сможем получить всегда актуальную информацию из репозитория, а не устаревшую из параметров.
Вопрос:
Есть список элементов. По клику открывается информация о конкретном элементе.
Можно ли передавать элемент через параметры нового экрана или надо в параметры класть только Id.
Что предлагаем:
Правильнее передавать параметром только Id, а сами элементы будут закешированы в репозитории.
Так как в этом случае мы сможем получить всегда актуальную информацию из репозитория, а не устаревшую из параметров.
#кейсы
Вопрос:
Может ли Presenter обращаться к Interactor за некоторыми константами (Interactor.ROOT_FOLDER_ID)?
Что предлагаем:
Лучше чтобы презентер не знал о каких-то константах бизнес логики.
Если эта константа дальше нужна для получения данных, то лучше сделать явный метод getRootFolderInfo() или что-то в этом роде
Вопрос:
Может ли Presenter обращаться к Interactor за некоторыми константами (Interactor.ROOT_FOLDER_ID)?
Что предлагаем:
Лучше чтобы презентер не знал о каких-то константах бизнес логики.
Если эта константа дальше нужна для получения данных, то лучше сделать явный метод getRootFolderInfo() или что-то в этом роде
#кейсы
Вопрос:
Необходимо в тексте подсветить некоторые части с помощью спанов.
Это бизнес логика, как лучше поступить?
Что предлагаем:
Передавать из презентера массив пар строка-цвет и отрисовывать во вью.
Или передавать всю строку, и массив из выделений (индекс начала, индекс конца, цвет)
Вопрос:
Необходимо в тексте подсветить некоторые части с помощью спанов.
Это бизнес логика, как лучше поступить?
Что предлагаем:
Передавать из презентера массив пар строка-цвет и отрисовывать во вью.
Или передавать всю строку, и массив из выделений (индекс начала, индекс конца, цвет)
#книги
Приводим список книг, которые помогут вам писать более поддерживаемый, модифицируемый, "чистый" код.
1. Паттерны проектирования. Банда четырех.
Основа основ.
2. Effective Java 2. Джошуа Блох.
Хорошо вправляет мозги, особенно начинающим. Полезные советы о том, как писать хороший код на Java.
3. Чистый код. Роберт Мартин.
Отличная книга, показывающая, каких ошибок не стоит совершать.
4. Совершенный код. Стив Макконнелл.
Отлично прочищает мозги.
5. Экстремальное программирование. Кент Бек.
Как писать с TDD. Учит мыслить тестами.
6. The Clean coder. Робер Мартин.
Хорошие советы разработчикам.
7. Working effectively with Legacy code. Майкл Фезерс.
Про боль, которая знакома каждому. Как бороться с легаси кодом.
8. Refactoring. Мартин Фаулер.
Не всегда мы пишем всё с нуля. Тут нам подскажут, как с наименьшими потерями обновить существующую кодовую базу.
В каждой книге вы найдете что-то своё. И самое главное, вы сможете найти в них ответы на многие свои вопросы.
Приводим список книг, которые помогут вам писать более поддерживаемый, модифицируемый, "чистый" код.
1. Паттерны проектирования. Банда четырех.
Основа основ.
2. Effective Java 2. Джошуа Блох.
Хорошо вправляет мозги, особенно начинающим. Полезные советы о том, как писать хороший код на Java.
3. Чистый код. Роберт Мартин.
Отличная книга, показывающая, каких ошибок не стоит совершать.
4. Совершенный код. Стив Макконнелл.
Отлично прочищает мозги.
5. Экстремальное программирование. Кент Бек.
Как писать с TDD. Учит мыслить тестами.
6. The Clean coder. Робер Мартин.
Хорошие советы разработчикам.
7. Working effectively with Legacy code. Майкл Фезерс.
Про боль, которая знакома каждому. Как бороться с легаси кодом.
8. Refactoring. Мартин Фаулер.
Не всегда мы пишем всё с нуля. Тут нам подскажут, как с наименьшими потерями обновить существующую кодовую базу.
В каждой книге вы найдете что-то своё. И самое главное, вы сможете найти в них ответы на многие свои вопросы.
#теория
Состоялся тут в чатике холивар по тому, на сколько нужны паттерны проектирования для начинающих и вся подобная теория.
Вывод довольно простой на самом деле. Без знания языка и какой-то практики теория не будет иметь большого смысла. Шаблоны - хороший и выразительный инструмент для функциональных конструкций. В каждом проекте применяется множество шаблонов, их нужно уметь распознавать и применять. Это требует практики и осмысления. Существует несколько базовых принципов, понимание которых сильно упростит и понимание шаблонов, GRASP и SOLID. Понимание этих принципов сделает некоторые шаблоны очевидными, некоторые вполне закономерными. В современных тенденция также будут полезными знания освновных принципов функционального программирования.
На основе этого можно достаточно легко оперировать такими инструментами как DI, применять Rx, разделять отвественности по слоям.
Состоялся тут в чатике холивар по тому, на сколько нужны паттерны проектирования для начинающих и вся подобная теория.
Вывод довольно простой на самом деле. Без знания языка и какой-то практики теория не будет иметь большого смысла. Шаблоны - хороший и выразительный инструмент для функциональных конструкций. В каждом проекте применяется множество шаблонов, их нужно уметь распознавать и применять. Это требует практики и осмысления. Существует несколько базовых принципов, понимание которых сильно упростит и понимание шаблонов, GRASP и SOLID. Понимание этих принципов сделает некоторые шаблоны очевидными, некоторые вполне закономерными. В современных тенденция также будут полезными знания освновных принципов функционального программирования.
На основе этого можно достаточно легко оперировать такими инструментами как DI, применять Rx, разделять отвественности по слоям.
#Вечный_вопрос
Использовать контекст в Презентере и Интеракторе или нет? Почти как "быть или не быть", судя по той частоте, с которой задается данный вопрос.
Причем вроде все согласны с тем, что андроид-классам в бизнес-логике не место. На то она и бизнес-логика, чтобы быть максимально независимой, особенно независимой от платформы. Андроид-классы у нас обычно или во вьюшке, или в Data-слое (получение данных типа геопозиции, контактов и прочее).
Но вот нужно нам строчку из Презентера передать вьюшке. И как быть? Без контекста вроде никак. И тут мы добавляем зависимость. И это только для получения строчки, не более. Но проблема в том, что последователи могут начать использовать контекст в Презентере не по назначению. А если контекст будет в Интеракторе, то теоретически наша бизнес-логика будет завязана на конкретную платформу, что делает ее не переиспользуемой (кейс переиспользования бизнес-логики где-то в другом месте, конечно, очень редкий в нашем мобильном мире, но все же).
На самом деле есть способы избежать использования контекста в том же Презентере.
Для доступа к ресурсам надо создать отдельную сущность, которая будет работать с контекстом только ради ресурсов, типа ResourceManager, и все.
Проблема решаема, причем довольно малой кровью. Но зато наш код чистый и независимый.
Использовать контекст в Презентере и Интеракторе или нет? Почти как "быть или не быть", судя по той частоте, с которой задается данный вопрос.
Причем вроде все согласны с тем, что андроид-классам в бизнес-логике не место. На то она и бизнес-логика, чтобы быть максимально независимой, особенно независимой от платформы. Андроид-классы у нас обычно или во вьюшке, или в Data-слое (получение данных типа геопозиции, контактов и прочее).
Но вот нужно нам строчку из Презентера передать вьюшке. И как быть? Без контекста вроде никак. И тут мы добавляем зависимость. И это только для получения строчки, не более. Но проблема в том, что последователи могут начать использовать контекст в Презентере не по назначению. А если контекст будет в Интеракторе, то теоретически наша бизнес-логика будет завязана на конкретную платформу, что делает ее не переиспользуемой (кейс переиспользования бизнес-логики где-то в другом месте, конечно, очень редкий в нашем мобильном мире, но все же).
На самом деле есть способы избежать использования контекста в том же Презентере.
Для доступа к ресурсам надо создать отдельную сущность, которая будет работать с контекстом только ради ресурсов, типа ResourceManager, и все.
Проблема решаема, причем довольно малой кровью. Но зато наш код чистый и независимый.
#Теория
Что есть Interactor и UseCase?
Каноничный юзкейс - это класс с одним методом execute. На практике это не всегда бывает удобно. Плюс порождает большое количество классов. Поэтому вводится такое понятие как Интерактор.
На самом деле каноничного определения Интерактора нет.
В нашем понимании Интерактор = набор юзкейсов связанных одной фичей.
То есть ProfileInteractor = LoadProfileUseCase + UpdateProfilePhotoUseCase + UpdateProfileNameUseCase + ...
Что есть Interactor и UseCase?
Каноничный юзкейс - это класс с одним методом execute. На практике это не всегда бывает удобно. Плюс порождает большое количество классов. Поэтому вводится такое понятие как Интерактор.
На самом деле каноничного определения Интерактора нет.
В нашем понимании Интерактор = набор юзкейсов связанных одной фичей.
То есть ProfileInteractor = LoadProfileUseCase + UpdateProfilePhotoUseCase + UpdateProfileNameUseCase + ...
#статьи
Как понять по логам тестов что перестало работать? Как упростить понимание кода с помощью тестов? Как сделать тесты более читаемыми? В статье приведены 7 подходов к именованию unit-тестов, которые помогут ответить на эти вопросы глядя только имя тестового метода.
https://dzone.com/articles/7-popular-unit-test-naming
Как понять по логам тестов что перестало работать? Как упростить понимание кода с помощью тестов? Как сделать тесты более читаемыми? В статье приведены 7 подходов к именованию unit-тестов, которые помогут ответить на эти вопросы глядя только имя тестового метода.
https://dzone.com/articles/7-popular-unit-test-naming
DZone
7 Popular Unit Test Naming Conventions
The article presents a compiled list of unit tests naming strategy that one could follow for naming their unit tests. The article is intended to be a quick reference instead of going through multiple great pages such as following.
#оВечном
Я хочу быть ниндзя и расслоить мой проект как врага сюрекенами, но есть Glide, неужели его кишки тоже надо раскидать по всему проекту? Что делать?
Да, Glide (как и Пикассо, Фреско, УИЛ и тд) отличная вещь, не надо от нее отказываться.
Тут тебе и загрузка картинок, и пост обработка и кеши всякие.
Но, скажете вы, вьюха должна быть тупой, а картинка приходить из дата слоя. В теории все так, но в реальном мире надо уметь находить компромиссы, которые помогут писать проект и чисто и быстро.
(умение формулировать компромиссы появляется ТОЛЬКО с опытом, поэтому мы и создали этот чат, чтобы неопытные не выдумывали боль из ничего)
Итак, что с загрузкой картинок? Компромисс здесь в том, что мы будем считать, что вью каким-то образом умеет отображать URL картинки как саму картинку и все! Вас же не смущает, что вебвью смогло загрузить веб-страницу по переданной ссылке? Поэтому смело забывайте про загрузку картинок и передавайте их в виде ссылке внутрь вью!
Я хочу быть ниндзя и расслоить мой проект как врага сюрекенами, но есть Glide, неужели его кишки тоже надо раскидать по всему проекту? Что делать?
Да, Glide (как и Пикассо, Фреско, УИЛ и тд) отличная вещь, не надо от нее отказываться.
Тут тебе и загрузка картинок, и пост обработка и кеши всякие.
Но, скажете вы, вьюха должна быть тупой, а картинка приходить из дата слоя. В теории все так, но в реальном мире надо уметь находить компромиссы, которые помогут писать проект и чисто и быстро.
(умение формулировать компромиссы появляется ТОЛЬКО с опытом, поэтому мы и создали этот чат, чтобы неопытные не выдумывали боль из ничего)
Итак, что с загрузкой картинок? Компромисс здесь в том, что мы будем считать, что вью каким-то образом умеет отображать URL картинки как саму картинку и все! Вас же не смущает, что вебвью смогло загрузить веб-страницу по переданной ссылке? Поэтому смело забывайте про загрузку картинок и передавайте их в виде ссылке внутрь вью!
#статьи
Service Locator - паттерн проектирования, описанный Мартином Фаулером ещё в далеком 2004 году: http://martinfowler.com/articles/injection.html
Сейчас только ленивый не говорит о том, что Service Locator - это анти-паттерн, и нужно избегать его использование. Первое громкое заявление, что Service Locator это анти-паттерн, было от Марка Симана в 2010 году. Следует отметить, что Марк разрабатывал Service Locator для первой версии Microsoft patterns & practices Enterprise Library и работал над проектом несколько лет, прежде чем признать Service Locator анти-паттерном и отказаться от него.
Причина простая, есть лучшая альтернатива - DI.
Автор статьи, которую мы хотим представить вашему вниманию, согласен с тем, что DI - лучшая альтернатива, но хочет сказать пару слов в защиту Service Locator. Из статьи вы узнаете о некоторых проблемах DI, которых нет в Service Locator и найдёте много интересного теоретического материала.
http://bayou.io/draft/In_Defense_of_Service_Locator.html
Service Locator - паттерн проектирования, описанный Мартином Фаулером ещё в далеком 2004 году: http://martinfowler.com/articles/injection.html
Сейчас только ленивый не говорит о том, что Service Locator - это анти-паттерн, и нужно избегать его использование. Первое громкое заявление, что Service Locator это анти-паттерн, было от Марка Симана в 2010 году. Следует отметить, что Марк разрабатывал Service Locator для первой версии Microsoft patterns & practices Enterprise Library и работал над проектом несколько лет, прежде чем признать Service Locator анти-паттерном и отказаться от него.
Причина простая, есть лучшая альтернатива - DI.
Автор статьи, которую мы хотим представить вашему вниманию, согласен с тем, что DI - лучшая альтернатива, но хочет сказать пару слов в защиту Service Locator. Из статьи вы узнаете о некоторых проблемах DI, которых нет в Service Locator и найдёте много интересного теоретического материала.
http://bayou.io/draft/In_Defense_of_Service_Locator.html
martinfowler.com
Inversion of Control Containers and the Dependency Injection
pattern
pattern
Explaining the Dependency Injection pattern, by contrasting it with Service Locator. The choice between them is less important than the principle of separating configuration from use.
#кейсы
Если посмотреть лекции дядюшки Боба, интерактор отвечает за бизнес логику и ничего не знает о внешних фреймворках, ui, db.
То, что Андроид обязан работать со вьюхами только в главном потоке, знает только сам Андроид фреймворк. Соответственно, обязанность предоставить шедулер
Обязанность презентера - координировать вью и модель. Если вью необходимо, чтобы данные обрабатывались в главном потоке - мы явно указываем
@senneco заметил, что не нужно всё делать асинхронно — ведь если репозиторий возвращает данные из мемори кэша, то незачем переключать потоки туда-сюда.
Поэтому,
Пример:
Презентер:
Интерактор:
Репозиторий (в более сложном кейсе, шедулер зависит от источника данных, тут упрощённый пример с нетворком)
Summary:
Переключение потоков может быть как частью бизнес-логики, так и частью слоя данных. Зависит от того, какой класс имеет необходимую информацию для принятия решения.
Мнение:
При передаче между слоями можно всегда прокидывать данные через главный поток - таким образом, при получении observable в новом слое мы знаем, на каком потоке он выполнится. Минус подхода - зачастую, будут излишние переключения.
Если посмотреть лекции дядюшки Боба, интерактор отвечает за бизнес логику и ничего не знает о внешних фреймворках, ui, db.
То, что Андроид обязан работать со вьюхами только в главном потоке, знает только сам Андроид фреймворк. Соответственно, обязанность предоставить шедулер
Android.mainThread()
должна лежать снаружи от интерактора.Обязанность презентера - координировать вью и модель. Если вью необходимо, чтобы данные обрабатывались в главном потоке - мы явно указываем
observeOn(AndroidSchedulers.mainThread())
.@senneco заметил, что не нужно всё делать асинхронно — ведь если репозиторий возвращает данные из мемори кэша, то незачем переключать потоки туда-сюда.
Поэтому,
subscriveOn()
происходит уже в интеракторе, или репозитории, которые владеют необходимой информацией о том, стоит ли выделить новый поток (который будет уже Андроид-независимым, как Schedulers.Io()
или Schedulers.computation()
).Пример:
Презентер:
userInteractor.downloadUserInfo()
.map(mapper::entityToView);
.observeOn(AndroidSchedulers.mainThread())
.subscribe(view::showUserInfo);
Интерактор:
repository.downloadUserInfo();
Репозиторий (в более сложном кейсе, шедулер зависит от источника данных, тут упрощённый пример с нетворком)
api.downloadUserInfo()
.subscribeOn(Schedulers.io)
.map(mapper::networkToEntity);
Summary:
Переключение потоков может быть как частью бизнес-логики, так и частью слоя данных. Зависит от того, какой класс имеет необходимую информацию для принятия решения.
Мнение:
При передаче между слоями можно всегда прокидывать данные через главный поток - таким образом, при получении observable в новом слое мы знаем, на каком потоке он выполнится. Минус подхода - зачастую, будут излишние переключения.
#кейсы
Вопрос: от сервера в Repository приходит флаг, по которому необходимо разлогинить пользователя. Но перед этим мне необходимо почистить все данные пользователя (SharedPreferences, Database).
Этот флаг может придти в любом запросе.
Получается, что необходимо в каждый Repository Inject-ить LogoutResolver или реализовать эту логику на уровне BaseRepository?
Вариант 1:
Ввести декоратор для репозтория, в который инжектиться все необходимое для очистки данных. Однако, если у декоратора нет полной информации о том, как должны очищаться остальные репозитории (они могут хранить что-то в других преференсах, бд, файлах), то по-прежнему остаётся проблема того, что эти репозитории нужно как-то уведомить о необходимости очистки.
Один из вариантов - создать список слушателей в декораторе, куда подключать все репозитории. В дальнейшем, если один репозиторий поймал событие о разлогине, уведомляются все репозитории-слушатели и выполняют свою логику по очистке.
Недостаток: многовато кода и недостаточно легко масштабируемо.
Вариант 2:
Можно ввести специальную новую сущность, например, DataCleaner.
Он будет инжектиться в интерсептор OkHttpClient, но при этом будет имет доступ в БД и Преференсам, чтобы почистить их.
То есть все будет разруливаться в дата слое без Репозитория и прочего.
При этом, если есть, допустим, несколько файлов Преференсов, и их нужно все почистить, то для большего удобства можно ввести что-то вроде PreferencesFacade, который бы предоставлял унифицированный доступ ко всем файлам нужным. И собственно из Репозиториев тоже можно работать с преференсами через него. Тогда точно ничего не забудется.
Вопрос: от сервера в Repository приходит флаг, по которому необходимо разлогинить пользователя. Но перед этим мне необходимо почистить все данные пользователя (SharedPreferences, Database).
Этот флаг может придти в любом запросе.
Получается, что необходимо в каждый Repository Inject-ить LogoutResolver или реализовать эту логику на уровне BaseRepository?
Вариант 1:
Ввести декоратор для репозтория, в который инжектиться все необходимое для очистки данных. Однако, если у декоратора нет полной информации о том, как должны очищаться остальные репозитории (они могут хранить что-то в других преференсах, бд, файлах), то по-прежнему остаётся проблема того, что эти репозитории нужно как-то уведомить о необходимости очистки.
Один из вариантов - создать список слушателей в декораторе, куда подключать все репозитории. В дальнейшем, если один репозиторий поймал событие о разлогине, уведомляются все репозитории-слушатели и выполняют свою логику по очистке.
Недостаток: многовато кода и недостаточно легко масштабируемо.
Вариант 2:
Можно ввести специальную новую сущность, например, DataCleaner.
Он будет инжектиться в интерсептор OkHttpClient, но при этом будет имет доступ в БД и Преференсам, чтобы почистить их.
То есть все будет разруливаться в дата слое без Репозитория и прочего.
При этом, если есть, допустим, несколько файлов Преференсов, и их нужно все почистить, то для большего удобства можно ввести что-то вроде PreferencesFacade, который бы предоставлял унифицированный доступ ко всем файлам нужным. И собственно из Репозиториев тоже можно работать с преференсами через него. Тогда точно ничего не забудется.