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

Что такое слои в архитектуре?

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

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

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

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

Что такое слои в архитектуре?

В разработке программного обеспечения, особенно для больших и сложных систем, слои (layers) — это фундаментальный принцип организации кода, который делит приложение на отдельные уровни ответственности. Каждый слой выполняет строго определённую функцию и взаимодействует только со своими непосредственными соседями, образуя иерархическую структуру. Основная цель — управление сложностью, повышение тестируемости, поддерживаемости и масштабируемости кода.

Представьте себе слоёный торт: каждый слой — отдельный компонент с конкретной задачей (например, бисквит, крем, глазурь). Вы не будете смешивать крем напрямую с тарелкой, так и в архитектуре: слой бизнес-логики не должен напрямую работать с базой данных или HTTP-запросами. Это достигается за счёт разделения ответственностей (Separation of Concerns, SoC).

Ключевые принципы слоистой архитектуры

  • Однонаправленная зависимость: Слои зависят только от слоёв, находящихся ниже них в иерархии. Например, слой представления (UI) зависит от слоя бизнес-логики, но не наоборот.
  • Инкапсуляция: Каждый слой скрывает детали своей реализации от других слоёв, предоставляя чёткий интерфейс (API) для взаимодействия.
  • Слабая связанность (Loose Coupling): Изменения в одном слое должны минимально влиять на другие слои.

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

Рассмотрим классическую трёхслойную (3-tier) архитектуру, адаптированную под Go.

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

Это точка входа в приложение. Он отвечает за взаимодействие с внешним миром: обработку HTTP-запросов, валидацию входных данных, сериализацию ответов (JSON, XML) и маршрутизацию. В Go эту роль часто выполняют роутеры (например, gorilla/mux, chi или стандартный http.ServeMux) и обработчики (handlers).

// Пример handler в слое представления
package presentation

import (
    "encoding/json"
    "net/http"
    "myapp/application"
)

type UserHandler struct {
    Service *application.UserService
}

func (h *UserHandler) GetUser(w http.ResponseWriter, r *http.Request) {
    id := r.PathValue("id")

    // Вызов нижележащего слоя
    user, err := h.Service.GetByID(r.Context(), id)
    if err != nil {
        http.Error(w, err.Error(), http.StatusNotFound)
        return
    }

    // Сериализация ответа
    w.Header().Set("Content-Type", "application/json")
    json.NewEncoder(w).Encode(user)
}

2. Слой бизнес-логики (Business Logic Layer / Application Layer)

Это "мозг" приложения. Здесь содержатся все ключевые правила, алгоритмы и сценарии использования (use cases). Этот слой не знает о деталях HTTP, баз данных или внешних API. Он оперирует domain-моделями (сущностями, value-объектами) и интерфейсами (портами) для доступа к данным. Это сердце Domain-Driven Design (DDD).

// Пример службы в слое бизнес-логики
package application

import (
    "context"
    "errors"
    "myapp/domain"
)

// Интерфейс репозитория (порт) - определён здесь, реализуется в инфраструктуре
type UserRepository interface {
    FindByID(ctx context.Context, id string) (*domain.User, error)
    Save(ctx context.Context, user *domain.User) error
}

type UserService struct {
    repo UserRepository
}

func (s *UserService) GetByID(ctx context.Context, id string) (*domain.UserDTO, error) {
    if id == "" {
        return nil, errors.New("invalid id")
    }

    // Бизнес-правило: только активные пользователи
    user, err := s.repo.FindByID(ctx, id)
    if err != nil {
        return nil, err
    }
    if !user.IsActive {
        return nil, errors.New("user is inactive")
    }

    // Преобразование доменной модели в DTO для слоя представления
    return &domain.UserDTO{ID: user.ID, Name: user.Name, Email: user.Email}, nil
}

3. Слой доступа к данным / Инфраструктурный слой (Data Access Layer / Infrastructure Layer)

Этот слой отвечает за взаимодействие с внешними системами: базами данных (PostgreSQL, MongoDB), кешами (Redis), внешними API, файловой системой, брокерами сообщений (Kafka). Он реализует интерфейсы (порты), объявленные в слое бизнес-логики. Здесь живут конкретные реализации репозиториев, клиенты к внешним сервисам.

// Пример репозитория в инфраструктурном слое
package infrastructure

import (
    "context"
    "database/sql"
    "myapp/domain"
    "myapp/application" // Импортируем для реализации интерфейса
)

type PostgreSQLUserRepository struct {
    db *sql.DB
}

// Реализация интерфейса UserRepository из слоя бизнес-логики
func (r *PostgreSQLUserRepository) FindByID(ctx context.Context, id string) (*domain.User, error) {
    const query = `SELECT id, name, email, is_active FROM users WHERE id = $1`
    row := r.db.QueryRowContext(ctx, query, id)

    var user domain.User
    err := row.Scan(&user.ID, &user.Name, &user.Email, &user.IsActive)
    if err == sql.ErrNoRows {
        return nil, application.ErrUserNotFound // Используем ошибку доменного уровня
    }
    if err != nil {
        return nil, err
    }
    return &user, nil
}

Преимущества слоистой архитектуры в Go

  • Удобство тестирования: Слой бизнес-логики можно тестировать юнит-тестами, подменяя репозитории моками (gomock, testify/mock). Слой представления тестируется через интеграционные или E2E-тесты.
  • Гибкость и заменаемость: Вы можете сменить базу данных или фреймворк веб-сервера, переписав только инфраструктурный слой, почти не затрагивая ядро приложения.
  • Понятность кодовой базы: Новичку в проекте легче разобраться, так как код структурирован по функциональному признаку.
  • Параллельная разработка: Разные команды могут работать над разными слоями одновременно.

Примеры и вариации в Go-экосистеме

  • Clean Architecture / Hexagonal Architecture: Более продвинутые эволюции слоистой архитектуры, где доменный слой (Domain Layer) находится в самом центре и не зависит ни от чего. В Go это часто реализуется через организацию пакетов: internal/domain, internal/app, internal/infrastructure, cmd/.
  • Многослойные проекты: Классическая структура папок cmd/, internal/, pkg/ из стандартного Go Project Layout хорошо ложится на слоистый подход.

Заключение

Слои в архитектуре — это не строгий фреймворк, а ментальная модель и набор принципов для создания чистого, долгоживущего кода. В Go, с его акцентом на простоту и явные зависимости, этот подход особенно органичен. Правильно применяя слои, вы создаёте приложение, которое легко развивать, тестировать и адаптировать к новым требованиям, что критически важно в долгосрочной перспективе любого проекта.

Что такое слои в архитектуре? | PrepBro