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

Поділитися
Вставка
  • Опубліковано 6 лют 2025

КОМЕНТАРІ • 138

  • @TimofeyKovalenko
    @TimofeyKovalenko  3 роки тому +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 - подводим итого

  • @Artur_Maji
    @Artur_Maji Рік тому +2

    Так понятно даже в универе не объясняли насчёт архитектуры и UML, туман рассеивается, благодарю!

  • @Revakovskyi
    @Revakovskyi 2 роки тому +15

    Ваш курс и уровень доступности ваших объяснений - это бомба петарда ракета 💣🧨🚀🔥 Огромное спасибо вам!

  • @artlinestudio6735
    @artlinestudio6735 8 місяців тому +1

    Да, не простой урок, но очень интересный. Великолепно. Большое спасибо за науку Тимофей.

  • @uservhhrXdgko1234
    @uservhhrXdgko1234 3 роки тому +1

    боже, слов благодарностей таких не существует которыми бы хотелось вас обложить, спасибо большое

  • @GriNAME
    @GriNAME 3 роки тому +3

    Очень доступно подается материал. Жалею только, что я раньше не нашел этот канал)

  • @b.shpanchuk
    @b.shpanchuk 3 роки тому +11

    Спасибо!! Хотелось бы про правильную/красивую организацию мапперов больше :)

    • @TimofeyKovalenko
      @TimofeyKovalenko  3 роки тому +5

      Будет отдельное видео, где поговорим о том что можно улучшить в этом приложении, какие варианты есть и тд. И там будем говорить про мапперы.

  • @МагомедИбрагимов-н8с

    Спасибо, полезное видео. Жду следующее 👍

    • @TimofeyKovalenko
      @TimofeyKovalenko  3 роки тому

      Следующее видео: ua-cam.com/video/rCkyU5lPAT8/v-deo.html

  • @kraduschiisyatigrinc3207
    @kraduschiisyatigrinc3207 3 роки тому +6

    Тимофей, с твоим талантом объяснять, тебе нужно записать видео про асинхронщину, RX, корутины. Было бы здорово!

    • @TimofeyKovalenko
      @TimofeyKovalenko  3 роки тому +2

      😎, еще бы время найти на все))).

  • @AnatoliTsoi
    @AnatoliTsoi 9 місяців тому

    Очень качественный контент! Материал подан простым и доступным языком, все последовательно и систематично 💪

  • @ohjelmistokehittaja4446
    @ohjelmistokehittaja4446 2 роки тому +7

    private val userRepository by lazy {UserRepositoryImpl(userStorage = SharedPrefUserStorage(context = applicationContext))} в активити. На следующем уроке скажут.

  • @АндрейФедоров-к1ч

    Посмотрел 3 видео, очень понятно, за пол часа полность переделал свое приложение по клину. У меня уже было какое то подобие, mvvm+repository, но вынес логику из вьюмодели в usecase. Теперь приятно глазу и понимаю, что читать и маштабировать приложение намного легче.Спасибо!

  • @spyro2008
    @spyro2008 10 місяців тому

    Спасибо, суперский урок и курс!!!

  • @c01nd01r
    @c01nd01r 2 роки тому

    Посмотрел этот и другие ролики на канале - снимаю шляпу, я в восторге от качества видео и доступности объяснения!

  • @ssbykov
    @ssbykov 3 місяці тому

    Спасибо большое за материал. Уже пишу свои приложения, но эти знания прямо в тему. В идеале немного поработать над звуком. Если честно, немного отвлекают посторонние звучки вроде причмокивания, сглатывания и тд. Уж извините за эту откровенность. Сам материал очень понравился. Еще раз спасибо! )

  • @olegkovalenko5708
    @olegkovalenko5708 2 роки тому +1

    Мужик, спасибо. Круто!

  • @ДмитрийМещеряков-м3х

    Видео - огонь!!!) Так детально и доходчиво пожалуй в ру сегменте мало кто рассказывает. Жаль про мапперы до конца тут не рассмотрено.
    А не лучше ли мапперы располагать в отдельном пакете на уровне пакетов слоев (дата, домен, презентейшн)? Ведь по факту они особо к конкретному слою не принадлежат и связаны с несколькими слоями.

    • @TimofeyKovalenko
      @TimofeyKovalenko  2 роки тому +4

      Нет. Мапперы связаны только с одним слоем. Например, вы мапите из дата в домен. В этом случае домен не должен ничего знать про маперы, он просто получает нужные данные и все. То есть маперы все лежат в дата.
      Если вынести в отдельный модуль, то есть риск, что это начнуть неверно переиспользовать и все пойдет боком.

  • @Rustinesss
    @Rustinesss 10 місяців тому

    Спасибо за ваши видео! Они были тем что помогло размешать кашу в моей голове.

  • @firdavsdj5491
    @firdavsdj5491 4 місяці тому

    Спасибо Тимофей у вас лучшие уроки 👍

  • @КахарманБалтабаев-б2о

    Шикароный урок!!!

  • @luckydevil1601
    @luckydevil1601 2 роки тому

    Безумно интересно, спасибо!!

  • @toniuswar6148
    @toniuswar6148 Рік тому

    Огромное Вам спасибо за контент! В данный момент уже занимаюсь на курсах по андроид разработке. Дошёл до "MVVM", "Dagger-2", "Hilt". Преподаватели стараются, объясняют, но, видимо, я туповат - приходится искать уроки с более простой подачей. Недавно открыл для себя Ваш канал. Теперь жалею, что занимаюсь не на Ваших курсах.

    • @sovaz1997
      @sovaz1997 Рік тому

      Если это первый ваш опыт разработки, то это абсолютно нормально - процесс не быстрый)

  • @samuilzhumakhanov6056
    @samuilzhumakhanov6056 3 роки тому +1

    Благодарю, Тимофей! Очень полезное видео!

  • @СергейГорюнов-ы4ч
    @СергейГорюнов-ы4ч 3 роки тому +1

    Спасибо огромное за материал. Очень доступное объяснение!

  • @mikhaillazarev5378
    @mikhaillazarev5378 2 роки тому

    Очеень полезное видео, спасибо большое!=)

  • @AndoidAnd
    @AndoidAnd 7 місяців тому

    очень подробное и крутое объяснение! Я бы сказал, что лучшее на всём UA-cam

  • @lirjarmuhametova8516
    @lirjarmuhametova8516 2 роки тому

    Отличный курс) спасибо большое

  • @sovrinfo
    @sovrinfo 3 роки тому

    Спасибо за видео.Коммент в поддержку!

  • @zoompartyru
    @zoompartyru 2 роки тому

    Отличные материалы. Спасибо!

  • @UZEXCEL
    @UZEXCEL Рік тому

    Красота.

  • @sergeyfilatov3027
    @sergeyfilatov3027 2 роки тому

    Вы говорите, что слой domain ни от кого не зависит. Но при этом когда описываете setName 28:46 вы импортируете data.storage.User. Получается если вы измените например имя поля в data.storage.User нужно будет все равно лезть в domain исправлять.

    • @TimofeyKovalenko
      @TimofeyKovalenko  2 роки тому

      Вы наверное, что-то не досмотрели. Domain модуль не имеет зависимости Data. То есть даже, если бы мы очень захотели использовать data.storage.User в домене, то не смогли бы. Возможно вы спрашиваете про то, что мы использует модель storage в реализации репозитория. Тут проблем нет, так как Storage ни о ком не знает, и те кто его использует, естественно получает Storage модели, и дальше уже маппит или как-то еще использует. Storage это часть более низкого уровня чем репозиторий, поэтому репозиторий и имеет доступ к Storage моделям.

  • @redfox6089
    @redfox6089 3 роки тому +6

    Спасибо за уроки, может проглядел, но по моему mainActivity нужно подправить, там где контекст передается в UserRepositoryImpl

    • @TimofeyKovalenko
      @TimofeyKovalenko  3 роки тому +1

      Да, все верно, просто в видео сфокусировался на дата слое и совсем забыл про activity.

    • @Serjoo88
      @Serjoo88 2 роки тому

      UserRepositoryImpl(SharedPrefUserStorage(applicationContext))
      В следующем видео "Модули в Android Clean Architecture на практике" на 16.01

    • @НаргизаБаймухамедова
      @НаргизаБаймухамедова 2 роки тому

      А юзерсторадж где создавать?

    • @ohjelmistokehittaja4446
      @ohjelmistokehittaja4446 2 роки тому +1

      private val userRepository by lazy {UserRepositoryImpl(userStorage = SharedPrefUserStorage(context = applicationContext))}

    • @АнтошаГорохов
      @АнтошаГорохов Рік тому

      @@ohjelmistokehittaja4446 Спасибо огромное за Ваш труд. Можно один глупый вопрос? Обязательно создавать переменную - userStorage: SharedPrefUserStorage? Или можно сразу инстанс передать? - private val userRepository by lazy { UserRepositoryImplementation(SharedPrefsUserStorage(context = applicationContext)) }

  • @Анастасиядр-п2п

    Спасибо!

  • @СемёнШудегов
    @СемёнШудегов 3 роки тому

    Качественный контент!!!

  • @dmitryvakh6605
    @dmitryvakh6605 Рік тому

    Спасибо большое за уроки, очень информативные, жалко только то, что вы ссылку на гх не выложили😪

  • @stasleonov5196
    @stasleonov5196 2 роки тому

    Сломался слой Presentation) Но в целом очень, очень здорово, спасибо за труд

  • @РоманКовальчук-е2ы

    Спасибо за урок.

  • @codemachine19
    @codemachine19 2 роки тому

    оч крутое и понятное видео, большое спасибо

  • @kaylas2971
    @kaylas2971 3 роки тому

    Для меня открывается новая вселенная!!! Спасибо!

  • @allegas1
    @allegas1 3 роки тому +2

    Реквестирую гайд по корутинам :)

    • @TimofeyKovalenko
      @TimofeyKovalenko  3 роки тому

      Не в ближайшее время, но обязательно сделаю.

  • @maksym1266
    @maksym1266 Рік тому

    В конце видео вы анонсировали про мапперы, какие варианты есть с их достоинствами и недостатками. Не могу найти видео на эту тему, его нет? Это очень интересная тема, потому-что моделек уже 2 (хотя для UI тоже бы завести) и иной раз не понятно где хранить маппер который из одного слоя в другой мапит.

    • @TimofeyKovalenko
      @TimofeyKovalenko  Рік тому

      Да, отдельного видео по этой теме не было. Я рекомендую использовать kotlin extensions и хранить мапперы либо в отдельном пакете, например mappers, либо рядом с самими модельками.

  • @konstantinmezler5238
    @konstantinmezler5238 2 місяці тому

    Спасибо

  • @Мах-в2п
    @Мах-в2п 2 роки тому

    Супер!

  • @Chybakut2004
    @Chybakut2004 3 роки тому +2

    Тимофей, спасибо за подробные и качественные разборы Clean Architecture! Есть вопрос насчет ответственности репозитория. Вы сказали, что именно репозиторий решает, в какие хранилища сходить - в интернет, в базу данных, в Shared Preferences или во все одновременно. Но представьте ситуацию, что в рамках одной сущности (например, Фильм) есть два разных сценария:
    - На экране А нужно скачать фильмы из сети, сложить в базу данных и отобразить на экране.
    - На экране Б нужно скачать фильмы из сети и сразу отобразить на экране, без складывания в базу данных.
    В таком случае, необходимо сделать два разных метода в репозитории? Тогда как их именовать? Не логичнее было бы сделать несколько репозиториев, ответственных за конкретное хранилище, а на стороне конкретного UseCase-а обращаться к нужным репозиториям?

    • @TimofeyKovalenko
      @TimofeyKovalenko  3 роки тому +3

      В данном случае я бы все же сделал 2 разных юз кейса и разные методы в репозитории. Так в разы понятнее, какой экран, что делает и логика в разы проще и линейнее. Да и это же 2 разных варианта использования вашего приложения, которые заложены логикой, поэтому 2 юз кейса вполне логично.
      Возможность подкидывать разные реализации в основном нужна для того, что бы если меняется приложение/требования/источники данных, можно было сделать новые реализации по минимум затрагивая текущий код. То есть, по сути, это делается для более гибкого изменения и расширения кода, а не для того, что бы строить вокруг этого логику.

    • @Chybakut2004
      @Chybakut2004 3 роки тому +1

      @@TimofeyKovalenko спасибо большое за ответ! Да, насчет 2х юз кейсов сомнений не было, с ними всё предельно понятно, 2 сценария = 2 юз кейса. А вот с репозиториями не до конца понятно. Представьте, что сценарий номер 1 уже реализован, а теперь нужно реализовать сценарий 2. Вроде бы, всё обращение к данным у нас уже реализовано - в сеть ходить умеем, в базу складывать умеем, но почему-то требуется дописать код в слое data, добавив новый метод в репозиторий 🤔 А вот если разбить репозитории по источнику данных, например, FilmNetworkRepository, FilmStorageRepository, тогда юз кейсы смогут по собственному усмотрению пользоваться разными репозиториями в разных ситуциях, и для реализации 2го сценария не пришлось бы редактировать слой data 🤔 Может быть, я не до конца понимаю ответственность репозитория, но мне кажется, что в случае двух разных методов репозитория его реализация и набор методов косвенно становятся зависимы от бизнес-логики, что может привести к его бесконечному разрастанию 🤔

    • @TimofeyKovalenko
      @TimofeyKovalenko  3 роки тому +7

      Если я правильно понял, то ваш класс FilmNetworkRepository будет не только в сеть ходить, но и сохранять данные в базу, правильно? Если да, то такое разделение очень запутанно и странно выглядит. Для локальной базы у вас есть FilmStorageRepository. С такой логикой получается, что вы в юз кейсе должны получить данные из FilmNetworkRepository, а затем сохранить их, используя FilmStorageRepository. А в юз кейсе, где нужно только локальные данные читать, обратиться только к FilmStorageRepository.
      Но, это не совсем правильно, так как данными должен управлять репозиторий, а не UseCase. Тоесть если делаете такое разделение, то не нужно мешать логику внутри.
      По поводу бесконечного разрастания репозитория, это не проблема, если для разных сущностей вы используете разные репозитория. Очень сомневаюсь, что у вас будет так много вариаций работы с данными, что это заставить писать десятки методов.
      К тому же очень вряд ли, что методы работы с локальной базой, и методы работы с нетворк у вас будут одинаковые, я имею ввиду их количество и функционал. В реальном проекте, как правило так не бывает.
      Поэтому я бы рекомендовал все же иметь два метода или один с параметром, который задает конфиг работы с данными. Плюс, я бы сделал интерфейс Storage и от него 2 наследника NetworkStorage и LocalStorage. Эти объекты можно использовать в репозитории (подавать в конструктор естественно), и тем самым вынести работу с чтением/сохранением, и в репозитории оставить только логику работы с данными и манипулировать источниками.

  • @HelloWorld-sy4yc
    @HelloWorld-sy4yc 3 роки тому +4

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

  • @Relax-4-Relax
    @Relax-4-Relax Рік тому

    Не сказать что я чтото понял по клину)) Но понимать где я нахожусь и не терять нить я смог с 4 раза(не подряд естественно)

  • @beckaksel8783
    @beckaksel8783 Рік тому +2

    Приветствую, а почему вы не используете data классы для создания моделей?

    • @TimofeyKovalenko
      @TimofeyKovalenko  Рік тому

      А зачем?) Когда будет необходимость именно в дата классе, тогда и сделаем.

  • @PandaTop.
    @PandaTop. 3 роки тому +1

    От вас будут еще уроки по Андроид ? Мне интересно вас слушать и смотреть...

    • @TimofeyKovalenko
      @TimofeyKovalenko  3 роки тому +1

      конечно будут), прямо сейчас заливаю новое видео, завтра после обеда(по москве) будет доступно.

    • @PandaTop.
      @PandaTop. 3 роки тому +1

      @@TimofeyKovalenko Спасибо. Жду... ))

    • @TimofeyKovalenko
      @TimofeyKovalenko  3 роки тому +1

      Следующее видео: ua-cam.com/video/rCkyU5lPAT8/v-deo.html

  • @grigorechebac2247
    @grigorechebac2247 2 роки тому

    I'm watching it with passion it's a very interesting video.
    Thank for the cute video.

  • @olegleonov1310
    @olegleonov1310 3 роки тому +3

    Ну так если ты в одной модели поменяешь поля, то придётся менять и в другой модели? Где тогда тут независимость? А если была одна общая модель, то поменял бы в одном месте и всё.
    Другой пример, когда я хочу добавить ещё одно поле к User, например, адрес. Если у нас есть две модели, то я добавляю в одну, добавляю в другую, потом дописываю маппинг и дописываю сохранение. В случае если у меня одна общая модель, то я добавляю в одной модели и дописываю сохранение - всё. Ради только "независимости" не вижу смысла это делать.

    • @TimofeyKovalenko
      @TimofeyKovalenko  3 роки тому +3

      Вы рассматриваете вариант небольшого приложение, где модели, которые пришли, в том же виде выводятся на экран, в этом случае такой маппинг действительно не нужен. Но как только у вас появятся поля, которые есть например в базе данных но их нет в domain модели, то как будите с таким работать? Скорей всего такие модели со временем превратятся в свалку, где невозможно будет разобраться, какие поля и где используются.
      В более больших проектах, такое разделение, да, требует больше кода, но по итогу защищает код от ошибок, делает код более простым и предсказуемым. Дело далеко не только в независимости слоев, дело в том, что-бы пользовательский код сделать максимально простым, без необходимости думать о том какие поля и как необходимо их использовать.

  • @alexkoty5877
    @alexkoty5877 Рік тому

    Тимофей, спасибо большое. Так а в дата слое, в репозитории, может быть логика между загрузкой из сети и базой?

  • @ДятловаСветлана
    @ДятловаСветлана 2 роки тому

    С implementation не поняла. Мы до этого ведь тоже связали UserRepositoryImpl с User Model из domain.

  • @mujlugun1156
    @mujlugun1156 2 роки тому

    привет, хороший курс посмотрел все видео класс . хотел бы послушать про mapper- и и про экстеншены. может у тебя есть про это видео?
    спасибо ❤

    • @TimofeyKovalenko
      @TimofeyKovalenko  2 роки тому +1

      Про мапперы будет в ближайших видео.

  • @ШарьярЕсемуратов-о4х

    👍👍👍👍👍👍👍👍👍👍👍

  • @ВадимТатару-ч6я
    @ВадимТатару-ч6я 2 роки тому +1

    У меня вопрос: чем отличаются use cases от interactor'а? И, если его ещё нет, будет ли разбор interactor'а?

    • @juneuniversum
      @juneuniversum 2 роки тому +1

      Кажется что ничем, это просто другое название юзкейсов.

    • @TimofeyKovalenko
      @TimofeyKovalenko  2 роки тому

      С точки зрения клин архитектуры - это одно и тоже. Но если почитать умные книжки, то есть какие-то очень тонкие отличия. Так же часто считается, что Use Case содержит только один публичный метод, а Interactor может иметь несколько.
      Тут нужно понимать, что клин архитектуру можно сделать вообще без юз кейсов или репозиториев, используя другие паттерны и принципы. То есть это все наполнение, а не основа основ клина.

    • @ВадимТатару-ч6я
      @ВадимТатару-ч6я 2 роки тому

      @@TimofeyKovalenko Понял, спасибо)

  • @Mecenatt
    @Mecenatt 2 роки тому

    Круто . А в main activity не нужны исправления ?

  • @alexkoda6472
    @alexkoda6472 Рік тому

    Тимофей, привет! Подскажи пожалуйста, у меня в классе App, который наследует application и идет в name в манифесте, есть логика по изменению языка всего приложения и ночной темы, в рамках клин архитектуры и архитектуры в целом мне нужно эту логику из App куда-то переносить? Или пусть лежит себе в App, она не очень мудреная, спасибо за ответ

    • @TimofeyKovalenko
      @TimofeyKovalenko  Рік тому +1

      Без кода, сложно оценить. Но держать это в App не сильно хорошее решение

  • @holyglory2339
    @holyglory2339 3 місяці тому

    Тимофей, у меня такой вопрос.
    Если у нас в Дата слое имеется база данных со связью один ко многим
    и нам нужно работать с дочерней сущностью, то как быть со внешним ключом?
    Мы его тоже должны передавать в Домен?
    Я слышал такую версию, что в Домен слое в модели мы храним
    только ссылку на родительский объект (который тоже является моделью)
    А уже в дата слое мы храним внешний ключ, как в базе данных?
    Так ли это?

    • @TimofeyKovalenko
      @TimofeyKovalenko  7 днів тому

      Не совсем понял ваш вопрос. База и разные модули - это совсем не верный вопрос. Все, что связано с базой должно лежать рядом в базе, тоесть в дата слое. Домен ничего не знает про базу и не может иметь никаких моделей, которые связаны с базой данных.

  • @vesh95
    @vesh95 2 роки тому

    Я считаю, что в домене не обязательно должен быть стораж интерфейс, если мы собираемся работать с данными по интерфейсу репозитория

    • @TimofeyKovalenko
      @TimofeyKovalenko  2 роки тому

      Да, они там не нужны. Дальше по видео мы их и не размещаем в домене, все это размещаем в data.

  • @anton1evdokimov
    @anton1evdokimov Рік тому

    У нас получается полное дублирование модели User в domain и data?

    • @TimofeyKovalenko
      @TimofeyKovalenko  Рік тому

      В данном случае да, но в реальном приложении много различий может быть.

  • @yuriykyus
    @yuriykyus Рік тому

    Есть вопрос - а как с помощью такого подхода реализовать получение данных из сети? Ведь работа с сетью будет в модуле дата, но методом get в usecase мы вернуть данные из сети не сможет. Дата про presentation нечего не знает чтобы передать туда ответ..

    • @TimofeyKovalenko
      @TimofeyKovalenko  Рік тому

      Не понял вас))), берете корутины и вперед.

    • @yuriykyus
      @yuriykyus Рік тому

      @@TimofeyKovalenko Понял ). Спасибо!

  • @Relax-4-Relax
    @Relax-4-Relax 7 місяців тому

    добрый день. Я не пойме зачем на вхож используется одна модель saveuserparam на выхо другая useerName

    • @TimofeyKovalenko
      @TimofeyKovalenko  5 місяців тому

      Потому, что это очень частая ошибка делать одинаковые модели. Например, модель User может содержать id, но при добавлении новых данных у вас еще нет id, и выходит, что вы вынуждены делать поле id nullable, поэтому сразу показал развернутый вариант.
      Если все поля один в один совпадают, то делать вторую модель не нужно.

    • @Relax-4-Relax
      @Relax-4-Relax 4 місяці тому

      ​@@TimofeyKovalenko Есть еще вопрос по viewModelfactory
      если вас не затруднит
      Есть такой вариант передачи параметра в конструктор viewModel
      ________________________________________
      class WeatherViewModel(val repository: WeatherRepository) : ViewModel() {
      constructor() : this(WeatherRepository(ApiClient().getClient().create(ApiServices::class.java)))
      __________________________________________
      вторичный конструктор который сробатывает после первичтоно
      Настоклько это хуже фабрики и хуже ли вообще?

  • @РоманМаринов-ъ3ь
    @РоманМаринов-ъ3ь 2 роки тому +1

    класс sharedpref нигде не исп-ся, объявленные классы в mainactivity не изменены с прошлого видео

  • @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, чтобы не было путаницы

  • @serg888fert4
    @serg888fert4 2 роки тому

    А если в модели в domain что-то изменится, то маппере тоже надо вносить изменения. не получается полной независимости.

    • @TimofeyKovalenko
      @TimofeyKovalenko  2 роки тому

      Если логика поменялась, понятное дело зависимости тоже нужно менять. Независимость достигается тем, что каждая часть имеет свой API(свои методы и ентити) и их реализация не зависит от хотелок того, кто будет использовать эту логику. То есть domain не зависит от потребителей, а потребитель всегда подчиняется правилам API.
      К тому же, если у вас что-то поменялось в домене, вам это что-то требуется использовать - показать на экране или еще как то - тут никакая независимость не поможет))).
      В этом случае правильнее не изменять текущую логику, а добавить новую.

  • @ЕвгенийЕршов-п6э
    @ЕвгенийЕршов-п6э 3 роки тому

    Спасибо за уроки! А данный код не скинете например на гитхаб? Также не понял название методов с приставкой map. Логичнее например userToUserName(), а не mapToDomain() ?

    • @TimofeyKovalenko
      @TimofeyKovalenko  3 роки тому +1

      В котлине, RX и в многих других фреймворках/языках есть стандартные методы, которые как раз называются map и делают конвертацию данных. Также это просто общеупотребительное слово для подобных операций и такое название будет понятно большинству программистов.
      userToUserName как раз таки не говорит о том, что будет делаться, вообще названия методов лучше начинать с глагола.

    • @TimofeyKovalenko
      @TimofeyKovalenko  3 роки тому +7

      По поводу кода нет, никогда не скидываю студентам код на котором показываю примеры, иначе толку от лекции нет. Понять можно только если самому написать.

  • @Majjabee-np9nq
    @Majjabee-np9nq 3 роки тому +1

    Привет! Большое спасибо! Круто, весьма круто и на русском языке для джунов!

  • @MellNaVpiske
    @MellNaVpiske Рік тому +1

    Спасибо за контент, вы лучший. Но в данном случае приложение не запускается! Ошибка в MainActivity с by lazy {}

  • @rizvankhairullin2473
    @rizvankhairullin2473 Рік тому

    Где можно задонатить вам ,где ссылка?Хочу отблагодарить ,но не знаю как.

  • @karamba6936
    @karamba6936 2 роки тому

    То есть получается дата и домен работают с отдельными своими типами объектов, но эти типы связаны логикой приложения. А маперы в репозитории приводят один тип к другому для передачи между слоями?

    • @TimofeyKovalenko
      @TimofeyKovalenko  2 роки тому

      Да. Каждый слой делает свою логику использую только свои модели, а если нужно связаться с другим слоем, то маппим.

  • @newm_2002
    @newm_2002 2 роки тому

    идеальное объяснение, но все равно сложно понять от такого количества классов

  • @ВаняВолошин-я5к

    Привіт
    В мене є наступне питання
    Слой Data як я розумію відповідає суто за роботу з даними, чи то локальні чи на сервері.Значить якщо мені треба зробити певні операції з цими даними то їх я вже виконую в UseCase класах? І кидаю готові дані після певних операції на ViewModel?

  • @enikey87
    @enikey87 2 роки тому

    Вы бойлерплейтом в продакшене не давитесь при таком щепетильном следовании догматам Чистой Архитектуры?

    • @TimofeyKovalenko
      @TimofeyKovalenko  2 роки тому +1

      Нет). Если проработаете в ентерпрайзах от 3-4 лет в одном проекте, поймете почему.

  • @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  2 роки тому

      Если модели разные, то это будут совершенно разные интерфейсы. Репозиторий просто будет работать с каждым по отдельности. Вы пытаетесь сделать так, что-бы Storage подстроился под требования репозитория, но так делать не стоит. Да и выглядит так, что вы выносите логику репозитория в Storage.
      На практике, практически никогда не делают один интерфейс для нетворка и локального хранилища, это не удобно и сильно ограничивает вас в дальнейшем,

    • @it-vk8ik
      @it-vk8ik 2 роки тому

      @@TimofeyKovalenko да вы правы) , согласен что не делают один интерфейс для нетворка и локального хранилища
      вот последний вопрос, извиняюсь). У нас есть условно 4 репозитория которые зависят от LocalDataStorage и у него была RealmLocalDataStorageImpl или какой то другая impl не важно, через некоторое время мы мигрировали на RoomLocalDataStorageImpl и это все внутренности LocalDataStorage о котором не должны знать клиенты - то есть те которые зависят от этого стораджа.
      подскажите какую модельку должен предоставить LocalDataStorage чтобы каждый клиент не ломался от нашей миграции?

  • @barnomasoz
    @barnomasoz 3 роки тому

    Спасибо за урок. Но у меня есть сомнений. В слое domain есть модел UsernameModel и при добавление еще одно поле в конструктор данного класса в Storage появится ошибка. Это правильно или нет?

    • @TimofeyKovalenko
      @TimofeyKovalenko  3 роки тому +1

      Да, все тут верно. Просто домена модель это один API, storage это совсем другой API. Если задача подразумевает и там и там менять, то да, нужно поменять в двух местах.
      А если вы будите одну и туже модель использовать для UI и для Storage, то во первых модель может обрасти специфическими данными, которые нужны только кому-то одному, а во вторых при изменении модели вы сразу измените совершенно разные компоненты. Архитектура это не про то, что-бы быстро накидать код, а про удобство на длинной дистанции.

  • @diyorbek5664
    @diyorbek5664 2 роки тому

    привет Тимофей спасибо за контент ! советую c UML )

    • @TimofeyKovalenko
      @TimofeyKovalenko  2 роки тому +1

      Нет смысла показывать такие схемы по UML), иначе придется еще и курс по UML делать предварительно)))).

    • @diyorbek5664
      @diyorbek5664 2 роки тому

      @@TimofeyKovalenko )) такие схемы и показываются на UML) !
      не нестоит ,просто в начале видео покажи стрелки зависемости,наследование, реализаций ,и это на 100 хватит в этом видео

  • @frantsuzfrantsuz9237
    @frantsuzfrantsuz9237 2 роки тому

    разве domain не стал зависить от data из-за класса User?

    • @TimofeyKovalenko
      @TimofeyKovalenko  2 роки тому

      Нет, каким образом? Data не подключена к domain, даже если очень захотеть, этого не получится).

  • @vladyslavpasechnyk1319
    @vladyslavpasechnyk1319 3 роки тому

    STORAGE внутри DATA?
    может правильнее отдельно?

    • @TimofeyKovalenko
      @TimofeyKovalenko  3 роки тому

      Да, назначение даты как раз и заниматься хранением данных, поэтому в большинстве случаев нет необходимости его выносить. Но если у вас модуль массивный либо используется разными системами, то конечно можно вынести.

  • @kostyatigre
    @kostyatigre Рік тому

    А кто мне доступно объяснит зачем везде пихают мапперы, и почему дата у всех реализует домен?
    Если мы говорим про разделение, то давайте четко и разделять, без всяких интерфейсов, просто классами все прекрасно разделяется и работает, а интерфейсы - это про другое. Сначала говорим, что Data слой должен быть максимально простой и без логики, а потом туда запихиваем всю логику приложения (реализация domain - она почему-то в data оказывается и никого это не смущает). Entity можно использовать везде (для отображения, обычно еще нужно что-то отформатировать, но так никто не мешает работать с 1 набором моделей и без всяких маперов), clean - не про них вообще.
    Давайте не писать код ради кода и усложнять этот самый код, затягивая сроки написания чистого и красивого кода.

    • @TimofeyKovalenko
      @TimofeyKovalenko  Рік тому

      Мапперы нужны, что-бы развязать логику и дают возможность каждому компоненту работать со своей моделью, и соответственно делать с ней все, что будет нужно не заботясь об остальных. А добавлять или не добавлять маперы, это уже дело конкретного проекта. Исходя из моего опыта, на длинной дистанции это всегда оправдано.
      По поводу "почему дата у всех реализует домен" - просто это наиболее частый случай. Реализацию можно писать и в других модулях, да и доменов и дат может быть много в приложении.
      Насчет логики домена в дате, не понял вас, какая логика из домена у нас оказалась в дате? В нашем случае логики, как таковой, нет вообще, поэтому и юз кейсы простые.
      Нужно понимать, что это простой проект, просто для примера ;), запихать сюда кучу логики и взорвать мозг студентам не цель данного видео))))).

  • @rtgtdscfgrthjkgf8388
    @rtgtdscfgrthjkgf8388 9 місяців тому

    Пипец путаницу устрол, жесть