Go Clean Template | Чистая Архитектура и как её готовить, Михаил Непряхин

Поділитися
Вставка
  • Опубліковано 22 лис 2024

КОМЕНТАРІ • 81

  • @fess932
    @fess932 3 роки тому +54

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

  • @RusFarFaz
    @RusFarFaz Рік тому +8

    Большое спасибо за объяснение! Особенно с этим кругом было не понятно, а после вашего рисунок все стало на свои места.

  • @MrQsam
    @MrQsam Рік тому +5

    Спасибо. Видео несколько раз буду пересматривать .

  • @Mort4l1s
    @Mort4l1s Рік тому +13

    Спасибо за доклад, очень круто! Есть пару моментов с которыми я не согласен:
    12:00 - плохая идея использовать одну структуру в entity на все слои, объясню почему: мне нужно из controller передать в usecase два поля для пагинации (offset, limit). Почему слой entity (слой enterprise бизнес логики) должен знать про какую-то пагинацию?)
    14:20 - плохая практика использовать backticks с json в слое entity, т.к этот слой ничего не должен знать о представлении. То есть, если придет заказчик и скажет, что мне вместо json подавай xml, то придется менять слой entity (получается entity и controller имеют какую-то косвенную связь). К тому же у вас могут быть принципиально разные структуры, что в слое entity, что в controller.

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

      Разумеется. Но это уже детали. Я высокоуровнево и доступно старался объяснить.
      В реальном мире нужен пакет dto в котором это всё будет находится. Я dto использую для связи controller usecase. Большие и сложные dto бывает доходят и до адаптеров.
      Ну и внутри entity постепенно появляются другие пакеты по мере разрастания логики.
      Главное понять как управлять сложностью и где проводить границы между разными частями сервиса.

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

      @@neprja а каким образом стоит декаплить пакеты, в случае если мы в юзкейсе реализовали проверку(errors.As, errors.Is) и хендлинг кастомных ошибок(созданных errors.New) , возвращаемых пакетом, отвечающим, например, за интеграцию с другим микросервисом. Мы будем его импортировать, чтобы иметь доступ к переменным и типам тех ошибок. Или есть альтеративный подход, где мы оперируем абстракцией?

  • @spotlight2206
    @spotlight2206 Рік тому +3

    О! Не смотря это видео и только начав изучать чистую архитектуру я переделал одно микросервисное приложение под неё. Не знал как лучше архитектурно реализовывать многие вещи (нужна ли отдельная структура для юзкейсов, в ней ли должен храниться репозиторий, где обращаться к другому микросервису) и написал как смог придумать. Сейчас смотрю это видео и понимаю, что почти все делал правильно! Но теперь уже есть точное понимание, зачем и почему так. Спасибо, очень конкретное, дельное и познавательное видео.

  • @shushard
    @shushard Рік тому +4

    Наконец-то кто-то нормально объяснил эту тему

  • @andreychirkov1904
    @andreychirkov1904 2 роки тому +6

    Классный доклад! Очень доходчиво, структурировано и понятно. Спасибо

  • @dmitriyobidin6049
    @dmitriyobidin6049 Рік тому +4

    В рамках микросервисов нет деления на понятние application logic и core business logic. Потому что в самом смысле микросервисов заложено, что микросервисы должны быть слабосвязаны между собой, а соответственно и сквозных данных/логики между ними должно быть по минимуму.
    Это разделение было для стандартных монолитов, и за счет этого разделения возможно было бы использовать один единый удобный слой core business logic для разных целевых модулей/блоков приложения. Например, одна модель счет фактуры для разных сценариев и интерфейсов использования: наборщик на складе, водитель-экспедитор, приемщик и т.д. Они работают каждый через свой слой абстракции(application logic) с одной общей моделью(core business logic).
    В архитектуре микросервисов это спокойно распиливается на 4(условно) микросервиса.

  • @nnnabbot
    @nnnabbot 6 місяців тому +1

    Спасибо за видео. Очень многое понятно. Но хочется для таких как я 😂(начинающих), объяснить все тоже самое , но на примере конкретного приложения , например файлообменник. И прям на нем показать данный подход

  • @dmitriyobidin6049
    @dmitriyobidin6049 Рік тому +5

    19:17 Разве в импортах не должно быть хотя бы импорта моделей/entity?

  • @TheArtofDevelopment
    @TheArtofDevelopment 2 роки тому +18

    Классное объяснение! Заберу к себе пару тезисов - у меня на канале реализация чистой архитектуры в 3 частях.

  • @kitusis244
    @kitusis244 2 роки тому +2

    Огонь! Спасибо большое!

  • @Виталий-я7г8в
    @Виталий-я7г8в 8 місяців тому +2

    Подскажите, а как быть, если нужно в одном юзкейсе вызвать методы другого юзкейса ( в apple дернуть метод, связанный с banana)?

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

    странно что WebAPI оказался в слое Infrastructure, хотя это обычно находится в слое Presentation

  • @dmitriyobidin6049
    @dmitriyobidin6049 Рік тому +4

    Тоже никогда не понимал, зачем нужно пилить столько dtoшек в рамках микросервиса, особенно при том что всё это делается в папке internal, т.е. переиспользование всего этого добра в других проекта не предполагается...
    По мне так dto в такой архитектуре должен быть аналогом адаптера типов. Т.е. если вместо одного из модулей или вместо одной из частей системы мы подключаем внешний пакет, который не умеет работать с нашими моделями. В таком случае мы как раз используем dto, чтобы произвести маппинг на нужный формат данных. Но если мы все пилим в локальных, закрытых, не нацеленных на переиспользование в других проектах модулях - нафига этот огород?
    Прокидывать везде единые модели данных - это нормально. Но при этом если потом понядобится/захочется ввести локальные dto для каких-то сервисов/модулей - это можно легко сделать точечно.
    Конечно же все вшесказанное работает, если dto и entity совпадают на 90+%. Когда мы там передаем кучу служебных данных, не связанных с моделями - ну тут уж никуда.

  • @ilgizilgiz
    @ilgizilgiz Рік тому +3

    На 2 скорости становится нормально)

  • @AlexeiCheban
    @AlexeiCheban 2 роки тому +6

    Такс стоп, вы в докладе рассказали что должен быть модуль infrastucture где находяться repo и webapi. А в репе они у вас в usecase находяться.

    • @neprja
      @neprja 2 роки тому +2

      Репа немного устарела. Руки никак не доходят обновить. То что в докладе - актуально.

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

      @@neprja Благодарю за ответ

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

      тот же вопрос был))) спасибо!!!

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

      @@neprja а можете обновить реп пожалуйста?

  • @dmitryvakulenko7980
    @dmitryvakulenko7980 Рік тому +6

    Немного не согласен. Во-первых, нет смысла отделять интерфейсом слой контроллеров от слоя UseCase, т.к. UseCase никогда не будет вызывать контроллер, а контроллер вполне имеет право быть в курсе про конкретный UseCase согласно той же диаграмме зависимостей. Ситуации, конечно, разные могут быть, но в принципе это не нужно. И во-вторых, entity могут использоваться по всему проекту по той же причине. DTO никто не отменял, но, это, скорее элемент абстракции, а не ограничения видимости.

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

      Да, согласен)

  • @tumenit
    @tumenit 2 роки тому +2

    Спасибо!

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

    красава

  • @yarbersheer8559
    @yarbersheer8559 2 роки тому +6

    А могли бы разъяснить в чём отличия кроме названий слоёв между Clean и Hexagonal, Onion архитектурами?

    • @neprja
      @neprja 2 роки тому +5

      Отличий особо нет. Все они об одном и том же.

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

      @@neprja простите за глупые вопросы, я ещё даже не джун. У вас хорошая слоистость, поэтому пока не просто сразу въехать. Я верно понял, что ваш слой controller это слой port в гексагоналке?

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

      @@yarbersheer8559 Да. Контроллер - это точка входа.

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

      @@neprja спасибо) а могу ещё отнять немного вашего времени вопросом.
      Часто вижу, что параметры среды не выносятся в отдельный сервис синглтоном, при этом очевидно, что эта функция может иметь несколько итераций построения объекта среды, например default -> flags -> env -> external file (yaml, toml etc).
      Почему не принято выносить эту процедуру в отдельный entity? Или просто обычно этому нет нужды уделять отдельного внимания?

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

      @@yarbersheer8559 В entity ему точно не место, entity - это сущность бизнес-логики. А параметры среды - это конфигурация для построения объектов архитектуры приложения. Лучшая практика для переменных - делать синглтоном.

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

    Хмм, а как в вашем случае (на 25:50 показано справа) предполагается писать одни и те же методы (`New()`, например) для разных юзкейсов (apple/banana) в одном пакете usecase? Всё-таки надо их делить (создавать подпапки apple/banana внутри usecase) или есть возможность разграничить scope файлов apple/banana, чтобы компилятор не ругался на одинаковые методы?
    Просто если делить юзкейсы по папкам, тогда инфраструктуру, кажется, нужно выносить в отдельный пакет вне usecase, т.к. её могут использовать несколько юзкейсов (в репозитории из примера инфра лежит внутри usecase)

    • @neprja
      @neprja 2 роки тому +2

      Спасибо за замечания) На счет репозитория из примера, он немного устарел, туда лучше не смотрите. Идеи со слайдов актуальны. У меня пакет infrastructure находится на одном уровне с controller, entity и usecase. По поводу New(), в юзкейсах у меня 1 New: (func New() *UseCases) внутри которого все абстракции, а методы от него это уже самостоятельные юзкейсы. По поводу New в entity: если у сущности появляется конструктор, значит сущность достойна отдельного пакета. Я его обычно помещаю внутрь entity.

  • @MichailMishutkin
    @MichailMishutkin 2 роки тому +6

    я только разбираюсь в подходах к чистой архитектуре на Go и выражаю огромную благодарность за такое ёмкое и простое объяснение темы (несколько месяцев просто не мог вьехать при самостоятельной реализации). Но есть ряд вопросов: В примере вы указали последовательные инъекции из репозитория в юзкейс, а потом из юзкейса в контроллер, но на диаграммах указано, что юзкейс как отдаёт, так и принимает через интерфейс данные и в репу, и в контроллер. Я правильно понимаю, что из-за формата обратные инъекции не указаны? или нет? если нет, то как конкретно общается контроллер с репой через юзкейс сохраняя подход чистой архитектуры?

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

      21:15 в usecase инджектится repository а потом в controller инджектится usecase, так происходит инверсия зависимостей что нижний слой не зависит от верхних , нижний слой инджектится в верхний. После инджекта слои связываются и спокойно общаются друг с другом по цепочке. request-> controller-> usecase-> repo-> usecase-> controller-> response. То есть не нужно путать связанность кодовой базы и связи слоев в работающей программе.

    • @MichailMishutkin
      @MichailMishutkin Рік тому +3

      @@hakooplayplay3212 спасибо! очень хороший ответ. У меня всё встало на свои места год назад(когда вопрос задавал) опытным путём. Переменная(ые) результата вызова метода и являются обратной связью по цепочке. Вроде элементарно, но очевидно только на опыте.

  • @yarbersheer8559
    @yarbersheer8559 2 роки тому +2

    Спасибо.

  • @vadimalekseev3621
    @vadimalekseev3621 2 роки тому +2

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

    • @Aaaa-jn4bm
      @Aaaa-jn4bm 2 роки тому +1

      Ну так в функции с более чем тремя параметрами нужно передавать структуры.
      Для каждой функции с большим количеством параметров создаётся input структура, разве нет ?

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

      Совсем по верхам - ваша проблема в протекании модели в слой юзкейса

    • @ДмитрийКозлов-к8г
      @ДмитрийКозлов-к8г Рік тому

      Может быть нужно сделать дополнительные слои? Тогда зависимости будут везде от центра/центров к внешним слоям домена. Между слоями ставьте интерфейсы, чтобы внутренний слой знал самый минимум о более внешнем, точнее, заказывал только нужный ему функционал, а внешние слои этот функционал обеспечивали. Тогда изменения внешних слоев не затронет внутренний.
      Если приходится передавать много параметров значит вы не обеспечили принцип low cohesion

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

    интерфейсы нужно размещать там, где используются - об этом не нужно думать :)

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

      По дефолту, да.

    • @ИгорьСеверюхин
      @ИгорьСеверюхин 2 роки тому +2

      @@neprja Отличное видео, спасибо. Но есть вопрос на тему интерфейсов. Интересно ваше мнение. Если мы описываем интерфейсы там, где используем, то что делать, если два или более useCase используют один и тот же репозиторий и одни и те же методы из него?
      Если с разными методами более менее понятно - можно разделить интерфейс. То с одинаковыми вопрос.
      Или это уже проблема архитектуры и следует пересмотреть организацию бизнес логики?

    • @neprja
      @neprja 2 роки тому +2

      @@ИгорьСеверюхин Хороший вопрос.
      Решение простое - вынести все интерфейсы в отдельный пакет.
      Раньше я так и делал. Но пришел к тому что структура юзкейсов у меня всегда одна и в неё заинжекчены все адаптеры. А методы этой структуры - это уже конкретные юзкейсы.
      И интерфейсы я кладу как раз рядом со структурой Usecases в пакет usecase. Получается что интерфейсы находятся в месте использования. Все, кроме 1 интерфейса самого юзкейса (для вызовах в контроллере). Можно было бы держать интерфейс юзкейса в самом контроллере, но контроллеров может быть несколько. Поэтому я нарушаю это правило (держать интерфейс в месте использования) только в этом одном случае.

    • @Aaaa-jn4bm
      @Aaaa-jn4bm 2 роки тому +2

      @@ИгорьСеверюхин , а разве это такая большая проблема ? Меня это вполне устраивает

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

    Балдеж

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

    Привет, Михаил! Очень классный доклад и go-clean-template на гитхабе. Интересно, что нет юнит тестов для repo и webapi, получается, вы их тестируете заодно со слоем usecase. Или в реальных проектах вы пишете тесты для каждого слоя? Спасибо )

    • @neprja
      @neprja 2 роки тому +8

      В первую очередь хочется тестировать бизнес логику, которая находится в usecase. При тестах usecase мокаются зависимости (repo, webapi, microservice_name). И то тесты пишутся не на каждый usecase. Надо смотреть на ситуацию, есть ли смысл вообще тестировать. Если есть требование на покрытие, тут конечно без вариантов) Но в целом юнитесты пишутся исходя из здравого смысла. Всё остальное покрывают интеграционные тесты.

  • @АлександрАнтонов-я5б

    Ну хоть кто-то снизошел до уровня имплементации и четких примеров вместо бесконечных абстракций

  • @ТимофейЁлкин-о9е
    @ТимофейЁлкин-о9е 2 роки тому +3

    Хорошо, что человек решил помочь разобраться в теме. Но изложение путанное и местами сумбурно.

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

    Совсем не понял про пустые import. Если usecase, к примеру, возвращает структуру entity то без импорта никак не обойтись. Разве нет?

  • @VitalyVakhromeev
    @VitalyVakhromeev 2 роки тому +2

    Михаил, не подскажите, как быть при добавлении новых сущностей, добавлять для каждой свой "класс" обработчика, юзкейса и репозитория или же эти классы будут общими для всех сущностей?

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

      Отталкиватся нужно от юзкейса, новая задача = новый юзкейс. Все остальное вокруг него. Один юзкейс может оперировать несколькими сущностями и несколькими репозиториями в зависимости от задачи. Один юзкейс могут вызвать разные контроллеры (обработчики), их может быть несколько, а может быть один.

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

      @@neprja Спасибо.

    • @Aaaa-jn4bm
      @Aaaa-jn4bm 2 роки тому +3

      @@neprja , можете пожалуйста скинуть какой-нибудь годный репозиторий с чистой архитектурой, где применяется практика с описанием интерфейсов в месте использования ? Очень понравился такой подход, но нигде не могу таких примеров найти.. Глянул в ваш - там вы импорт интерфейсов делаете. Не то чтобы я сам не в состоянии написать код с таким подходом, просто хотелось бы на что-нибудь такое сеньёровское глянуть, где такой подход практикуется :) Ещё, очень желательно, чтобы это было api

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

    Не совсем понял про "у меня use case ни в коем случае не вызывают друг друга". В моем мире это попросту невозможно. Сплошь и рядом новая бизнес-функциональность - это комбинация старой. Типа было яблоко, были креветки, и тут вдруг раз - и появился салат с яблоком и креветками. Как вы в этом случае будете поступать, все свои модули двигать между слоями и папками?
    Или обратный пример - всё начинается сразу с салата из 50 ингредиентов. Это будет один огромный use case внутри одной папки? А когда потом его части в другой папке понадобятся, как эти части повторно переиспользовать, копированием?
    Я не критикую, скорее всего это я что-то не так понял. Скорее пытаюсь понять, в чём тут идея. Потому что у меня как раз use case друг друга сплошь и рядом используют, но только через DI, без сильных связей

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

      Давайте от обратного пойдем. Я не скажу как надо, но скажу как не надо. Если у вас один юзкейс вызывает другой юзкейс, то изменение в первом юзкейсе, повлекут изменения во втором. А это вам точно не нужно. Если у вас в одном юзкейсе используется другие юзкейсы, то вы обречены на страдания при минимальных изменениях. Принцип DRY можно забыть. Мартин говорит, что можете расслабится по поводу того что вам кажется что вы просто копируете код. И 2 юзкейса на начальном этапе могут выглядеть абсолютно одинаково. Если это разные юзкейсы их дороги в будущем разойдутся с вероятностью 100%.

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

      Креветки и яблоки - это entity или абстракции (infrastructure), а в юзкейсах вы их отдаете либо не изменными, либо готовите из них разные салаты.

    • @RusRes
      @RusRes 2 роки тому +5

      @@neprja Я наверное понял. Многое из того, что я для себя считаю юзкейсами, правильнее было бы считать частью доменной модели. Собственно, наверное по этой линии и проходит граница - домен переиспользуется, юзкейс уникален. Спасибо!

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

      @@RusRes Верно

  • @DonPardon-r5u
    @DonPardon-r5u Рік тому +11

    Зачем мигать только не понятно. Хочешь слушать человека и одновременно смотреть картинку. Зачем постоянно переключать картинка-человек-картинка, человек объясняет сложный технический вопрос. Рябит в глазах и раздражает, переделать можете по нормальному видео? Чтобы человек без морганий справа, картинка слева, как это делается у нормальных людей. Вроде кодеры, уж это то могли "встроить" в видео, это элементарное юзабилити, чтобы зритель досмотрел доконца, вы же хотите чтобы вас выслушали, верно?

  • @ВладПопов-э5я
    @ВладПопов-э5я 2 роки тому +3

    Доклад классный, а вот того кто делал монтаж - пороть розгами. Показывают код, он переключает на докладчика. Homo Idiotus.

  • @silentium_noxe
    @silentium_noxe Рік тому +3

    оч много воды. По факту можно все уложить в 5 минут.
    1. Есть слои абстракций, они не пересекаются между собой напрямую
    2. Используй интерфейс для связи лееров
    3. Вот такая структура директорий
    4. Вот такой нейминг

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

      Таких пятиминутных выдержек по всей сети море. И ничерта в них не разберёшься без продажи души и рюмок градусов. Я много всего перерыл, но вот это видео - оказалось той самой вишенкой, тем самым последним паззлом, что наконец позволило понять всю картину.

  • @ДжекиФ-д8т
    @ДжекиФ-д8т 9 місяців тому +1

    Оратора как-будто пчела в шею укусила. Что это? Красные пятна и волдырик как-будто. Всю дорогу уже не мог нормально слушать о чистой архитектуре, отвлекаясь на эти непонятки. К середине видео краснота прошла, и норм стало слушать.

    • @neprja
      @neprja 8 місяців тому

      От волнения)

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

      да уж )) неспортивный пацан какойто

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

      >>Всю дорогу уже не мог нормально слушать о чистой архитектуре, отвлекаясь на эти непонятки. К середине видео краснота прошла, и норм стало слушать.
      Это же сарказм, да? Или мне веру в человечество снова терять?