Как структурировать проект на Golang: гайд от backend-разработчика

Всем привет, меня зовут Авксентий, я backend-разработчик в inDriver. Думаю, каждый начинающий разработчик сталкивался с проблемой, как правильно выстроить архитектуру и структуру проекта. Ведь организация кода проекта — постоянно развивающаяся проблема, а следование стандартной структуре сохраняет чистоту кода и повышает производительность команды. 

Когда я начинал писать на Go, то потратил много времени на поиски стандартов структурирования проекта. В итоге так и не нашел официального и точного стандарта — либо информация была неполной, либо это было не то, что нужно. Я решил написать свой гайд на основе опыта. Он для начинающих разработчиков и посвящен тому, как структурировать проект на Golang.

96c2e9fb14cb47c1feb573f31007a6c3.png

Почему я решил написать эту статью

Правильно выстроенные архитектура и структура проекта в начале способствует безболезненной разработке, масштабированию и легкому внедрению новых разработчиков в проект. Конечно, плоскую структуру тоже можно использовать для маленьких проектов с одним main-файлом, но это непрактично для больших.

Я видел немало проектов, и из каждого взял что-то для себя. Рекомендую ознакомиться с этим проектом — многие ориентируется на него при создании структуры. В моем примере будет более компактная структура — мы детально разберем директорию /internal.

Конечно, метод не претендует на лучший или единственный способ ведения дел. Но, думаю, он хорошо подойдет для начала. Посмотрим на структуру корня проекта:

Корневая структура приложенияКорневая структура приложения

Директории

/cmd

Точка входа для нашего приложения. Имя директории для каждого приложения должно совпадать с именем исполняемого файла, который вы хотите собрать. Не стоит располагать в этой директории много кода. Самой распространенной практикой является использование маленькой main-функции, которая импортирует и вызывает весь необходимый код из директорий /internal и /pkg.

Структура директории /cmdСтруктура директории /cmd

/internal

Сердце нашего приложения — всю внутреннюю логику приложения храним здесь. /internal не импортируем в других приложениях и библиотеках. Код, который написан тут, предназначен исключительно для внутреннего использования в рамках кодовой базы. С версии Go 1.4 определен механизм, который не позволяет импортировать пакеты вне данного проекта, если они находятся внутри /internal. 

В /internal мы храним бизнес-логику проекта и работу с базами данными. В общем, всю логику, связанную с этим приложением. Выстроить структуру внутри /internal можно по-разному, в зависимости от архитектуры. Но я не буду сильно углубляться в нее, а поверхностно покажу, как это выглядит. Приведу пример трехуровневой архитектуры, когда приложение делится на 3 слоя:

  1. Транспортный.

  2. Бизнес.

  3. Базы данных.

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

Модель трехуровневой архитектурыМодель трехуровневой архитектуры

Транспортный слой:

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

Бизнес-слой:

Как следует из названия, содержит бизнес-логику, которая поддерживает основные функции приложения. Если в логике затрагиваются базы данных, мы идем на слой ниже.

Слой базы данных:

Отвечает за взаимодействие с постоянными хранилищами, такими как базы данных, и прочую обработку информации, которая не связана с бизнесом. Например, чтение и запись в базе данных.

Директории /internal:

  • /app
    Точка, где все наши зависимости и логика собираются и запускают приложение. Run-метод, который вызывается из /cmd.

  • /config
    Инициализация общих конфигураций приложения, которые мы прописывали в корне проекта.

  • /database (слой базы данных)
    Файлы содержат методы для взаимодействия с базами данных.

  • /models (слой базы данных)
    Структуры таблиц баз данных.

  • /services (бизнес-слой)
    Вся бизнес-логика приложения.

  • /transport (транспортный слой)
    Здесь храним http-настройки сервера, хендлеры, порты и так далее.

Структура директории /internalСтруктура директории /internal

/pkg

Если в /internal мы хранили код, который не могли импортировать в других приложениях, то в /pkg храним библиотеки, используемые в сторонних приложениях. Это нужно, чтобы потом импортировать их в другой проект, а не дублировать код из проекта в проект. В общем, кастомные или общие библиотеки мы храним здесь.

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

/configs

Статические конфигурации нашего приложения, связанные с процессом сборки приложения. Обычно это yaml-файлы.

/api

Документация по вашему API. Спецификации OpenAPI или Swagger, файлы JSON Schema, файлы определения протоколов.

/build

Файлы конфигурации для билда проекта, Docker-контейнера и так далее.

/deployments

Содержит файлы, связанные с развертыванием: плейбуки Ansible, манифесты Docker Compose, манифесты и настройки Kuberntes, диаграммы Helm.

/docs

Документирование кода — важная часть в начале проекта. Поэтому всю документацию кода и дизайна (в дополнение к автоматической документации Godoc) храним здесь.

README.md

Трудно ожидать, что кто-то захочет погрузиться в ваш код, если ему не предоставили общего описания проекта. Поэтому файл README тоже необходим.

Распространенные директории

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

/scripts

Скрипты для сборки, установки, анализа и прочих операций над проектом. Они позволяют оставить основной Makefile небольшим и простым.

/testdata

Дополнительные внешние приложения и данные для тестирования. Вы можете организовывать структуру директории /test так, как вам угодно. Для больших проектов имеет смысл создавать вложенную директорию с данными для тестов.

/tools

Инструменты поддержки проекта. Отмечу, что эти инструменты могут импортировать код из директорий /pkg и /internal.

/assets

Другие ресурсы, необходимые для работы: например, картинки и логотипы.

/web

Эта директория понадобится, если вы реализуете веб-приложение. Здесь находятся специальные компоненты для веб-приложений: статические веб-ресурсы, серверные шаблоны и одностраничные приложения.

/migrations

Здесь все миграции, связанные с базами данными: например, SQL-файлы.

Вывод

Конечно, не надо строго следовать моей структуре. Можно взять часть и отредактировать все под себя. Но когда я начинал, мне не хватало такого подробного гайда. Так что, надеюсь, статья вам помогла!

На всякий случай, оставлю ссылку на свой публичный sample-проект на GitHub. Если у вас есть вопросы, задавайте их в комментариях.

© Habrahabr.ru