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

Что такое Use Cases?

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

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

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

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

Что такое Use Cases (Сценарии использования)?

Use Cases — это концепция из области проектирования программного обеспечения и бизнес-анализа, описывающая взаимодействие между пользователем (актором) и системой для достижения конкретной цели. В контексте разработки на Go (и любого другого языка) use case представляет собой не просто техническую спецификацию, а бизнес-правило или операцию, которую система должна выполнить, чтобы предоставить ценность пользователю. Это ключевой элемент архитектуры "Чистого" (Clean) или Гексагонального (Hexagonal) подхода, где бизнес-логика изолирована от инфраструктурных деталей (баз данных, HTTP. фреймворков и т.д.).

Ключевые характеристики Use Case в коде на Go

  • Одна ответственность: Каждый use case реализует единственную бизнес.транзакцию (например, "Создать заказ", "Начислить бонусы пользователю", "Сгенерировать отчет").
  • Изолированность от инфраструктуры: Use case не зависит от способа вызова (HTTP, CLI, gRPC) или способа хранения данных (PostgreSQL, MongoDB, in-memory). Он работает с интерфейсами (interfaces), а не с конкретными реализациями.
  • Оркестрация бизнес-логики: Use case координирует вызовы к сущностям (Entities) и репозиториям (Repositories), применяет правила валидации и обрабатывает ошибки предметной области.
  • Входные и выходные данные (DTO): Обычно принимает простую структуру данных на вход (запрос) и возвращает другую структуру или ошибку на выход. Это контракт для слоя доставки (delivery).

Пример Use Case на Go: "Создание пользователя"

Рассмотрим реализацию use case для регистрации нового пользователя.

1. Определение интерфейсов репозитория (инфраструктурный слой, НЕ в use case)

// user/repository.go
package user

// Repository - интерфейс, который знает use case.
// Конкретная реализация (на PostgreSQL, в памяти и т.д.) будет предоставлена "снаружи".
type Repository interface {
    FindByEmail(email string) (*User, error)
    Save(user *User) error
}

**2. Определение сущности (Entity) - ядра бизнес.

логики**

// user/entity.go
package user

import (
    "errors"
    "regexp"
)

var (
    ErrInvalidEmail = errors.New("invalid email format")
    ErrUserExists   = errors.New("user with this email already exists")
)

type User struct {
    ID    string
    Email string
    Name  string
}

// NewUser - бизнес-правила создания сущности, валидация.
func NewUser(email, name string) (*User, error) {
    if !isValidEmail(email) {
        return nil, ErrInvalidEmail
    }
    return &User{
        Email: email,
        Name:  name,
    }, nil
}

func isValidEmail(e string) bool {
    // Упрощенная проверка для примера
    re := regexp.MustCompile(`^[a-z0-9._%+\-]+@[a-z0-9.\  
-]+\.[a-z]{2,4}$`)
    return re.MatchString(e)
}

3. Реализация самого Use Case

// user/create_usecase.go
package user

// CreateUserRequest - Data Transfer Object (DTO) для входных данных.
type CreateUserRequest struct {
    Email string
    Name  string
}

// CreateUserResponse - DTO для выходных данных.
type CreateUserResponse struct {
    UserID string
}

// CreateUserUseCase - сама реализация сценария использования.
type CreateUserUseCase struct {
    userRepo Repository
}

// NewCreateUserUseCase - конструктор (dependency injection).
func NewCreateUserUseCase(repo Repository) *CreateUserUseCase {
    return &CreateUserUseCase{userRepo: repo}
}

// Execute - основной метод use case, реализующий бизнес-сценарий.
func (uc *CreateUserUseCase) Execute(req CreateUserRequest) (*CreateUserResponse, error) {
    // 1. Проверить, не существует ли уже пользователь с таким email (бизнес.
правило)
    existingUser, err := uc.userRepo.FindByEmail(req.Email)
    if err != nil && !errors.Is(err, ErrNotFound) { // ErrNotFound - допустимая ошибка репозитория
        return nil, err // Прокидываем техническую ошибку (например, разрыв соединения с БД)
    }
    if existingUser != nil {
        return nil, ErrUserExists // Возвращаем ошибку предметной области
    }

    // 2. Создать валидированную сущность User (бизнес-правила валидации)
    user, err := NewUser(req.Email, req.Name)
    if err != nil {
        return nil, err // ErrInvalidEmail
    }

    // 3. Сохранить пользователя
    err = uc.userRepo.Save(user)
    if err != nil {
        return nil, err
    }

    // 4. Вернуть ответ
    return &CreateUserResponse{UserID: user.ID}, nil
}

Преимущества подхода Use Cases в Go

  • Тестируемость: Use case можно протестировать в полной изоляции с помощью mock-реализаций репозиториев. Не нужна реальная база данных или HTTP-сервер.
    func TestCreateUserUseCase_UserExists(t *testing.T) {
        // 1. Создаем mock репозитория
        mockRepo := new(MockRepository)
        // 2. Настраиваем ожидание: FindByEmail вернет существующего пользователя
        mockRepo.On("FindByEmail", "test@example.com").Return(&user.User{ID: "123"}, nil)
    
        // 3. Создаем use case с mock-зависимостью
        uc := user.NewCreateUserUseCase(mockRepo)
    
        // 4. Выполняем use case
        _, err := uc.Execute(user.CreateUserRequest{Email: "test@example.com"})
    
        // 5. Проверяем, что получили ожидаемую бизнес-ошибку
        assert.ErrorIs(t, err, user.ErrUserExists)
        mockRepo.AssertExpectations(t)
    }
    
  • Поддержка и читаемость: Код организован вокруг бизнес-возможностей, а не технических деталей. Новому разработчику легче понять, что делает система.
  • Гибкость: Один и тот же use case можно вызвать из HTTP-обработчика, gRPC-сервиса, CLI-команды или фонового worker'a, не изменяя его код.
  • Защита доменной логики: Бизнес-правила (валидация email, проверка на дубликаты) надежно инкапсулированы внутри сущностей и use cases и не "расползаются" по всему коду.

Где Use Cases располагаются в архитектуре?

В типичной чистой архитектуре на Go:

  • Слой Внутренних Сущностей (Entities): user/entity.go — базовые структуры и правила.
  • Слой Use Cases (Сценарии использования): user/create_usecase.go — прикладная бизнес-логика.
  • Слой Адаптеров/Инфраструктуры (Adapters/Infrastructure): Реализации Repository на PostgreSQL, HTTP-обработчики (/api/v1/user), которые вызывают uc.Execute(...).
  • Слой Внешних Интерфейсов (External Interfaces): Точка входа (cmd/api/main.go), которая "собирает" все компоненты вместе (внедряет реальный репозиторий в use case).

Таким образом, Use Cases в Go — это не просто функции, а четко структурированные компоненты, которые инкапсулируют конкретные бизнеспроцессы, делая приложение более тестируемым, поддерживаемым и независимым от внешних фреймворков и технологий. Они являются мостом между высокоуровневыми требованиями заказчика и низкоуровневой технической реализацией.

Что такое Use Cases? | PrepBro