Перейти до змісту

Структура проєкту та робочі простори

Go має тверду думку щодо кількох каталогових домовленостей і навмисно мовчить про решту. Ця стаття розглядає патерни структури, які інструменти насправді розуміють, і робочі простори (workspaces) для розробки кількох модулів одночасно.

Домовленості, які інструменти забезпечують

Дві назви каталогів мають реальне значення для команди go:

  • internal/ — пакети під каталогом internal/ можна імпортувати лише з коду, укоріненого в батьківському каталозі internal/. Це забезпечена компілятором приватність на рівні дерева пакетів.
  • testdata/ — ігнорується інструментами збірки; місце для тестових фікстур.
example.com/shop/
├── go.mod
├── internal/
│   └── auth/         # імпортується лише в межах example.com/shop/...
└── store/
    └── testdata/     # фікстури, ігноруються компілятором

Усе інше щодо структури — це домовленість, а не правило.

Правило internal/ забезпечує компілятор — імпорт ззовні батьківського піддерева не вдасться:

// з іншого модуля, що імпортує example.com/shop/internal/auth
import _ "example.com/shop/internal/auth"
// compile error: use of internal package example.com/shop/internal/auth not allowed

cmd/ та поширена структура

Широко вживана (але необов'язкова) форма відокремлює точки входу від коду бібліотек:

  • cmd/<name>/ — один каталог на кожну виконувану програму, кожен зі своїм package main. Назва каталогу стає назвою бінарника.
  • internal/ — приватні пакети, основна маса коду.
  • пакети верхнього рівня — публічний API модуля, якщо його призначено для імпорту.
myapp/
├── go.mod
├── cmd/
│   ├── server/main.go     # збирає бінарник "server"
│   └── cli/main.go        # збирає бінарник "cli"
├── internal/
│   ├── store/
│   └── auth/
└── api/                   # експортований, доступний для імпорту іншим

Зберіть конкретну команду за її шляхом:

go build ./cmd/server      # створює ./server
go install ./cmd/cli       # встановлює бінарник "cli"

З погляду Python: немає вимоги src/ і немає __init__.py. Каталог є пакетом завдяки своїм файлам .go; cmd/ та internal/ — це приблизні відповідники теки скриптів/точок входу та приватного підпакета.

Тримайте main тонким

Сильна домовленість: package main має робити якомога менше — розбирати прапорці, з'єднувати все докупи, викликати пакети з internal/ — щоб справжня логіка лишалася придатною до тестування та імпорту. Бінарник — це клей; пакети — це програма.

Робочі простори: розробка кількох модулів разом

Коли ви змінюєте два модулі одночасно — скажімо, застосунок і бібліотеку, від якої він залежить, — редагування go.mod із replace для кожного працює, але це марудно й легко закомітити випадково. Робочий простір вирішує це файлом go.work, який наказує команді go використовувати кілька локальних модулів разом.

go work init ./app ./lib
// go.work
go 1.25.0

use (
    ./app
    ./lib
)

Тепер збірка чи тестування з будь-якого місця в робочому просторі вирішує імпорти ./lib у вашу локальну копію — без директив replace. Додавайте ще через go work use ./other.

Ключова практика: go.work лише локальний. Він для циклу розробки кількох модулів на вашій машині, тож його зазвичай ігнорують у git і ніколи не публікують. Випущені збірки все одно вирішують залежності через go.mod/go.sum.

Швидка довідка

Шлях / файл Значення
internal/ імпортується лише в межах піддерева батьківського модуля
testdata/ тестові фікстури, ігноруються збіркою
cmd/<name>/ одна виконувана програма на підкаталог (package main)
go build ./cmd/x зібрати конкретну команду
go.work (go work init/use) використовувати кілька локальних модулів разом
тонкий main логіка живе в пакетах, придатних до імпорту

Джерела