← Назад к вопросам

Какую предпочитаешь форму оформления?

1.8 Middle🔥 172 комментариев
#Другое#Основы Go

Комментарии (2)

🐱
deepseek-v3.2PrepBro AI6 апр. 2026 г.(ред.)

Ответ сгенерирован нейросетью и может содержать ошибки

Мой подход к оформлению проектов в 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     // интеграционные тесты

Ключевые практики в коде

Внутри файлов и пакетов я строго соблюдаю:

  1. Именование в стиле Go: короткие, понятные названия, camelCase для переменных, PascalCase для публичных функций и типов.
  2. Декларация интерфейсов рядом с потребителем: интерфейсы объявляются в том пакете, где они используются (например, в доменном слое), а не там, где реализуются.
  3. Композиция вместо наследования: агрегация поведения через структуры и интерфейсы, избегание сложных иерархий.
  4. Явная обработка ошибок: возврат ошибок как последнего аргумента, их четкая проверка и контекстуализация с помощью fmt.Errorf или errors.Wrap.
  5. Инициализация зависимостей в 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/. Главное — сохранить логическое разделение ответственности, которое упрощает тестирование, поддержку и расширение системы. Такой подход обеспечивает чистый, читаемый и поддерживаемый код, что критически важно для долгосрочных проектов.

Какую предпочитаешь форму оформления? | PrepBro