Цели модуля
После модуля студент сможет:
- Объяснить, почему Go подходит для бэкенд-разработки
- Настроить рабочее окружение (Go, gopls, delve)
- Инициализировать проект через go mod
- Понимать структуру go.mod и go.sum
- Использовать go work для монорепо
- Запускать задачи через Makefile
- Понимать стандартные соглашения структуры проекта
1.1 Почему Go для бэкенда и API
Преимущества Go
-
Простой синтаксис. В Go нет наследования, перегрузки операторов, исключений. Меньше способов сделать одно и то же - меньше споров в команде, легче читать чужой код.
-
Быстрая компиляция. Go компилируется в нативный бинарник. Время сборки больших проектов - секунды, а не минуты.
-
Встроенная конкурентность. Горутины и каналы - часть языка, а не библиотека. Запустить 10 000 горутин так же просто, как 10.
-
Мощная стандартная библиотека. net/http, encoding/json, database/sql - всё из коробки. Для большинства задач не нужны внешние зависимости.
-
Статическая типизация. Ошибки типов ловятся на этапе компиляции, а не в production.
-
Кроссплатформенность. Один бинарник работает на Linux, macOS, Windows без установки рантайма.
Где Go особенно силён
- REST API и микросервисы
- CLI-утилиты (kubectl, docker, terraform написаны на Go)
- Сетевые сервисы и прокси
- Фоновые воркеры и обработчики очередей
- Cloud-native приложения
1.2 Экосистема Go и инструменты
Обязательные инструменты
go - основной инструмент (компилятор, менеджер пакетов, тестирование).
Установка (Linux):
bashwget https://go.dev/dl/go1.23.0.linux-amd64.tar.gz sudo tar -C /usr/local -xzf go1.23.0.linux-amd64.tar.gz echo "export PATH=$PATH:/usr/local/go/bin" >> ~/.bashrc source ~/.bashrc
Проверка установки:
bashgo version
gopls - language server для автодополнения в IDE.
bashgo install golang.org/x/tools/gopls@latest
delve - отладчик.
bashgo install github.com/go-delve/delve/cmd/dlv@latest
golangci-lint - агрегатор линтеров.
bashcurl -sSfL https://raw.githubusercontent.com/golangci/golangci-lint/master/install.sh | sh -s -- -b $(go env GOPATH)/bin v1.60.0
Основные команды go
| Команда | Назначение |
|---|---|
| go mod init | Инициализация модуля |
| go mod tidy | Синхронизация зависимостей |
| go build | Сборка бинарника |
| go run | Запуск без сборки |
| go test | Запуск тестов |
| go test -race | Тесты с race detector |
| go vet | Статический анализ |
| go fmt | Форматирование кода |
| go generate | Генерация кода |
1.3 Структура Go-проекта
Стандартная структура
Привязка к шаблону проекта: корень проекта.
textproject-root/ ├── cmd/ # Entry points (main.go для каждого бинарника) │ └── app/ │ └── main.go ├── internal/ # Приватный код проекта │ ├── app/ # DI-контейнер и сборка модулей │ ├── config/ # Конфигурация │ ├── models/ # Доменные модели │ ├── repository/ # Интерфейсы репозиториев │ ├── service/ # Бизнес-логика │ ├── usecase/ # Use Cases │ ├── adapters/ # Реализации интерфейсов │ ├── handlers/ # HTTP-хэндлеры │ └── observability/ # Логи, метрики, трейсинг ├── api/ # OpenAPI-спецификации ├── migrations/ # SQL-миграции ├── deploy/ # Terraform, Ansible ├── docker/ # Dockerfile, docker-compose ├── configs/ # Конфигурационные файлы ├── scripts/ # Вспомогательные скрипты ├── docs/ # Документация, ADR ├── go.mod # Описание модуля ├── go.sum # Контрольные суммы зависимостей ├── Makefile # Автоматизация задач └── .gitignore
Зачем нужна папка internal
Папка internal - специальная директория в Go. Код внутри неё не может быть импортирован из других модулей. Это защищает внутренние реализации от внешнего использования.
Пример:
- internal/service - только ваш проект использует эти сервисы
- pkg/utils - можно вынести, если хотите переиспользовать в других проектах
Зачем нужна папка cmd
В cmd лежит точка входа - функция main. Если у проекта один бинарник:
textcmd/app/main.go
Если несколько бинарей (как в serverless-версии шаблона):
textcmd/api/main.go cmd/git-gateway/main.go cmd/outbox-relay/main.go
1.4 go mod и зависимости
Инициализация модуля
bashgo mod init github.com/yourname/projectname
Это создаёт файл go.mod:
textmodule github.com/yourname/projectname go 1.23
Добавление зависимостей
bashgo get github.com/jackc/pgx/v5
После этого go.mod обновляется:
textmodule github.com/yourname/projectname go 1.23 require ( github.com/jackc/pgx/v5 v5.6.0 )
go.sum - что это
go.sum содержит криптографические хеши всех зависимостей. Это защита от supply-chain атак: если хеш не совпадёт при скачивании, сборка упадёт.
Никогда не редактируйте go.sum вручную. Он управляется командами go mod.
Синхронизация зависимостей
bashgo mod tidy
Эта команда:
- Добавляет зависимости, которые импортируются в коде, но отсутствуют в go.mod
- Удаляет зависимости, которые есть в go.mod, но не используются
- Обновляет go.sum
Запускайте go mod tidy после любых изменений импортов.
Проверка зависимостей
bashgo mod verify
Проверяет, что все зависимости в go.sum соответствуют ожидаемым хешам.
1.5 go work (workspaces)
Когда нужен workspace
Если у вас монорепо с несколькими модулями, go work позволяет работать с ними как с одним проектом.
Пример: у вас есть основной сервис и общая библиотека.
textworkspace/ ├── service/ │ ├── go.mod │ └── main.go ├── common/ │ ├── go.mod │ └── utils.go └── go.work
Создание workspace
bashgo work init ./service ./common
Файл go.work:
textgo 1.23 use ( ./service ./common )
Теперь service может импортировать common без публикации в реестр:
textimport "github.com/yourname/common"
Когда использовать
- Монорепо с несколькими сервисами
- Разработка библиотеки и её использование одновременно
- Локальная разработка с несколькими связанными модулями
1.6 Makefile для автоматизации
Привязка к шаблону: Makefile в корне проекта.
Пример Makefile из шаблона
makefile.PHONY: build test lint run migrate clean # Сборка бинарника build: go build -o bin/app ./cmd/app # Запуск тестов с race detector test: go test -race -cover ./... # Линтинг lint: golangci-lint run ./... # Запуск сервиса run: go run ./cmd/app serve # Применение миграций migrate: go run ./cmd/app migrate # Форматирование кода fmt: gofmt -s -w . # Очистка артефактов clean: rm -rf bin/
ВАЖНО: В Makefile отступы - это табуляция, а не пробелы. Если использовать пробелы, make выдаст ошибку.
Зачем нужен Makefile
- Единая точка входа для всех задач
- Не нужно запоминать длинные команды
- CI/CD использует те же команды, что и разработчик локально
- Новый член команды запускает make build и сразу работает
1.7 Стандартные соглашения проекта
Именование пакетов
- Короткие, без under_score: repo, user, auth
- Не используйте множественное число: model, а не models (хотя в шаблоне используется models - это допустимое исключение для папки)
- Не повторяйте имя пакета в именах типов: repo.Repository, а не repo.RepoRepository
Именование файлов
- Маленькие буквы, без пробелов: repo_service.go
- Тесты: repo_service_test.go
- Один тип - один файл (для крупных типов)
Именование переменных
- Короткие имена для коротких скоупов: i, j, ctx, err
- Полные имена для длинных скоупов: repository, handler
- Интерфейсы: Reader, Writer, Closer (суффикс -er)
- Константы: MaxRetries, DefaultTimeout
Обработка ошибок
В Go нет исключений. Ошибки возвращаются как значения:
goresult, err := doSomething() if err != nil { return fmt.Errorf("do something: %w", err) }
Это не многословность - это явное управление потоком ошибок.
💱 Компромиссы
- Стандартная библиотека vs внешние зависимости:
net/httpиencoding/jsonзакрывают типовые задачи без записей вgo.mod, но за специализированным (драйверpgx) платим ростом графа зависимостей и хешами вgo.sum, которые надо обслуживать. internal/vspkg/: код вinternal/нельзя импортировать из чужих модулей — приватность по умолчанию, но переиспользовать его в другом проекте без выноса в отдельную библиотеку не выйдет.go workvs версионированные модули: workspace позволяет править сервис и общую библиотеку одновременно без публикации, но локальный граф модулей расходится с тем, что получат потребители поgo.mod.- Makefile vs сырые команды
go:make buildдаёт единую точку входа, одинаковую у разработчика и в CI, но добавляет слой автоматизации: отступы только табами, цели надо поддерживать. - Простота языка vs выразительность: без наследования, перегрузки и исключений меньше способов сделать одно и то же; за читаемость платим ручной сборкой паттернов вроде DI из интерфейсов и композиции.
Практическое задание
Задание 1: Инициализация проекта
- Создайте директорию для проекта:
bashmkdir my-go-project cd my-go-project
- Инициализируйте модуль:
bashgo mod init github.com/yourname/my-go-project
- Создайте структуру папок:
bashmkdir -p cmd/app internal/models internal/service
- Создайте файл cmd/app/main.go:
gopackage main import "fmt" func main() { fmt.Println("Hello, Go!") }
- Запустите:
bashgo run ./cmd/app
Задание 2: Добавление зависимости
- Добавьте зависимость pgx:
bashgo get github.com/jackc/pgx/v5
-
Изучите изменения в go.mod и go.sum.
-
Запустите go mod tidy и объясните, что изменилось.
Задание 3: Makefile
-
Создайте Makefile с целями build, test, run, fmt.
-
Запустите make build и убедитесь, что бинарник создан.
-
Запустите make run.
Задание 4: Исследование шаблона
-
Откройте go.mod шаблона проекта.
-
Выпишите все зависимости и объясните назначение каждой.
-
Откройте Makefile шаблона и объясните каждую цель.
-
Нарисуйте структуру папок шаблона и объясните назначение каждой.
Quiz "Проверь себя"
go work?go.sum? — выберите все подходящиеgo mod tidy?internal?go get github.com/pkg/errors?go.mod?go.mod?package main
import "github.com/pkg/errors"
func main() {
errors.New("oops")
}✅ Итоги модуля
Студент должен:
- Установить Go, gopls, golangci-lint
- Инициализировать проект через go mod init
- Добавить зависимость через go get
- Объяснить назначение каждой зависимости в go.mod шаблона
- Создать Makefile с целями build, test, run
- Объяснить структуру папок шаблона проекта
- Ответить на все вопросы Quiz
🔗 Мостик к Модулю 2
Следующий модуль: Модуль 2. Базовые понятия языка - переменные, типы, слайсы, мапы, структуры, методы. Привязка к internal/models/ шаблона.