Как стать автором
Обновить

Комментарии 13

У вас онлайны отображаются некорректно и приложение почти не работает, если телефон в режиме энергосбережения. Иногда карточки в разделе свайпов не подгружаются и я смотрю на красивые прелоадеры. Кстати, почему если на ком-то остановиться, то не факт, что через 10 минут этот же человек будет наверху стопки карточек? Может я отложил


Напоминает ситуацию со Сбербанком, где машинное обучение и big data, но — где карточку открывали, туда и идите

Напишите, пожалуйста, мне в личные сообщения подробнее: какая платформа и версия приложения. Попробуем разобраться, из-за чего может тормозить.
Спасибо за статью.

Похоже, у вас получился EventBus с ручной маршрутизацией. Как вы решаете вопрос, если какому-то событию нужен колбек?
Я не совсем понял ваш комментарий про EventBus, если распишите подробнее свою мысль, постараюсь ответить.

На счёт коллбэков.
Это как раз достигается с помощью input/output подхода. Сейчас приведу упрощённый пример.
У вас есть компонент, который логинит юзера в приложение.
В обычном сценарии, вы вызываете метод и либо регистрируете заранее коллбэк, либо через rx цепочку получаете результат.
В подходе с компонентами в виде input/output выглядит примерно следующим образом:
interface LoginComponent {
    interface Dependency {
        fun input(): ObservableSource<Input>
        fun output(): Consumer<Output>
    }

    sealed class Input {
        object Login: Input()
    }

    sealed class Output {
        object Success: Output()
        object Failed: Output()
    }
}


И вы просто подписываетесь на output, который этот компонент возвращает.
Тогда после отправки события Login вы получите результаты через output.
Компоненты такого уровня мы не делаем, это упрощённый пример, чтобы ответить на вопрос.
> Я не совсем понял ваш комментарий про EventBus, если распишите подробнее свою мысль, постараюсь ответить.

Имел в виду, что концепция input/output потоков напоминает шаблон EventBus. Но у вас отличие, что не все компоненты слушают абсолютно все события от любых компонентов, а только отфильтрованные с помощью заданных вручную биндингов.

Спасибо за пример. Сам я использую местами похожий на ваше решение «велосипед» основанный на RxJava, позволяющий как отправлять события так и получать колбеки на них. Поэтому было интересно, как вы решили эту проблему.
У меня же в Output сваливаются не события, а нечто вроде Pair<Event, Maybe>, где первый аргумент изначальное событие а второй результат его обработки. После результат передается в том место, откуда поступил запрос. Это позволяет делать цепочки вида
class Login extends RequestMessage<Boolean>{}
....
request(new Login())
.flatMap(result -> result ?
     request(new Operation1()) :
     request(new Operation2())
....
В этом решении есть сильные отличия от EventBus за счёт чётких контрактов по которым работает компонент. Так ведь можно и концепцию коллбэков описать как EventBus)
По настоящему сложные и нужные проекты имеют слабое разделение на объекты. Так как связей очень много между объектами.
Ещё иногда теряется производительность при разделении на объекты — всегда был противником потери производительности, даже теоретической и миллисекундной.
ООП — это круто, но надо соблюдать меру пропорционально сложности проекта.
Нужно помнить о том, что программы, которые мы пишем — не всегда должны быть красивы для нас — людей. Они в первую очередь должны быть красивы для компьютеров и эту красоту нужно, просто понимать.
Стоит избегать преждевременных оптимизаций. Иначе с таким подходом стоит не использовать никакие библиотеки наподобие rxJava и потом не найти разработчиков на поддержку данного проекта.
Так что мы пользуемся подходом написания приложения в едином стиле и переписываем какие-то куски кода, когда профайлер демонстрирует проблемы.
Если вы полагаетесь только на интерфейсы, а не на конкретные реализации, то вам будет проще заменять компоненты, проще переключаться на другие реализации, не переписывая большую часть кода, что упрощает в том числе и модульное тестирование.
Я работаю в проекте уже почти пять лет. У нас изначально каждый «сервис» (не в терминах Андроид) сделан имплементацией своего интерфейса. Именно по той причине, что вы написали. Но знаете, что? За пять лет только один сервис был переписан с нуля, и мы этим воспользовались. И воспользовались только формально, в этом совершенно не было необходимости. Потом было больше проблем с вырезанием ненужной старой версии сервиса и переименовывание нового в старый, ибо нафиг он теперь нужен?
Проект развивается постепенно. Каждое изменение «атомарно» в терминах мерджа в master, и зачем эти техники тогда?
Есть дополнительные плюсы у использования интерфейсов, кроме простоты подмены.
Чёткий контракт, по которому видно каким образом работает компонент.
Гарантированное отсутствие проблем в тестах, когда будем мокать эту зависимость.

Но ваше замечание тоже валидно и имеет право на жизнь.
Ну вот разве что для мока и подойдёт, да. А для разработки даже «чёткий контракт» не нужен, ибо всегда можно посмотреть какие паблики у класса-имплементации есть.
Зарегистрируйтесь на Хабре, чтобы оставить комментарий