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

แชร์
ฝัง
  • เผยแพร่เมื่อ 22 ต.ค. 2024

ความคิดเห็น • 81

  • @RusFarFaz
    @RusFarFaz ปีที่แล้ว +8

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

  • @MrQsam
    @MrQsam ปีที่แล้ว +5

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

  • @fess932
    @fess932 2 ปีที่แล้ว +54

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

  • @shushard
    @shushard ปีที่แล้ว +4

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

  • @spotlight2206
    @spotlight2206 ปีที่แล้ว +3

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

  • @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) , возвращаемых пакетом, отвечающим, например, за интеграцию с другим микросервисом. Мы будем его импортировать, чтобы иметь доступ к переменным и типам тех ошибок. Или есть альтеративный подход, где мы оперируем абстракцией?

  • @andreychirkov1904
    @andreychirkov1904 ปีที่แล้ว +6

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

  • @dmitriyobidin6049
    @dmitriyobidin6049 ปีที่แล้ว +4

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

  • @nnnabbot
    @nnnabbot 5 หลายเดือนก่อน +1

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

  • @TheArtofDevelopment
    @TheArtofDevelopment 2 ปีที่แล้ว +18

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

  • @dmitriyobidin6049
    @dmitriyobidin6049 ปีที่แล้ว +4

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

  • @dmitriyobidin6049
    @dmitriyobidin6049 ปีที่แล้ว +5

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

  • @dmitryvakulenko7980
    @dmitryvakulenko7980 ปีที่แล้ว +6

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

    • @neprja
      @neprja ปีที่แล้ว

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

  • @kitusis244
    @kitusis244 2 ปีที่แล้ว +2

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

  • @Виталий-я7г8в
    @Виталий-я7г8в 7 หลายเดือนก่อน +2

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

  • @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 спасибо! очень хороший ответ. У меня всё встало на свои места год назад(когда вопрос задавал) опытным путём. Переменная(ые) результата вызова метода и являются обратной связью по цепочке. Вроде элементарно, но очевидно только на опыте.

  • @ivanchukayev6547
    @ivanchukayev6547 หลายเดือนก่อน

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

  • @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 а можете обновить реп пожалуйста?

  • @АлександрАнтонов-я5б
    @АлександрАнтонов-я5б 2 ปีที่แล้ว +8

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

  • @svyatoslavazizov8231
    @svyatoslavazizov8231 ปีที่แล้ว +3

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

    • @neprja
      @neprja ปีที่แล้ว +2

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

  • @tumenit
    @tumenit 2 ปีที่แล้ว +2

    Спасибо!

  • @ilgizilgiz
    @ilgizilgiz ปีที่แล้ว +3

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

  • @yarbersheer8559
    @yarbersheer8559 2 ปีที่แล้ว +2

    Спасибо.

  • @devchuli5155
    @devchuli5155 2 ปีที่แล้ว +3

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

    • @neprja
      @neprja 2 ปีที่แล้ว +8

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

  • @kinvain
    @kinvain 2 ปีที่แล้ว +4

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

  • @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 - это сущность бизнес-логики. А параметры среды - это конфигурация для построения объектов архитектуры приложения. Лучшая практика для переменных - делать синглтоном.

  • @VitalyVakhromeev
    @VitalyVakhromeev 2 ปีที่แล้ว +2

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

    • @neprja
      @neprja 2 ปีที่แล้ว +3

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

    • @VitalyVakhromeev
      @VitalyVakhromeev 2 ปีที่แล้ว +1

      @@neprja Спасибо.

    • @Aaaa-jn4bm
      @Aaaa-jn4bm 2 ปีที่แล้ว +3

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

  • @vadimalekseev3621
    @vadimalekseev3621 2 ปีที่แล้ว +2

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

    • @Aaaa-jn4bm
      @Aaaa-jn4bm 2 ปีที่แล้ว +1

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

    • @aidarlatypov7747
      @aidarlatypov7747 2 ปีที่แล้ว +1

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

    • @ДмитрийКозлов-к8г
      @ДмитрийКозлов-к8г ปีที่แล้ว

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

  • @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 Верно

  • @MamontSFFP
    @MamontSFFP 2 ปีที่แล้ว +3

    Балдеж

  • @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

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

  • @DonPardon-r5u
    @DonPardon-r5u ปีที่แล้ว +11

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

  • @ТимофейЁлкин-о9е
    @ТимофейЁлкин-о9е 2 ปีที่แล้ว +3

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

  • @silentium_noxe
    @silentium_noxe ปีที่แล้ว +3

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

    • @makssof5220
      @makssof5220 4 หลายเดือนก่อน

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

  • @ВладПопов-э5я
    @ВладПопов-э5я 2 ปีที่แล้ว +3

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

  • @ДжекиФ-д8т
    @ДжекиФ-д8т 8 หลายเดือนก่อน +1

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

    • @neprja
      @neprja 7 หลายเดือนก่อน

      От волнения)

    • @errmaker
      @errmaker 6 หลายเดือนก่อน

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

    • @makssof5220
      @makssof5220 4 หลายเดือนก่อน

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