RSS Telegram YouTube Apple Яндекс Spotify Amazon Почта

99. Go project layout v2

27.04.2025

Скачать

К списку выпусков

Ссылки выпуска:

Пару лет назад, в 13 эпизоде, мы уже затрагивали тему организации проекта. Какие главные принципы организации проекта?

Модули vs пакеты

Пакет (package) — это набор связанных файлов .go, находящихся в одной директории. Каждый файл начинается с объявления package <имя>. Пакеты позволяют структурировать код и повторно использовать его. Например, стандартная библиотека Go содержит пакеты fmt, math/rand и т.д. Вы можете импортировать их с помощью инструкции import "fmt" и использовать их функции, такие как fmt.Println().

Внутри одного модуля вы можете создавать несколько пакетов, размещая их в отдельных подкаталогах. Это помогает логически разделять функциональность вашего приложения.

Модуль (module) — это коллекция связанных пакетов, объединённых в единое целое с помощью файла go.mod. Модуль определяет границы проекта и управляет зависимостями от других модулей, включая их версии. С помощью модуля вы можете импортировать пакеты из других модулей, указав их путь и версию в go.mod

🌳 Аналогия: дерево, ветви и листья

Для любителей разобраться почему именно такие слова были использованы. До Go 1.11 (24 августа 2018) были только пакеты. Управление зависимостями было либо ручным (вендоринг, с директорией vendor/), либо с использованием сторонних утилит вроде Glide, Godep, Dep etc. Термин пакет уже был занят!

Подход "Bottom-Up"

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

Этот подход в инженерном деле предлагает начинать с самых простых компонентов и на базе простых решений создавать сложные. Его мы можем применить и при организации файлов проекта.

Рекомендация №1: весь код в корневой директории

При этом программа отличается от обычного пакета тем, что в ней есть файл main.go

Рекомендация №2: использовать internal

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

Однако, официальная рекомендация считает, что с самого начала нужно размещать код в internal:

Initially, it’s recommended placing such packages into a directory named internal...

Рекомендация №3: для каждой исполняемой программы своя директория

Рекомендация №4: web-сервер

project-root-directory/
  go.mod
  internal/
    auth/
      ...
    metrics/
      ...
    model/
      ...
  cmd/
    api-server/
      main.go
    metrics-analyzer/
      main.go
    ...
  ... the project's other directories with non-Go code
    

No nonsense guide to Go projects layout

Минимализм в структуре: Размещайте main.go в корне проекта, если у вас один исполняемый файл. Это упрощает установку и запуск:

go install github.com/you/project@latest

Избегайте internal/ без необходимости: Папка internal/ ограничивает доступ к коду, но не стоит использовать её без веской причины. Если ваш код не предназначен для широкого переиспользования, достаточно не экспортировать элементы, делая их с маленькой буквы.

Не используйте pkg/ по умолчанию: Ранее pkg/ применялась для размещения библиотек, но сейчас это считается устаревшей практикой. Размещайте пакеты непосредственно в корне проекта.

Избегайте util/, common/, shared/: Такие абстрактные папки затрудняют навигацию. Лучше размещать вспомогательные функции рядом с местом их использования или в тематически названных пакетах.

Не дробите проект на множество пакетов без необходимости: Избыточное количество пакетов усложняет структуру и может привести к циклическим зависимостям. Начните с одного пакета и реорганизуйте структуру по мере роста проекта.

Осторожно с мажорными версиями: Избегайте преждевременного перехода на v2, v3 и т.д. Используйте версии v0.x до тех пор, пока API не стабилизируется, чтобы не усложнять поддержку и использование модуля.