Тёмный

Clean Architecture Android на практике - раздельные модели 

Тимофей Коваленко
Подписаться 9 тыс.
Просмотров 24 тыс.
50% 1

Опубликовано:

 

29 сен 2024

Поделиться:

Ссылка:

Скачать:

Готовим ссылку...

Добавить в:

Мой плейлист
Посмотреть позже
Комментарии : 133   
@TimofeyKovalenko
@TimofeyKovalenko 3 года назад
СОДЕРЖАНИЕ: 00:00:00 - про меня ;) 00:01:21 - обзор проекта с Clean Architecture 00:03:18 - чистая архитектура на диаграмме 00:05:47 - создаем Storage компонент 00:14:14 - Storage компонент на диаграмме 00:16:54 - про раздельные модели на диаграмме 00:21:08 - делаем раздельные модели в коде на Android 00:28:54 - чистим и улучшаем код 00:32:40 - подводим итого
@ohjelmistokehittaja4446
@ohjelmistokehittaja4446 2 года назад
private val userRepository by lazy {UserRepositoryImpl(userStorage = SharedPrefUserStorage(context = applicationContext))} в активити. На следующем уроке скажут.
@МагомедИбрагимов-н8с
Спасибо, полезное видео. Жду следующее 👍
@TimofeyKovalenko
@TimofeyKovalenko 3 года назад
Следующее видео: ru-vid.com/video/%D0%B2%D0%B8%D0%B4%D0%B5%D0%BE-rCkyU5lPAT8.html
@mikhaillazarev5378
@mikhaillazarev5378 Год назад
Очеень полезное видео, спасибо большое!=)
@РоманКовальчук-е2ы
Спасибо за урок.
@ШарьярЕсемуратов-о4х
👍👍👍👍👍👍👍👍👍👍👍
@artlinestudio6735
@artlinestudio6735 3 месяца назад
Да, не простой урок, но очень интересный. Великолепно. Большое спасибо за науку Тимофей.
@MellNaVpiske
@MellNaVpiske Год назад
Спасибо за контент, вы лучший. Но в данном случае приложение не запускается! Ошибка в MainActivity с by lazy {}
@Artur_Maji
@Artur_Maji 9 месяцев назад
Так понятно даже в универе не объясняли насчёт архитектуры и UML, туман рассеивается, благодарю!
@b.shpanchuk
@b.shpanchuk 3 года назад
Спасибо!! Хотелось бы про правильную/красивую организацию мапперов больше :)
@TimofeyKovalenko
@TimofeyKovalenko 3 года назад
Будет отдельное видео, где поговорим о том что можно улучшить в этом приложении, какие варианты есть и тд. И там будем говорить про мапперы.
@Revakovskyi
@Revakovskyi 2 года назад
Ваш курс и уровень доступности ваших объяснений - это бомба петарда ракета 💣🧨🚀🔥 Огромное спасибо вам!
@TimofeyKovalenko
@TimofeyKovalenko 2 года назад
Спасибо)
@kraduschiisyatigrinc3207
@kraduschiisyatigrinc3207 2 года назад
Тимофей, с твоим талантом объяснять, тебе нужно записать видео про асинхронщину, RX, корутины. Было бы здорово!
@TimofeyKovalenko
@TimofeyKovalenko 2 года назад
😎, еще бы время найти на все))).
@beckaksel8783
@beckaksel8783 Год назад
Приветствую, а почему вы не используете data классы для создания моделей?
@TimofeyKovalenko
@TimofeyKovalenko Год назад
А зачем?) Когда будет необходимость именно в дата классе, тогда и сделаем.
@РоманМаринов-ъ3ь
@РоманМаринов-ъ3ь 2 года назад
класс sharedpref нигде не исп-ся, объявленные классы в mainactivity не изменены с прошлого видео
@ДмитрийМещеряков-м3х
Видео - огонь!!!) Так детально и доходчиво пожалуй в ру сегменте мало кто рассказывает. Жаль про мапперы до конца тут не рассмотрено. А не лучше ли мапперы располагать в отдельном пакете на уровне пакетов слоев (дата, домен, презентейшн)? Ведь по факту они особо к конкретному слою не принадлежат и связаны с несколькими слоями.
@TimofeyKovalenko
@TimofeyKovalenko 2 года назад
Нет. Мапперы связаны только с одним слоем. Например, вы мапите из дата в домен. В этом случае домен не должен ничего знать про маперы, он просто получает нужные данные и все. То есть маперы все лежат в дата. Если вынести в отдельный модуль, то есть риск, что это начнуть неверно переиспользовать и все пойдет боком.
@olegleonov1310
@olegleonov1310 2 года назад
Ну так если ты в одной модели поменяешь поля, то придётся менять и в другой модели? Где тогда тут независимость? А если была одна общая модель, то поменял бы в одном месте и всё. Другой пример, когда я хочу добавить ещё одно поле к User, например, адрес. Если у нас есть две модели, то я добавляю в одну, добавляю в другую, потом дописываю маппинг и дописываю сохранение. В случае если у меня одна общая модель, то я добавляю в одной модели и дописываю сохранение - всё. Ради только "независимости" не вижу смысла это делать.
@TimofeyKovalenko
@TimofeyKovalenko 2 года назад
Вы рассматриваете вариант небольшого приложение, где модели, которые пришли, в том же виде выводятся на экран, в этом случае такой маппинг действительно не нужен. Но как только у вас появятся поля, которые есть например в базе данных но их нет в domain модели, то как будите с таким работать? Скорей всего такие модели со временем превратятся в свалку, где невозможно будет разобраться, какие поля и где используются. В более больших проектах, такое разделение, да, требует больше кода, но по итогу защищает код от ошибок, делает код более простым и предсказуемым. Дело далеко не только в независимости слоев, дело в том, что-бы пользовательский код сделать максимально простым, без необходимости думать о том какие поля и как необходимо их использовать.
@allegas1
@allegas1 3 года назад
Реквестирую гайд по корутинам :)
@TimofeyKovalenko
@TimofeyKovalenko 3 года назад
Не в ближайшее время, но обязательно сделаю.
@AndoidAnd
@AndoidAnd 3 месяца назад
очень подробное и крутое объяснение! Я бы сказал, что лучшее на всём RU-vid
@redfox6089
@redfox6089 3 года назад
Спасибо за уроки, может проглядел, но по моему mainActivity нужно подправить, там где контекст передается в UserRepositoryImpl
@TimofeyKovalenko
@TimofeyKovalenko 3 года назад
Да, все верно, просто в видео сфокусировался на дата слое и совсем забыл про activity.
@Serjoo88
@Serjoo88 2 года назад
UserRepositoryImpl(SharedPrefUserStorage(applicationContext)) В следующем видео "Модули в Android Clean Architecture на практике" на 16.01
@НаргизаБаймухамедова
А юзерсторадж где создавать?
@ohjelmistokehittaja4446
@ohjelmistokehittaja4446 2 года назад
private val userRepository by lazy {UserRepositoryImpl(userStorage = SharedPrefUserStorage(context = applicationContext))}
@АнтошаГорохов
@АнтошаГорохов Год назад
@@ohjelmistokehittaja4446 Спасибо огромное за Ваш труд. Можно один глупый вопрос? Обязательно создавать переменную - userStorage: SharedPrefUserStorage? Или можно сразу инстанс передать? - private val userRepository by lazy { UserRepositoryImplementation(SharedPrefsUserStorage(context = applicationContext)) }
@GriNAME
@GriNAME 2 года назад
Очень доступно подается материал. Жалею только, что я раньше не нашел этот канал)
@Rustinesss
@Rustinesss 5 месяцев назад
Спасибо за ваши видео! Они были тем что помогло размешать кашу в моей голове.
@rizvankhairullin2473
@rizvankhairullin2473 Год назад
Где можно задонатить вам ,где ссылка?Хочу отблагодарить ,но не знаю как.
@Relax-4-Relax
@Relax-4-Relax 10 месяцев назад
Не сказать что я чтото понял по клину)) Но понимать где я нахожусь и не терять нить я смог с 4 раза(не подряд естественно)
@rtgtdscfgrthjkgf8388
@rtgtdscfgrthjkgf8388 5 месяцев назад
Пипец путаницу устрол, жесть
@spyro2008
@spyro2008 6 месяцев назад
Спасибо, суперский урок и курс!!!
@Majjabee-np9nq
@Majjabee-np9nq 2 года назад
Привет! Большое спасибо! Круто, весьма круто и на русском языке для джунов!
@dmitryvakh6605
@dmitryvakh6605 Год назад
Спасибо большое за уроки, очень информативные, жалко только то, что вы ссылку на гх не выложили😪
@samuilzhumakhanov6056
@samuilzhumakhanov6056 2 года назад
Благодарю, Тимофей! Очень полезное видео!
@alexkoda6472
@alexkoda6472 Год назад
Тимофей, привет! Подскажи пожалуйста, у меня в классе App, который наследует application и идет в name в манифесте, есть логика по изменению языка всего приложения и ночной темы, в рамках клин архитектуры и архитектуры в целом мне нужно эту логику из App куда-то переносить? Или пусть лежит себе в App, она не очень мудреная, спасибо за ответ
@TimofeyKovalenko
@TimofeyKovalenko Год назад
Без кода, сложно оценить. Но держать это в App не сильно хорошее решение
@kostyatigre
@kostyatigre Год назад
А кто мне доступно объяснит зачем везде пихают мапперы, и почему дата у всех реализует домен? Если мы говорим про разделение, то давайте четко и разделять, без всяких интерфейсов, просто классами все прекрасно разделяется и работает, а интерфейсы - это про другое. Сначала говорим, что Data слой должен быть максимально простой и без логики, а потом туда запихиваем всю логику приложения (реализация domain - она почему-то в data оказывается и никого это не смущает). Entity можно использовать везде (для отображения, обычно еще нужно что-то отформатировать, но так никто не мешает работать с 1 набором моделей и без всяких маперов), clean - не про них вообще. Давайте не писать код ради кода и усложнять этот самый код, затягивая сроки написания чистого и красивого кода.
@TimofeyKovalenko
@TimofeyKovalenko Год назад
Мапперы нужны, что-бы развязать логику и дают возможность каждому компоненту работать со своей моделью, и соответственно делать с ней все, что будет нужно не заботясь об остальных. А добавлять или не добавлять маперы, это уже дело конкретного проекта. Исходя из моего опыта, на длинной дистанции это всегда оправдано. По поводу "почему дата у всех реализует домен" - просто это наиболее частый случай. Реализацию можно писать и в других модулях, да и доменов и дат может быть много в приложении. Насчет логики домена в дате, не понял вас, какая логика из домена у нас оказалась в дате? В нашем случае логики, как таковой, нет вообще, поэтому и юз кейсы простые. Нужно понимать, что это простой проект, просто для примера ;), запихать сюда кучу логики и взорвать мозг студентам не цель данного видео))))).
@Анастасиядр-п2п
@Анастасиядр-п2п 10 месяцев назад
Спасибо!
@anton1evdokimov
@anton1evdokimov 10 месяцев назад
У нас получается полное дублирование модели User в domain и data?
@TimofeyKovalenko
@TimofeyKovalenko 10 месяцев назад
В данном случае да, но в реальном приложении много различий может быть.
@maksym1266
@maksym1266 10 месяцев назад
В конце видео вы анонсировали про мапперы, какие варианты есть с их достоинствами и недостатками. Не могу найти видео на эту тему, его нет? Это очень интересная тема, потому-что моделек уже 2 (хотя для UI тоже бы завести) и иной раз не понятно где хранить маппер который из одного слоя в другой мапит.
@TimofeyKovalenko
@TimofeyKovalenko 10 месяцев назад
Да, отдельного видео по этой теме не было. Я рекомендую использовать kotlin extensions и хранить мапперы либо в отдельном пакете, например mappers, либо рядом с самими модельками.
@alexkoty5877
@alexkoty5877 11 месяцев назад
Тимофей, спасибо большое. Так а в дата слое, в репозитории, может быть логика между загрузкой из сети и базой?
@TimofeyKovalenko
@TimofeyKovalenko 10 месяцев назад
Конечно может.
@ВаняВолошин-я5к
Привіт В мене є наступне питання Слой Data як я розумію відповідає суто за роботу з даними, чи то локальні чи на сервері.Значить якщо мені треба зробити певні операції з цими даними то їх я вже виконую в UseCase класах? І кидаю готові дані після певних операції на ViewModel?
@TimofeyKovalenko
@TimofeyKovalenko Год назад
Да, все верно
@olegkovalenko5708
@olegkovalenko5708 2 года назад
Мужик, спасибо. Круто!
@TimofeyKovalenko
@TimofeyKovalenko 2 года назад
😀
@СергейГорюнов-ы4ч
@СергейГорюнов-ы4ч 3 года назад
Спасибо огромное за материал. Очень доступное объяснение!
@Relax-4-Relax
@Relax-4-Relax 3 месяца назад
добрый день. Я не пойме зачем на вхож используется одна модель saveuserparam на выхо другая useerName
@TimofeyKovalenko
@TimofeyKovalenko 22 дня назад
Потому, что это очень частая ошибка делать одинаковые модели. Например, модель User может содержать id, но при добавлении новых данных у вас еще нет id, и выходит, что вы вынуждены делать поле id nullable, поэтому сразу показал развернутый вариант. Если все поля один в один совпадают, то делать вторую модель не нужно.
@Relax-4-Relax
@Relax-4-Relax 20 дней назад
​@@TimofeyKovalenko Есть еще вопрос по viewModelfactory если вас не затруднит Есть такой вариант передачи параметра в конструктор viewModel ________________________________________ class WeatherViewModel(val repository: WeatherRepository) : ViewModel() { constructor() : this(WeatherRepository(ApiClient().getClient().create(ApiServices::class.java))) __________________________________________ вторичный конструктор который сробатывает после первичтоно Настоклько это хуже фабрики и хуже ли вообще?
@uservhhrXdgko1234
@uservhhrXdgko1234 2 года назад
боже, слов благодарностей таких не существует которыми бы хотелось вас обложить, спасибо большое
@TimofeyKovalenko
@TimofeyKovalenko 2 года назад
Спасибо)
@PandaTop.
@PandaTop. 3 года назад
От вас будут еще уроки по Андроид ? Мне интересно вас слушать и смотреть...
@TimofeyKovalenko
@TimofeyKovalenko 3 года назад
конечно будут), прямо сейчас заливаю новое видео, завтра после обеда(по москве) будет доступно.
@PandaTop.
@PandaTop. 3 года назад
@@TimofeyKovalenko Спасибо. Жду... ))
@TimofeyKovalenko
@TimofeyKovalenko 3 года назад
Следующее видео: ru-vid.com/video/%D0%B2%D0%B8%D0%B4%D0%B5%D0%BE-rCkyU5lPAT8.html
@AnatoliTsoi
@AnatoliTsoi 4 месяца назад
Очень качественный контент! Материал подан простым и доступным языком, все последовательно и систематично 💪
@ВадимТатару-ч6я
@ВадимТатару-ч6я 2 года назад
У меня вопрос: чем отличаются use cases от interactor'а? И, если его ещё нет, будет ли разбор interactor'а?
@juneuniversum
@juneuniversum 2 года назад
Кажется что ничем, это просто другое название юзкейсов.
@TimofeyKovalenko
@TimofeyKovalenko 2 года назад
С точки зрения клин архитектуры - это одно и тоже. Но если почитать умные книжки, то есть какие-то очень тонкие отличия. Так же часто считается, что Use Case содержит только один публичный метод, а Interactor может иметь несколько. Тут нужно понимать, что клин архитектуру можно сделать вообще без юз кейсов или репозиториев, используя другие паттерны и принципы. То есть это все наполнение, а не основа основ клина.
@ВадимТатару-ч6я
@ВадимТатару-ч6я 2 года назад
@@TimofeyKovalenko Понял, спасибо)
@UZEXCEL
@UZEXCEL Год назад
Красота.
@grigorechebac2247
@grigorechebac2247 2 года назад
I'm watching it with passion it's a very interesting video. Thank for the cute video.
@Chybakut2004
@Chybakut2004 2 года назад
Тимофей, спасибо за подробные и качественные разборы Clean Architecture! Есть вопрос насчет ответственности репозитория. Вы сказали, что именно репозиторий решает, в какие хранилища сходить - в интернет, в базу данных, в Shared Preferences или во все одновременно. Но представьте ситуацию, что в рамках одной сущности (например, Фильм) есть два разных сценария: - На экране А нужно скачать фильмы из сети, сложить в базу данных и отобразить на экране. - На экране Б нужно скачать фильмы из сети и сразу отобразить на экране, без складывания в базу данных. В таком случае, необходимо сделать два разных метода в репозитории? Тогда как их именовать? Не логичнее было бы сделать несколько репозиториев, ответственных за конкретное хранилище, а на стороне конкретного UseCase-а обращаться к нужным репозиториям?
@TimofeyKovalenko
@TimofeyKovalenko 2 года назад
В данном случае я бы все же сделал 2 разных юз кейса и разные методы в репозитории. Так в разы понятнее, какой экран, что делает и логика в разы проще и линейнее. Да и это же 2 разных варианта использования вашего приложения, которые заложены логикой, поэтому 2 юз кейса вполне логично. Возможность подкидывать разные реализации в основном нужна для того, что бы если меняется приложение/требования/источники данных, можно было сделать новые реализации по минимум затрагивая текущий код. То есть, по сути, это делается для более гибкого изменения и расширения кода, а не для того, что бы строить вокруг этого логику.
@Chybakut2004
@Chybakut2004 2 года назад
@@TimofeyKovalenko спасибо большое за ответ! Да, насчет 2х юз кейсов сомнений не было, с ними всё предельно понятно, 2 сценария = 2 юз кейса. А вот с репозиториями не до конца понятно. Представьте, что сценарий номер 1 уже реализован, а теперь нужно реализовать сценарий 2. Вроде бы, всё обращение к данным у нас уже реализовано - в сеть ходить умеем, в базу складывать умеем, но почему-то требуется дописать код в слое data, добавив новый метод в репозиторий 🤔 А вот если разбить репозитории по источнику данных, например, FilmNetworkRepository, FilmStorageRepository, тогда юз кейсы смогут по собственному усмотрению пользоваться разными репозиториями в разных ситуциях, и для реализации 2го сценария не пришлось бы редактировать слой data 🤔 Может быть, я не до конца понимаю ответственность репозитория, но мне кажется, что в случае двух разных методов репозитория его реализация и набор методов косвенно становятся зависимы от бизнес-логики, что может привести к его бесконечному разрастанию 🤔
@TimofeyKovalenko
@TimofeyKovalenko 2 года назад
Если я правильно понял, то ваш класс FilmNetworkRepository будет не только в сеть ходить, но и сохранять данные в базу, правильно? Если да, то такое разделение очень запутанно и странно выглядит. Для локальной базы у вас есть FilmStorageRepository. С такой логикой получается, что вы в юз кейсе должны получить данные из FilmNetworkRepository, а затем сохранить их, используя FilmStorageRepository. А в юз кейсе, где нужно только локальные данные читать, обратиться только к FilmStorageRepository. Но, это не совсем правильно, так как данными должен управлять репозиторий, а не UseCase. Тоесть если делаете такое разделение, то не нужно мешать логику внутри. По поводу бесконечного разрастания репозитория, это не проблема, если для разных сущностей вы используете разные репозитория. Очень сомневаюсь, что у вас будет так много вариаций работы с данными, что это заставить писать десятки методов. К тому же очень вряд ли, что методы работы с локальной базой, и методы работы с нетворк у вас будут одинаковые, я имею ввиду их количество и функционал. В реальном проекте, как правило так не бывает. Поэтому я бы рекомендовал все же иметь два метода или один с параметром, который задает конфиг работы с данными. Плюс, я бы сделал интерфейс Storage и от него 2 наследника NetworkStorage и LocalStorage. Эти объекты можно использовать в репозитории (подавать в конструктор естественно), и тем самым вынести работу с чтением/сохранением, и в репозитории оставить только логику работы с данными и манипулировать источниками.
@КахарманБалтабаев-б2о
Шикароный урок!!!
@stasleonov5196
@stasleonov5196 Год назад
Сломался слой Presentation) Но в целом очень, очень здорово, спасибо за труд
@ДятловаСветлана
@ДятловаСветлана 2 года назад
С implementation не поняла. Мы до этого ведь тоже связали UserRepositoryImpl с User Model из domain.
@yuriykyus
@yuriykyus Год назад
Есть вопрос - а как с помощью такого подхода реализовать получение данных из сети? Ведь работа с сетью будет в модуле дата, но методом get в usecase мы вернуть данные из сети не сможет. Дата про presentation нечего не знает чтобы передать туда ответ..
@TimofeyKovalenko
@TimofeyKovalenko Год назад
Не понял вас))), берете корутины и вперед.
@yuriykyus
@yuriykyus Год назад
@@TimofeyKovalenko Понял ). Спасибо!
@АндрейФедоров-к1ч
Посмотрел 3 видео, очень понятно, за пол часа полность переделал свое приложение по клину. У меня уже было какое то подобие, mvvm+repository, но вынес логику из вьюмодели в usecase. Теперь приятно глазу и понимаю, что читать и маштабировать приложение намного легче.Спасибо!
@Mecenatt
@Mecenatt 2 года назад
Круто . А в main activity не нужны исправления ?
@dordzhiev
@dordzhiev Год назад
Почему перекидыванием занимается use case, а не Repository в data слое? Domain ведь не должен знать о data.
@TimofeyKovalenko
@TimofeyKovalenko Год назад
Мы имеете ввиду маперы между разными entity? Мы их в Repository как раз и делаем.
@dordzhiev
@dordzhiev Год назад
​@@TimofeyKovalenko извините, я что-то спутал. У меня есть интерфейс DataProvider, у которого есть имплементации для CSV, XML и JDBC. Я инициализирую для каждой модели Storage свой DataProvider. Затем получается я должен передавать это в отдельный Repository для каждой конкретной модели в Domain, и передать в UseCase, всё верно?
@dordzhiev
@dordzhiev Год назад
​@@TimofeyKovalenkoа ещё мне кажется модели Storage лучше называть Entity, чтобы не было путаницы
@newm_2002
@newm_2002 Год назад
идеальное объяснение, но все равно сложно понять от такого количества классов
@lirjarmuhametova8516
@lirjarmuhametova8516 Год назад
Отличный курс) спасибо большое
@codemachine19
@codemachine19 2 года назад
оч крутое и понятное видео, большое спасибо
@c01nd01r
@c01nd01r Год назад
Посмотрел этот и другие ролики на канале - снимаю шляпу, я в восторге от качества видео и доступности объяснения!
@kaylas2971
@kaylas2971 2 года назад
Для меня открывается новая вселенная!!! Спасибо!
@luckydevil1601
@luckydevil1601 2 года назад
Безумно интересно, спасибо!!
@zoompartyru
@zoompartyru 2 года назад
Отличные материалы. Спасибо!
@sergeyfilatov3027
@sergeyfilatov3027 Год назад
Вы говорите, что слой domain ни от кого не зависит. Но при этом когда описываете setName 28:46 вы импортируете data.storage.User. Получается если вы измените например имя поля в data.storage.User нужно будет все равно лезть в domain исправлять.
@TimofeyKovalenko
@TimofeyKovalenko Год назад
Вы наверное, что-то не досмотрели. Domain модуль не имеет зависимости Data. То есть даже, если бы мы очень захотели использовать data.storage.User в домене, то не смогли бы. Возможно вы спрашиваете про то, что мы использует модель storage в реализации репозитория. Тут проблем нет, так как Storage ни о ком не знает, и те кто его использует, естественно получает Storage модели, и дальше уже маппит или как-то еще использует. Storage это часть более низкого уровня чем репозиторий, поэтому репозиторий и имеет доступ к Storage моделям.
@enikey87
@enikey87 2 года назад
Вы бойлерплейтом в продакшене не давитесь при таком щепетильном следовании догматам Чистой Архитектуры?
@TimofeyKovalenko
@TimofeyKovalenko 2 года назад
Нет). Если проработаете в ентерпрайзах от 3-4 лет в одном проекте, поймете почему.
@vladyslavpasechnyk1319
@vladyslavpasechnyk1319 2 года назад
STORAGE внутри DATA? может правильнее отдельно?
@TimofeyKovalenko
@TimofeyKovalenko 2 года назад
Да, назначение даты как раз и заниматься хранением данных, поэтому в большинстве случаев нет необходимости его выносить. Но если у вас модуль массивный либо используется разными системами, то конечно можно вынести.
@HelloWorld-sy4yc
@HelloWorld-sy4yc 2 года назад
Благодарю вас, Тимофей, за вашу работу! Редкость получать столь уникальные вещи! Ребят, старайтесь побольше практиковаться, а именно на фоне писать какое-то другое свое приложение с использованием каких-то вещей, о которых было рассказано в самом видео. Не стоит код переписывать!
@toniuswar6148
@toniuswar6148 Год назад
Огромное Вам спасибо за контент! В данный момент уже занимаюсь на курсах по андроид разработке. Дошёл до "MVVM", "Dagger-2", "Hilt". Преподаватели стараются, объясняют, но, видимо, я туповат - приходится искать уроки с более простой подачей. Недавно открыл для себя Ваш канал. Теперь жалею, что занимаюсь не на Ваших курсах.
@sovaz1997
@sovaz1997 10 месяцев назад
Если это первый ваш опыт разработки, то это абсолютно нормально - процесс не быстрый)
@karamba6936
@karamba6936 Год назад
То есть получается дата и домен работают с отдельными своими типами объектов, но эти типы связаны логикой приложения. А маперы в репозитории приводят один тип к другому для передачи между слоями?
@TimofeyKovalenko
@TimofeyKovalenko Год назад
Да. Каждый слой делает свою логику использую только свои модели, а если нужно связаться с другим слоем, то маппим.
@barnomasoz
@barnomasoz 2 года назад
Спасибо за урок. Но у меня есть сомнений. В слое domain есть модел UsernameModel и при добавление еще одно поле в конструктор данного класса в Storage появится ошибка. Это правильно или нет?
@TimofeyKovalenko
@TimofeyKovalenko 2 года назад
Да, все тут верно. Просто домена модель это один API, storage это совсем другой API. Если задача подразумевает и там и там менять, то да, нужно поменять в двух местах. А если вы будите одну и туже модель использовать для UI и для Storage, то во первых модель может обрасти специфическими данными, которые нужны только кому-то одному, а во вторых при изменении модели вы сразу измените совершенно разные компоненты. Архитектура это не про то, что-бы быстро накидать код, а про удобство на длинной дистанции.
@mujlugun1156
@mujlugun1156 Год назад
привет, хороший курс посмотрел все видео класс . хотел бы послушать про mapper- и и про экстеншены. может у тебя есть про это видео? спасибо ❤
@TimofeyKovalenko
@TimofeyKovalenko Год назад
Про мапперы будет в ближайших видео.
@serg888fert4
@serg888fert4 2 года назад
А если в модели в domain что-то изменится, то маппере тоже надо вносить изменения. не получается полной независимости.
@TimofeyKovalenko
@TimofeyKovalenko 2 года назад
Если логика поменялась, понятное дело зависимости тоже нужно менять. Независимость достигается тем, что каждая часть имеет свой API(свои методы и ентити) и их реализация не зависит от хотелок того, кто будет использовать эту логику. То есть domain не зависит от потребителей, а потребитель всегда подчиняется правилам API. К тому же, если у вас что-то поменялось в домене, вам это что-то требуется использовать - показать на экране или еще как то - тут никакая независимость не поможет))). В этом случае правильнее не изменять текущую логику, а добавить новую.
@vesh95
@vesh95 2 года назад
Я считаю, что в домене не обязательно должен быть стораж интерфейс, если мы собираемся работать с данными по интерфейсу репозитория
@TimofeyKovalenko
@TimofeyKovalenko 2 года назад
Да, они там не нужны. Дальше по видео мы их и не размещаем в домене, все это размещаем в data.
@СемёнШудегов
@СемёнШудегов 2 года назад
Качественный контент!!!
@frantsuzfrantsuz9237
@frantsuzfrantsuz9237 2 года назад
разве domain не стал зависить от data из-за класса User?
@TimofeyKovalenko
@TimofeyKovalenko 2 года назад
Нет, каким образом? Data не подключена к domain, даже если очень захотеть, этого не получится).
@sovrinfo
@sovrinfo 3 года назад
Спасибо за видео.Коммент в поддержку!
@TimofeyKovalenko
@TimofeyKovalenko 3 года назад
Спасибо)
@ЕвгенийЕршов-п6э
@ЕвгенийЕршов-п6э 2 года назад
Спасибо за уроки! А данный код не скинете например на гитхаб? Также не понял название методов с приставкой map. Логичнее например userToUserName(), а не mapToDomain() ?
@TimofeyKovalenko
@TimofeyKovalenko 2 года назад
В котлине, RX и в многих других фреймворках/языках есть стандартные методы, которые как раз называются map и делают конвертацию данных. Также это просто общеупотребительное слово для подобных операций и такое название будет понятно большинству программистов. userToUserName как раз таки не говорит о том, что будет делаться, вообще названия методов лучше начинать с глагола.
@TimofeyKovalenko
@TimofeyKovalenko 2 года назад
По поводу кода нет, никогда не скидываю студентам код на котором показываю примеры, иначе толку от лекции нет. Понять можно только если самому написать.
@diyorbek5664
@diyorbek5664 2 года назад
привет Тимофей спасибо за контент ! советую c UML )
@TimofeyKovalenko
@TimofeyKovalenko 2 года назад
Нет смысла показывать такие схемы по UML), иначе придется еще и курс по UML делать предварительно)))).
@diyorbek5664
@diyorbek5664 2 года назад
@@TimofeyKovalenko )) такие схемы и показываются на UML) ! не нестоит ,просто в начале видео покажи стрелки зависемости,наследование, реализаций ,и это на 100 хватит в этом видео
@it-vk8ik
@it-vk8ik 2 года назад
получается если я сделаю RoomUserStorage у которого свои entity с аннотациями, я должен внутри storage скоупа мапить из UserEntity(RoomUserStorage) -> User(UserStorage) и прокинуть в Repository который смапит в UserName(Domain)?
@TimofeyKovalenko
@TimofeyKovalenko 2 года назад
Storage не должен знать ни о чем вокруг него, маппинг делаете за пределами storage. То есть репозиторий получит entity из Storage и далее должен будет их замапить.
@it-vk8ik
@it-vk8ik 2 года назад
@@TimofeyKovalenko нет смотрите , UserStorage - интерфейс, и репозиторий не знает ничего о реализации ,там может быть NetworkUserStorage , RoomUserStorage , SharedPrefUserStorage - и у каждого будут свои сущности с аннотациями, может и нет), также могут присутствовать лишние поля которые не нужны дальше. Вы говорите "репозиторий получит entity из Storage и далее должен будет их замапить." - это же означает, что теперь репозиторий хоть работает с интерфейсам, но все же жестко зависит от Room имплементации, из за мапинга. Поэтому может каждая имлементация внутри Storage скоупа должна смапить к обобщенной модельки которая будет независимой(без аннотации итд) , и прокидать в репозиторий который будет мапить Storage модельку в Domain модель - и тут репо теперь не знает о реализации надеюсь смог объяснить :)
@TimofeyKovalenko
@TimofeyKovalenko Год назад
Если модели разные, то это будут совершенно разные интерфейсы. Репозиторий просто будет работать с каждым по отдельности. Вы пытаетесь сделать так, что-бы Storage подстроился под требования репозитория, но так делать не стоит. Да и выглядит так, что вы выносите логику репозитория в Storage. На практике, практически никогда не делают один интерфейс для нетворка и локального хранилища, это не удобно и сильно ограничивает вас в дальнейшем,
@it-vk8ik
@it-vk8ik Год назад
@@TimofeyKovalenko да вы правы) , согласен что не делают один интерфейс для нетворка и локального хранилища вот последний вопрос, извиняюсь). У нас есть условно 4 репозитория которые зависят от LocalDataStorage и у него была RealmLocalDataStorageImpl или какой то другая impl не важно, через некоторое время мы мигрировали на RoomLocalDataStorageImpl и это все внутренности LocalDataStorage о котором не должны знать клиенты - то есть те которые зависят от этого стораджа. подскажите какую модельку должен предоставить LocalDataStorage чтобы каждый клиент не ломался от нашей миграции?
@Мах-в2п
@Мах-в2п Год назад
Супер!
Далее
🦊🎀
00:16
Просмотров 311 тыс.
Редакция. News: 136-я неделя
45:09
Просмотров 1,4 млн
MVVM в Android на практике
41:32
Просмотров 48 тыс.
Koin в Android на практике c MVVM
28:08
Просмотров 23 тыс.