Попытка реализовать Чистую Архитектуру на Golang. Часть 2
Practical.DEV
После описания моего опыта в статье «Попытка реализовать Чистую Архитектуру на Golang» (https://hackernoon.com/golang-clean-archithecture-efd6d7c43047) я узнал много нового от людей и в частности от пользователей Go. Я получил множество писем, комментариев и даже Github issue в моем проекте. Все это помогло мне понять, что я пропустил и где ошибся.
Цикличный импорт
Вспоминая мой старый проект из первой части статьи, я могу сказать, что он и его структура ограничены для Golang. Одна из самых больших проблем, с которой я столкнулся, – это наличие нескольких зависимостей в моделях. Из-за этого появляется циклический импорт, как упоминал пользователь daf0rth здесь: https://github.com/bxcodec/go-clean-arch/issues/7.
Система пакетов
Другой вопрос в том, что Golang отличается от других языков программирования. Он использует систему пакетов. Другими словами, будет лучше, если вся структура проекта или функция хранится в одном пакете, так безопаснее. Я вижу это решение во многих проектных библиотеках или открытых исходных кодах на Github. Возьмем в качестве примера проект logrus (https://github.com/sirupsen/logrus). Все структуры и функции хранятся в одном пакете, а он находится в корне пакета проектов. Таким образом, мы можем легко импортировать logrus в виде пакета для любых других наших проектов.
Решение?
Поэтому, осознав эти проблемы, я попробовал множество подходов, не упуская из виду концепцию “Чистой Архитектуры”, которая является независимой, тестируемой, поддерживаемой и чистой. При всем при этом не теряя идентичности Golang. И, в конце концов, я сделал обновление своих старых проектов: https://github.com/bxcodec/go-clean-arch
– Предотвращение циклических импортов
Чтобы избежать циклического импорта, я разделяю модели в одном пакете. Так, если у нас имеются связи между моделями, мы можем разрешить их, зная, что они уже хранятся в одном пакете.
– Восстановление идентичности Golang с помощью системы пакетов
И, чтобы не терять идентичность Golang, как пакетного языка программирования, я перемещаю интерфейс (слой варианта использования и слой репозитория) в их пакет корневого домена.

article ├── delivery │ └── http │ ├── article_handler.go │ └── article_test.go ├── mocks │ ├── ArticleRepository.go │ └── ArticleUsecase.go ├── repository //Encapsulated Implementation of Repository Interface │ ├── mysql_article.go │ └── mysqlarticle_test.go ├── repository.go // Repository Interface ├── usecase //Encapsulated Implementation of Usecase Interface │ ├── articleucase_test.go │ └── artilce_ucase.go └── usecase.go // Usecase Interface.
Таким образом, исходя из этой структуры проектов, другие домены, такие как домен Author, знают только об интерфейсе и функции, а не об их реализации.
Ну, на самом деле, я просто напросто перемещаю интерфейс репозитория и варианта использования в их корневой домен.
article/usecase/usecase.go >>>> article/usecase.go article/repository/repository.go >>>> article/repository.go
И я оставил их реализации в старых папках. И следуя этому замыслу, я все еще могу редактировать их без изменения соглашения между ними. Я так же могу изменить базу данных репозитория с MySQL на MongoDB, или логику варианта использования, не меняя выходящие и входящие данные функций.
Тестирование?
Концепция до сих пор не поменялась. Как и тестирование. Все то же самое. Эти изменения касаются только предотвращения циклического импорта, а также восстановления идентичности Golang в качестве пакетного языка.
Последнее, но не менее значимое
Весь этот замысел основан на моем собственном и на полученном от других людей опыте. Некоторые функции я взял, возможно, из другого исходного кода, а в некоторых из них я сделал несколько улучшений. Я буду очень признателен за любой вопрос, комментарии или поправку, если я делаю что-то неправильно или пропускаю что-то в своей статье.
В Golang, нет стандартной архитектуры. Мы можем свободно перепробовать множество подходов, как мы можем сделать и узнать. Для некоторых людей предлагаемая мной архитектура полезна, но для других действительно не подходит и не решает реальную проблему. Но я хочу сказать, что Golang свободен и никогда будет иметь стандартов. Вы можете разработать свой собственный стандарт, или попробовать то, что делают другие. Ведь там так много предложенной разными людьми Чистой Архитектуры, которая, возможно, поможет вам больше.