Практическое руководство по чистой архитектуре в Go с генератором кода Goro
LectureEvrone Development•23,815 views•Jun 30, 2023
Тигран Ханагян из Delivery Hero делится опытом построения чистой архитектуры на Go и демонстрирует автоматизацию бойлерплейта с помощью библиотеки Goro.
Blurb
В этом видео инженер Тигран Ханагян из Delivery Hero рассказывает о построении чистой архитектуры в Go-проектах, выделяя ключевые слои: entity, usecase, service, adapter и handler. Он объясняет, как разделить бизнес-логику и инфраструктуру, избегать циклических импортов и утечек абстракций, а также демонстрирует принцип инверсии зависимостей. Вторая часть видео посвящена практической демонстрации использования библиотеки Goro — инструмента для генерации бойлерплейт-кода, который ускоряет разработку и поддерживает структуру чистой архитектуры. Тигран показывает, как быстро создавать проекты, описывать зависимости и реализовывать бизнес-логику на примере сервиса подписок.
Want the big picture?
Highlighted Clips
Введение и знакомство с докладчиком
Тигран Ханагян рассказывает о своем опыте и текущей работе в Delivery Hero.
Разделение кода на инфраструктуру и бизнес-логику
Обсуждение важности разделения инфраструктурного кода и бизнес-логики в Go-проектах.
Проблемы с зависимостями и циклическими импортами
Анализ типичных ошибок в организации кода, приводящих к сильной связности и циклическим импортам.
Обзор чистой архитектуры и ее слоев
Объяснение слоев entity, usecase, service, adapter и handler с примерами и схемами.
Введение и знакомство с докладчиком
Тигран Ханагян начинает с краткого представления себя и своего опыта: он инженер в группе компаний Delivery Hero, работает с Go и имеет более десяти лет опыта в программировании на разных языках, включая PHP и Python. Он упоминает, что занимается высоконагруженными сервисами и делится знаниями на конференциях и в блогах.
"Меня зовут Тигран и на данный момент я работаю в качестве инженера в группе компаний Delivery Hero... За свой более десятилетний опыт я успел поработать с такими языками как PHP, Python... последнее время работаю в основном с Go."
Ключевые моменты:
- Опыт работы с высоконагруженными сервисами.
- Акцент на Go как основном языке.
- Цель доклада — рассказать о чистой архитектуре на практике.
О чем будет доклад: проблемы и разделение кода
Тигран обозначает, что расскажет о частых ошибках при старте проектов и связанных с этим проблемах, а также предложит решение в виде чистой архитектуры. Он предлагает мысленно разделить код на два типа: инфраструктурный (логгеры, подключения к БД, очереди) и бизнес-логику (продуктовый код).
"Я предлагаю мысленно разделить наш код на два типа: это некий инфраструктурный код... и бизнес логика — это непосредственно наш продуктовый код."
Ключевые моменты:
- Фокус на бизнес-логике, так как времени мало.
- Следование стандартному Project layout для Go.
- Частые ошибки: смешение ответственности, копипаст, циклические импорты.
Проблемы с традиционной организацией кода
Тигран показывает, как часто бизнес-логика в Go проектах оказывается в одном пакете service, где смешиваются функции и структуры, что приводит к копипасту и сильной связности. Он демонстрирует примеры, где сервисы напрямую знают о конкретных реализациях репозиториев и подключениях к базе, что ведет к циклическим импортам.
"Наш сервис — это слой бизнес логики, он знает конкретную реализацию соединения к базе данных... это обязательно приведет к циклическим импортам."
Ключевые проблемы:
- Сильная связность между слоями.
- Утечка абстракций (например, роутер занимается бизнес-логикой).
- Копипаст и сложности с тестированием.
- Циклические импорты и трудности расширения.
Решение: чистая архитектура и ее слои
Тигран предлагает использовать чистую архитектуру (известную как архитектура дядюшки Боба), чтобы избавиться от перечисленных проблем. Он упрощает классическую схему, выделяя три ключевых слоя: entity (бизнес-логика и данные), usecase (бизнес-правила и оркестрация логики), и adapter (взаимодействие с внешним миром).
"Чистая архитектура — это когда слои независимы друг от друга, общаются через интерфейсы... Это избавляет нас от циклических импортов и сильной связности."
Ключевые моменты:
- Слои общаются через интерфейсы.
- Entity — данные и простая бизнес-логика, не зависящая от внешних сервисов.
- Usecase — оркестратор бизнес-логики, реализует фичи приложения.
- Adapter — реализация доступа к базе, API, очередям.
- Важен принцип инверсии зависимостей: зависимости идут от нижних слоев к верхним через интерфейсы.
Детали слоя Entity и бизнес-логики
Entity — это структуры с данными и ограниченной бизнес-логикой, которая не требует внешних вызовов. Тигран предпочитает делать entity глобальными, чтобы они могли свободно передаваться между слоями, избегая утечек абстракций.
"Я обычно помещаю в entity бизнес-логику, которую могу осуществить с помощью данных, доступных в этом entity... Entity могут быть глобальными, чтобы переносить данные через все слои."
Ключевые моменты:
- Entity — это структуры с данными и простой бизнес-логикой.
- Использование тегов для базы данных и сериализации.
- Глобальные entity упрощают передачу данных между слоями.
Слой Usecase: бизнес-правила и фичи
Usecase — это слой, который реализует бизнес-правила приложения, то есть фичи, которые клиент видит и использует. Он выступает как оркестратор, вызывая сервисы и управляя последовательностью действий.
"Usecase — это бизнес правило приложения, логика приложения, наши фичи... Usecase — это оркестратор нашей бизнес-логики."
Ключевые моменты:
- Usecase реализует фичи приложения.
- Usecase вызывает только слой сервисов, не обращается напрямую к репозиториям.
- Интерфейсы сервисов объявляются приватными внутри usecase, что ограничивает область видимости.
Слой сервисов и принцип инверсии зависимостей
Сервисы содержат более сложную бизнес-логику, включая взаимодействие с базами данных и внешними API. Важный момент — сервисы получают зависимости через интерфейсы, а не конкретные реализации, что реализует принцип инверсии зависимостей.
"Все наши сервисы объявляем так, что нам нужны интерфейсы, а не конкретные реализации... Это избавляет нас от циклических импортов и сильной связности."
Ключевые моменты:
- Сервисы вызывают репозитории и другие сервисы.
- Зависимости передаются через интерфейсы.
- Интерфейсы приватные, принадлежат конкретному сервису.
Адаптеры и хендлеры: связь с внешним миром
Адаптеры — это слой, который реализует конкретные драйверы и протоколы для доступа к базе данных, очередям, API и т.д. Тигран рекомендует структурировать адаптеры по протоколам (например, HTTP, MySQL, Mongo).
Хендлеры — слой, который отвечает за прием запросов, валидацию данных и вызов соответствующих usecase. Они определяют, как фичи доступны клиенту.
"Адаптеры — это наша связь с внешним миром... Хендлеры отвечают за то, как фичи можно вызывать, определяют протокол, валидацию, ответы."
Ключевые моменты:
- Адаптеры реализуют конкретные подключения и драйверы.
- Хендлеры обрабатывают запросы и вызывают usecase.
- Каждый слой изолирован и может быть вынесен в отдельный проект.
Проблема бойлерплейта и решение с библиотекой Goro
Тигран признает, что чистая архитектура приводит к большому количеству повторяющегося кода (бойлерплейта). Чтобы облегчить разработку, он создал библиотеку Goro — кодогенератор, который автоматически создает структуру проекта и шаблоны кода для всех слоев.
"Все это приведет к не малому количеству бойлерплейт кода... Я решил написать инструмент — библиотеку Goro, которая генерирует этот код."
Ключевые моменты:
- Goro генерирует код для инфраструктуры и бизнес-логики.
- Позволяет быстро создавать проекты и добавлять новые сервисы.
- Активно развивается, уже покрывает базовый функционал.
Демонстрация работы с Goro: создание проекта и сервисов
Тигран показывает, как скачать и установить Goro, затем создать проект с помощью конфигурационного файла YAML. В конфиге описываются usecase, сервисы и адаптеры с их зависимостями. После генерации появляется структура с папкой internal и слоями entity, usecase, service, adapter.
"Мы скачиваем конфиг, запускаем генератор, и у нас появляется папка internal с пакетами entity, usecase, service, adapter."
Ключевые моменты:
- Конфиг описывает методы usecase и зависимости.
- Генератор создает интерфейсы и шаблоны для реализации.
- Зависимости передаются по интерфейсам, что соответствует принципу инверсии.
Пример: сервис подписок и методы
Тигран развивает пример с сервисом подписок, добавляя методы для получения цен и оплаты подписки. Он показывает, как в конфиге описать новый сервис, репозиторий и зависимости, затем сгенерировать проект и увидеть готовую структуру.
"Давайте сделаем приложение подписок... Опишем методы Pay и GetSubscriptionPrice, укажем зависимости и сгенерируем проект."
Ключевые моменты:
- Быстрое добавление новых сервисов и методов.
- Репозитории указываются с конкретными драйверами (например, MySQL).
- Генератор проверяет конфиг и сообщает об ошибках.
Запуск и проверка проекта
В конце Тигран запускает сгенерированный HTTP сервер и демонстрирует вызов метода ping, который сообщает, что нужно реализовать бизнес-логику в usecase. Это показывает, что структура готова к наполнению реальным кодом.
"Запускаем HTTP сервер, вызываем метод ping, он говорит, что нужно имплементировать метод в usecase."
Ключевые моменты:
- Проект запускается сразу после генерации.
- Можно постепенно добавлять бизнес-логику.
- Goro облегчает старт и поддержание чистой архитектуры.
Заключение и благодарности
Тигран благодарит зрителей за внимание и приглашает задавать вопросы.
"Спасибо что выслушали до конца... Если есть вопросы, буду рад ответить."
Итог
В этом докладе Тигран Ханагян подробно разбирает проблемы традиционной организации Go проектов и показывает, как чистая архитектура помогает их решить. Он объясняет ключевые слои — entity, usecase, service, adapter, handler — и принцип инверсии зависимостей, который делает код независимым и тестируемым. Чтобы упростить работу с большим количеством шаблонного кода, он разработал библиотеку Goro, которая генерирует структуру и интерфейсы, позволяя быстро создавать и расширять проекты с чистой архитектурой. Доклад наполнен практическими примерами и демонстрацией работы с инструментом, что делает его полезным для разработчиков, стремящихся писать чистый и поддерживаемый код на Go.
Key Questions
Чистая архитектура — это подход к организации кода, который разделяет бизнес-логику и инфраструктуру, снижает связность и упрощает тестирование и расширение проекта. В Go это помогает избежать циклических импортов и утечек абстракций.
Have more questions?
Analyzing video...
This may take a few moments.