Как принято структурировать слой доступа к данным (Data Access Layer) в Go-проектах?

Ответ

В Go нет единого строгого фреймворка, поэтому структура проекта определяется соглашениями. Слой доступа к данным, часто реализуемый через паттерн "Репозиторий" (Repository), принято размещать в следующих директориях:


  1. internal/repository (или internal/storage): Самый распространенный вариант. Код в internal не может быть импортирован другими проектами, что обеспечивает инкапсуляцию логики доступа к данным внутри вашего сервиса.



  2. pkg/repository: Используется, если вы пишете библиотеку, и этот код предназначен для переиспользования в нескольких проектах. Для бизнес-приложений это менее частый случай.



  3. db/ или storage/ (в корне проекта): Иногда используется в небольших проектах для простоты.


Пример структуры:

/my-project
├── cmd/app/main.go
├── internal/
│   ├── service/      # Бизнес-логика
│   │   └── user_service.go
│   ├── repository/   # Слой доступа к данным
│   │   └── user_repository_postgres.go
│   └── models/       # Модели данных
│       └── user.go
└── pkg/
    └── db/           # Логика подключения к БД
        └── postgres.go

Пример кода репозитория:

package repository

import (
    "database/sql"
    "my-project/internal/models"
)

// UserRepository определяет интерфейс для работы с пользователями
// Это позволяет легко подменять реализацию (например, для тестов).
type UserRepository interface {
    GetByID(id int) (*models.User, error)
}

// UserPostgresRepo - конкретная реализация для PostgreSQL.
type UserPostgresRepo struct {
    db *sql.DB // Зависимость от подключения к БД
}

func NewUserPostgresRepo(db *sql.DB) *UserPostgresRepo {
    return &UserPostgresRepo{db: db}
}

func (r *UserPostgresRepo) GetByID(id int) (*models.User, error) {
    // ... логика запроса к БД ...
    return nil, nil
}

Ключевая цель такого разделения — изоляция бизнес-логики от деталей реализации хранилища. Это упрощает тестирование (можно подменить репозиторий моком), сопровождение и возможную замену СУБД в будущем.