Что такое слои в архитектуре приложения (Layered Architecture)?

Ответ

Слоистая архитектура (Layered Architecture) — это подход к проектированию ПО, при котором приложение разделяется на горизонтальные уровни (слои), каждый из которых имеет свою четко определенную зону ответственности.

Основное правило: вышележащий слой может обращаться только к нижележащему. Это создает однонаправленный поток зависимостей и уменьшает связанность компонентов.

Типичные слои в Go веб-сервисе:

  1. Слой представления (Presentation/Transport Layer)

    • Ответственность: Прием HTTP-запросов, парсинг данных (JSON, query-параметры), валидация и передача данных на следующий слой. В Go это обычно пакет http или фреймворки (Gin, Echo).
    • Пример: handler, controller.
  2. Слой бизнес-логики (Business Logic/Service Layer)

    • Ответственность: Реализация основной логики приложения. Координирует работу с данными, выполняет вычисления, применяет бизнес-правила. Не зависит от способа доставки (HTTP, gRPC) и хранения данных (PostgreSQL, Redis).
    • Пример: service, usecase.
  3. Слой доступа к данным (Data Access/Repository Layer)

    • Ответственность: Взаимодействие с хранилищами данных (БД, кэш, внешние API). Абстрагирует детали работы с конкретной базой данных.
    • Пример: repository, storage, dao.

Пример потока в Go:

// 1. Presentation Layer (handler)
func (h *UserHandler) GetUser(c *gin.Context) {
    userID := c.Param("id")
    // Вызов слоя бизнес-логики
    user, err := h.userService.GetByID(c.Request.Context(), userID)
    if err != nil {
        // ... обработка ошибки
        return
    }
    c.JSON(http.StatusOK, user)
}

// 2. Business Logic Layer (service)
func (s *UserService) GetByID(ctx context.Context, id string) (*User, error) {
    // Вызов слоя доступа к данным
    return s.userRepo.FindByID(ctx, id)
}

// 3. Data Access Layer (repository)
func (r *UserRepo) FindByID(ctx context.Context, id string) (*User, error) {
    // Выполнение SQL-запроса к базе данных
    // ... db.QueryRowContext(ctx, "SELECT ...")
    return &User{}, nil
}

Преимущества:

  • Низкая связанность (Low Coupling): Изменение в одном слое (например, замена PostgreSQL на MongoDB) минимально затрагивает другие слои.
  • Тестируемость: Каждый слой можно тестировать изолированно, подменяя его зависимости моками (например, тестировать сервис с моком репозитория).
  • Повторное использование: Логику из слоя сервисов можно использовать в разных обработчиках (HTTP, gRPC, CLI).
  • Понятная структура: Проект легко читать и поддерживать, так как у каждого компонента есть свое место и роль.