Какую предпочитаешь форму оформления?
Комментарии (2)
Ответ сгенерирован нейросетью и может содержать ошибки
Мой подход к оформлению проектов в Go
Я предпочитаю иерархичную и модульную структуру проекта, которая балансирует между стандартами сообщества и практическими потребностями конкретного проекта. Основной ориентир — это рекомендации от команды Go и проверенные паттерны из реальных проектов.
Основные принципы структуры
Я строю проекты по следующим ключевым принципам:
- Следование стандарту Go Modules: Корень проекта всегда содержит
go.modфайл, что обеспечивает четкое управление зависимостями и версиями. - Разделение по функциональным слоям (Clean Architecture/Onion): Даже в небольших проектах стараюсь отделять:
* `internal/` — для приватных пакетов, недоступных внешним потребителям.
* `pkg/` — для публичных, reusable библиотек, если проект предоставляет такие.
* Доменный слой (`domain/`, `entities/`) для бизнес-сущностей и правил.
* Слой применения бизнес-логики (`usecases/`, `services/`).
* Слой инфраструктуры (`repositories/`, `clients/`, `handlers/`) для работы с внешними системами.
- Конфигурация через интерфейсы: Внедрение зависимостей через интерфейсы, объявленные в доменном слое, а реализации — в инфраструктурном.
- Группировка по feature/domain в крупных проектах: Для монолитов с множеством функциональных блоков иногда применяю вертикальное разделение (например,
user/,order/,payment/), где каждый модуль содержит свою внутреннюю структуру слоев.
Пример базовой структуры проекта
Вот пример базовой структуры проекта среднего размера, которую я часто использую как стартовую точку:
// Пример организации в корневом каталоге проекта
cmd/
api/
main.go // точка входа для API сервера
cli/
main.go // точка входа для CLI инструмента
internal/
config/
config.go // структуры и логика загрузки конфигурации
domain/
user.go // бизнес-сущность User с методами и правилами
order.go
repository/
interface.go // интерфейсы типа UserRepository
postgres/
user.go // конкретная реализация для PostgreSQL
service/
user_service.go // бизнес-логика, работающая с репозиториями
handler/
http/
user_handler.go // HTTP обработчики, зависят от сервисов
pkg/
logger/
logger.go // публичный пакет для логирования
utils/
validation.go // вспомогательные функции
configs/
config.yaml // файлы конфигурации
tests/
integration/
user_test.go // интеграционные тесты
Ключевые практики в коде
Внутри файлов и пакетов я строго соблюдаю:
- Именование в стиле Go: короткие, понятные названия,
camelCaseдля переменных,PascalCaseдля публичных функций и типов. - Декларация интерфейсов рядом с потребителем: интерфейсы объявляются в том пакете, где они используются (например, в доменном слое), а не там, где реализуются.
- Композиция вместо наследования: агрегация поведения через структуры и интерфейсы, избегание сложных иерархий.
- Явная обработка ошибок: возврат ошибок как последнего аргумента, их четкая проверка и контекстуализация с помощью
fmt.Errorfилиerrors.Wrap. - Инициализация зависимостей в
main.go: сборка "объекта графа" (wire, manual DI) исключительно в точке входа, что делает слои независимыми и тестируемыми.
// Пример объявления интерфейса в доменном слое и его использования
// internal/domain/repository/interface.go
package repository
type UserRepository interface {
FindByID(ctx context.Context, id int) (*domain.User, error)
Save(ctx context.Context, user *domain.User) error
}
// internal/service/user_service.go
package service
type UserService struct {
repo repository.UserRepository
}
func (s *UserService) GetUser(ctx context.Context, id int) (*domain.User, error) {
// Явная обработка ошибки
user, err := s.repo.FindByID(ctx, id)
if err != nil {
return nil, fmt.Errorf("failed to get user %d: %w", id, err)
}
// ... бизнес-логика
return user, nil
}
Адаптация под проект
Эта структура не является догмой. Для микросервисов или CLI-тулов она может быть значительно упрощена (например, только cmd/, internal/ и pkg/). Для больших монолитов я добавляю уровень modules/ или features/. Главное — сохранить логическое разделение ответственности, которое упрощает тестирование, поддержку и расширение системы. Такой подход обеспечивает чистый, читаемый и поддерживаемый код, что критически важно для долгосрочных проектов.