Ой, дайте пять! Мы с другом в детстве записали свою озвучку для Worms 3D (потому что ее там не перевели), разобравшись, где лежат файлы, и затем ускорили наши голоса в стандартном XP-шном звуковом редакторе. Веселые времена :)
Карты в CS 1.6 разрабатывать еще не так сложно, я кое-как сумел разобраться, хотя карты были кривые, а вот для Source… ухх, хотелось бы еще раз попробовать, но боюсь разочароваться в себе.
К слову, есть экспериментально-андерграундный рэп-проект ΔLDEΔ MΔLVΔDΔ, у которого все тексты — это либо пулеметная цепь отсылок к чему угодно, либо абсолютно бессвяззный текст, и этот проект вполне себе хорош.
В общем, хоть Dagger и классный, но в большинстве проектов он не подходит по большей части из-за своей сложности
Вот тут полностью согласен, инструмент действительно недружелюбный к новичкам. До сих пор помню, как я не мог понять, как же Dagger работает со scope-ами.
К сожалению, официальный туториал все еще использует ужасный пример с Thermosiphon'ом.
>Паттерны — делегат, строитель. Работа с асинхронностью — корутины.
Так. Есть вероятность, что я чего-то не знаю, поэтому спрошу — в Kotlin есть какая-то особая поддержка Builder'ов? Или вы имели в виду возможность сделать свой DSL?
Работа с асинхронностью — корутины
Оффтопик, но еще бы объяснялось в туториалах лучше, как именно они работают… Я слабо представлял, как корутина может прыгать между тредами (Это же один метод, думал я!) и «приостанавливать» тред и исполнять там другой код, пока не посмотрел под капот, и не понял, что вызов (очень условно) каждой
За такое я бы руки отрывал. Rx — мощнейший инструмент, при использовании которого все приложение строится по-другому, но для некоторых это всего лишь способ вынести запросы на сервер в другой тред… и в итоге наблюдаешь subscribe внутри subscribe
Помимо либ мы можем написать DI руками, используя делегаты
Так это не DI, это service locator. Что Koin, что Kodein, по сути, не особо уменьшают связанность классов, они просто перемещают это в другое место. Toothpick, в принципе, то же самое.
Плюс у них отсутствует проверка наличия зависимостей во время компиляции. В маленьком приложении это не так проблемно, а вот в большом это будет вполне себе заметно — раз за разом где-нибудь при тестировании (а то и в продакшене) будет оказываться, что кто-то забыл предоставить зависимость.
Плюс Dagger редко требует от меня явного прописывания создания объектов — если объекту просто нужно предоставить зависимости, я помечу его scope-аннотацией, помечу конструктор @Inject — и готово, объект будет создан. Явное создание объектов в моделях нужно только в случае, если объект создается нетривиально, в остальных случаях я могу либо не использовать модули, либо использовать @Binds. В Koin/Kodein мне придется каждый раз писать, как именно создавать объект. Сейчас я работаю над очень большим проектом, в котором используется Dagger 2, и, скажу честно, я очень рад, что я могу просто объявить класс, объявить его зависимости, пометить конструктор аннотацией — и все, больше мне не нужно ничего делать.
Ну и лично мне очень нравится, как scopes устроены в Dagger 2. Они очень дисциплинируют и не позволяют бездумно раздавать объекты направо и налево.
А в Kotlin паттерн Singleton пишется одним ключевым словом object.
С objectом нужно быть очень осторожным, иначе получите плохотестируемое нечто. А если нужен синглтон с зависимостями, то object отправляется гулять. ИМХО, object я бы использовал только либо как хранилище графа объектов, либо как подкласс sealed класса, у которого нет состояния (ну или какие-то util штуковины).
Аналогично работает и с другими инструментами.
Можно еще примеров? Моя фантазия, к сожалению, ставит меня в тупик.
К сожалению, я потерял статью, в которой было описано как красиво можно написать DI на Kotlin делегатах
Не знаю почему библиотекой до сих пор активно пользуются после появления Kotlin
Что? С каких пор язык стал заменять инструмент для внедрения зависимостей?
Не, ну тут очевидно все, виновато отсутствие бумажки. Писали бы код на бумажке — все было бы идеально. И вовсе не в том, что не так-то сложно придумать задачу, которая даже с возможностью гугления не решится без своих мозгов.
Нет-нет, просто я с английского криво калькировал и перенес фокус не туда. В этом контексте полярность — это то, где в розетке hot и neutral провода. В общем-то, насколько я понимаю, в европейских розетках такие провода тоже есть (куда же без них в трехфазной системе), просто все приборы сделаны с рассчетом на то, что розетку могут воткнуть и так, и сяк.
Можно еще вспомнить розетки, в которые необходимо вставлять вилку в правильной ориентации, иначе будет не та полярность и некоторым приборам может настать белый и пушистый. Конечно, как правило у таких приборов вилка имеет утолщение на одном из контактов, но сам факт того, что у розетки есть правильные и неправильные ориентации поразил меня до глубины души.
Ага, а потом еще были протесты один-в-один по американской модели — перекроем шоссе, начнем громить рандомные места…
Хорошо хоть, что в Израиле люди в целом не подвержены сказкам об "угнетенных", и все это нашло угасающе малый процент поддержки.
Ну, например, в том, что передачей-получением результатов у нас по каким-то причинам заведует FragmentManager. По идее, это не должно быть его заботой, это должно быть заботой отдельного класса, который занимается только получением-передачей этих результатов. Диаграмма с тем, какой FragmentManager нужно использовать, чтобы правильно получить результаты — это весело, конечно. Захотел использовать Fragment внутри другого Fragment'а в одном месте, а в другом внутри Activity? Пиши if-else на выбор FragmentManager'а.
Короче говоря, обычный observer становится совсем необычным.
Плюс нет никакого типирования результата. Хочешь узнать, что тебе пришло из другого фрагмента? Полезай, дружок, в код этого фрагмента и узнай. А если уж вдруг кто-то ошибся и переиспользовал ключ с другим типом данных, то лови ClassCastException.
Понятно, конечно, что все это сделано максимально адски в связи с жизненным циклом Fragment/Activity и возможностью убийства процесса, а, значит, нужно сохранять состояние и его восстанавливать, но выглядит это чересчур неуклюже и громоздко.
Ой, дайте пять! Мы с другом в детстве записали свою озвучку для Worms 3D (потому что ее там не перевели), разобравшись, где лежат файлы, и затем ускорили наши голоса в стандартном XP-шном звуковом редакторе. Веселые времена :)
Карты в CS 1.6 разрабатывать еще не так сложно, я кое-как сумел разобраться, хотя карты были кривые, а вот для Source… ухх, хотелось бы еще раз попробовать, но боюсь разочароваться в себе.
… со случайно открывающейся во время работы дверцей.
Вот тут полностью согласен, инструмент действительно недружелюбный к новичкам. До сих пор помню, как я не мог понять, как же Dagger работает со scope-ами.
К сожалению, официальный туториал все еще использует ужасный пример с Thermosiphon'ом.
>Паттерны — делегат, строитель. Работа с асинхронностью — корутины.
Так. Есть вероятность, что я чего-то не знаю, поэтому спрошу — в Kotlin есть какая-то особая поддержка Builder'ов? Или вы имели в виду возможность сделать свой DSL?
Оффтопик, но еще бы объяснялось в туториалах лучше, как именно они работают… Я слабо представлял, как корутина может прыгать между тредами (Это же один метод, думал я!) и «приостанавливать» тред и исполнять там другой код, пока не посмотрел под капот, и не понял, что вызов (очень условно) каждой просто нарезает функцию на вызовы с коллбэками.
За такое я бы руки отрывал. Rx — мощнейший инструмент, при использовании которого все приложение строится по-другому, но для некоторых это всего лишь способ вынести запросы на сервер в другой тред… и в итоге наблюдаешь
subscribeвнутриsubscribeТак это не DI, это service locator. Что Koin, что Kodein, по сути, не особо уменьшают связанность классов, они просто перемещают это в другое место. Toothpick, в принципе, то же самое.
Плюс у них отсутствует проверка наличия зависимостей во время компиляции. В маленьком приложении это не так проблемно, а вот в большом это будет вполне себе заметно — раз за разом где-нибудь при тестировании (а то и в продакшене) будет оказываться, что кто-то забыл предоставить зависимость.
Плюс Dagger редко требует от меня явного прописывания создания объектов — если объекту просто нужно предоставить зависимости, я помечу его scope-аннотацией, помечу конструктор
@Inject— и готово, объект будет создан. Явное создание объектов в моделях нужно только в случае, если объект создается нетривиально, в остальных случаях я могу либо не использовать модули, либо использовать@Binds. В Koin/Kodein мне придется каждый раз писать, как именно создавать объект. Сейчас я работаю над очень большим проектом, в котором используется Dagger 2, и, скажу честно, я очень рад, что я могу просто объявить класс, объявить его зависимости, пометить конструктор аннотацией — и все, больше мне не нужно ничего делать.Ну и лично мне очень нравится, как scopes устроены в Dagger 2. Они очень дисциплинируют и не позволяют бездумно раздавать объекты направо и налево.
С
objectом нужно быть очень осторожным, иначе получите плохотестируемое нечто. А если нужен синглтон с зависимостями, тоobjectотправляется гулять. ИМХО,objectя бы использовал только либо как хранилище графа объектов, либо как подклассsealedкласса, у которого нет состояния (ну или какие-то util штуковины).Можно еще примеров? Моя фантазия, к сожалению, ставит меня в тупик.
Не она, случайно?
proandroiddev.com/lets-build-our-own-simplified-version-of-koin-19a887306258
Ух, берлинская любовь к наличным иногда выводит из себя.
Не, ну тут очевидно все, виновато отсутствие бумажки. Писали бы код на бумажке — все было бы идеально. И вовсе не в том, что не так-то сложно придумать задачу, которая даже с возможностью гугления не решится без своих мозгов.
Ага, а потом еще были протесты один-в-один по американской модели — перекроем шоссе, начнем громить рандомные места…
Хорошо хоть, что в Израиле люди в целом не подвержены сказкам об "угнетенных", и все это нашло угасающе малый процент поддержки.
Короче говоря, обычный observer становится совсем необычным.
Плюс нет никакого типирования результата. Хочешь узнать, что тебе пришло из другого фрагмента? Полезай, дружок, в код этого фрагмента и узнай. А если уж вдруг кто-то ошибся и переиспользовал ключ с другим типом данных, то лови ClassCastException.
Понятно, конечно, что все это сделано максимально адски в связи с жизненным циклом Fragment/Activity и возможностью убийства процесса, а, значит, нужно сохранять состояние и его восстанавливать, но выглядит это чересчур неуклюже и громоздко.
Как Андроид-разработчик, я иногда поражаюсь, насколько Гугл любит переусложнять и переизобретать вещи.
До сих пор не понимаю, почему доступ к буферу обмена не является чем-то, к чему приложение может достучаться только после получения на это разрешения