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

В какой папке лежит слой обращения в базу данных

2.2 Middle🔥 191 комментариев
#Микросервисы и архитектура

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

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

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

Где размещается слой работы с базой данных в проекте на Go?

В экосистеме Go не существует жёсткого стандарта или единого мнения, диктующего обязательное название папки для слоя доступа к данным (Data Access Layer, DAL) или репозитория (Repository Layer). Это связано с философией языка, которая поощряет простоту и практичность, оставляя выбор архитектуры на усмотрение команды. Однако, сложились устойчивые и общепринятые паттерны организации кода, которые можно наблюдать в большинстве production-проектов.

Основная идея — отделить логику работы с данными (SQL-запросы, вызовы API внешних сервисов, кэширование) от бизнес-логики (use cases, сервисы) и транспортного слоя (HTTP-обработчики, gRPC). Это повышает тестируемость, поддерживаемость и позволяет менять источник данных без переписывания всей бизнес-логики.

Типичные названия директорий и их назначение

Наиболее распространённые варианты расположения кода для работы с БД:

  1. /internal/repository или /internal/repositories
    *   Это, пожалуй, самый популярный выбор в современных проектах, следующих принципам **чистой архитектуры (Clean Architecture)** или **гексагональной архитектуры (Hexagonal Architecture)**. Папка `internal` указывает, что этот код является приватным для модуля и не должен импортироваться извне.
    *   В этой директории находятся **репозитории (Repositories)** — структуры и интерфейсы, которые абстрагируют доступ к данным. Каждый репозиторий отвечает за одну сущность (например, `UserRepository`, `OrderRepository`).
    *   Ключевая особенность: репозитории определяются через **интерфейсы**, которые живут в этой же папке или в соседней (например, `/internal/domain/repository`). Реализация этих интерфейсов (на SQL, в памяти и т.д.) помещается в поддиректорию, например, `postgres`, или в файлы с суффиксом `_impl`.

```go
// internal/domain/user.go
package domain

type User struct {
    ID    int
    Email string
    Name  string
}

// internal/domain/repository/user_repository.go
package repository

import "project/internal/domain"

type UserRepository interface {
    FindByID(id int) (*domain.User, error)
    Save(user *domain.User) error
}

// internal/repository/postgres/user_repository.go
package postgres

import (
    "database/sql"
    "project/internal/domain"
    "project/internal/domain/repository"
)

type userRepository struct {
    db *sql.DB
}

func NewUserRepository(db *sql.DB) repository.UserRepository {
    return &userRepository{db: db}
}

func (r *userRepository) FindByID(id int) (*domain.User, error) {
    // Реализация SQL-запроса...
    row := r.db.QueryRow("SELECT id, email, name FROM users WHERE id = $1", id)
    user := &domain.User{}
    err := row.Scan(&user.ID, &user.Email, &user.Name)
    return user, err
}
```

2. /internal/store

    *   Более традиционное название, пришедшее из ранних шаблонов Go. Отражает место, где хранится состояние (store) приложения. Часто используется для прямого доступа к `*sql.DB` или ORM.
    *   Может быть менее абстрактным, чем `repository`, и иногда содержит более низкоуровневые операции с БД.

  1. /internal/db или /internal/database
    *   Прямое и очевидное название. Здесь обычно размещаются:
        *   Конфигурация подключения к базе (`sql.Open`, миграции).
        *   Прямые реализации запросов (без обязательного использования интерфейсного слоя).
        *   Вспомогательные функции для работы с БД.
    *   Часто встречается в проектах средней сложности, где абстракция репозитория может быть избыточной.

  1. /pkg/db или /pkg/repository
    *   Используется, если код слоя данных должен быть доступен для импорта из других модулей (что случается реже). Папка `pkg`, в отличие от `internal`, предполагает публичный API.

  1. Плоская структура (без отдельной папки)
    *   В очень небольших проектах или микросервисах, где есть всего 2-3 сущности, код для работы с БД может лежать в корне модуля или рядом с обработчиками HTTP, если это не нарушает читаемость.

Рекомендуемая структура и практика

Для новых проектов я рекомендую следующий подход, который обеспечивает хороший баланс между чёткостью и гибкостью:

/myapp
├── cmd/                 # Точки входа (например, /cmd/api, /cmd/cli)
├── internal/            # Приватный код приложения
│   ├── domain/         # Бизнес-сущности (структуры, интерфейсы репозиториев)
│   │   ├── user.go
│   │   └── repository/ # Интерфейсы репозиториев
│   │       └── user_repository.go
│   ├── repository/     # РЕАЛИЗАЦИИ репозиториев (слой работы с БД)
│   │   └── postgres/  # Конкретная реализация для PostgreSQL
│   │       └── user_repository.go
│   ├── service/        # Бизнес-логика (использует интерфейсы репозиториев)
│   │   └── user_service.go
│   └── transport/      # HTTP/gRPC обработчики
│       └── http/
│           └── user_handler.go
├── pkg/                # Публичный код (если нужен)
├── migrations/         # SQL-миграции
├── go.mod
└── go.sum

Ключевые принципы, которые делают эту структуру эффективной:

  • Зависимость от абстракций: Сервисный слой (/internal/service) зависит только от интерфейса UserRepository из /internal/domain/repository, а не от конкретной SQL-реализации. Это позволяет легко подменять реализацию (например, для тестов).
  • Инъекция зависимостей (Dependency Injection): Репозиторий, принимающий *sql.DB в конструкторе, передаётся (инжектируется) в сервис при инициализации приложения (обычно в cmd/api/main.go).
  • Отделение миграций: SQL-миграции вынесены в отдельную директорию (/migrations), что является стандартом для инструментов вроде golang-migrate.

Таким образом, отвечая прямо на вопрос: в современном Go-проекте код слоя обращения к базе данных чаще всего лежит в папке /internal/repository (в виде реализаций интерфейсов), в то время как их контракты (интерфейсы) могут быть определены в /internal/domain/repository. Это не догма, но сильный конвенциональный выбор, ведущий к созданию чистого, тестируемого и адаптируемого кода.

В какой папке лежит слой обращения в базу данных | PrepBro