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

Где в гексагональной архитектуре размещается Frontend?

2.7 Senior🔥 91 комментариев
#Архитектура и паттерны

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

🐱
claude-haiku-4.5PrepBro AI2 апр. 2026 г.(ред.)

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

Frontend в гексагональной архитектуре

Frontend размещается на внешнем кольце (Ports and Adapters) как один из адаптеров для взаимодействия с пользователем. Это критично для понимания архитектуры.

Структура гексагональной архитектуры

┌─────────────────────────────────────────┐
│         EXTERNAL WORLD                   │
│  (Frontend, Mobile, CLI, Third-party)   │
└──────────┬──────────────────────────────┘
           │
           │ HTTP/REST/GraphQL
           │
┌──────────▼────────────────────────────────┐
│    PORTS & ADAPTERS (Boundary Layer)     │
│  ┌────────────────────────────────────┐  │
│  │  API Adapter (HTTP/REST)           │  │
│  │  - Controllers                     │  │
│  │  - DTOs                            │  │
│  │  - Error Handlers                  │  │
│  └────────────────────────────────────┘  │
│                                          │
│  Frontend + Mobile + CLI = Adapters     │
└──────────┬───────────────────────────────┘
           │
           │ (Internal Protocol)
           │
┌──────────▼───────────────────────────────┐
│    APPLICATION LAYER                     │
│  - Use Cases / Services                  │
│  - Business Rules (validation, logic)    │
│  - Error Handling                        │
└──────────┬───────────────────────────────┘
           │
           │
┌──────────▼───────────────────────────────┐
│    DOMAIN LAYER                          │
│  - Entities                              │
│  - Domain Services                       │
│  - Value Objects                         │
│  - Domain Rules (pure business logic)    │
└──────────┬───────────────────────────────┘
           │
           │
┌──────────▼───────────────────────────────┐
│    INFRASTRUCTURE LAYER                  │
│  - Database (Repositories)               │
│  - External Services (Email, Payment)    │
│  - Config (Environment, Caching)         │
└──────────────────────────────────────────┘

Где Frontend в этой схеме

Frontend НЕ часть архитектуры backend.

Frontend это отдельное приложение, которое:

  1. Взаимодействует с backend через Port (Interface)
  2. Backend предоставляет Adapter (API endpoint) для Frontend
  3. Frontend -> HTTP/REST -> API Controller -> Application Layer
Frontend App         Backend App
(React/Vue)          (FastAPI/Django/Node)
    │                    │
    │ API Request        │
    ├───────────────────>│ Port (HTTP API)
    │                    │
    │  POST /api/users  │
    │  { name, email }  │
    │                    │
    │                    ├─> Adapter (Controller)
    │                    │   - Validate DTO
    │                    │   - Call Use Case
    │                    │   - Return Response
    │                    │
    │                    ├─> Application Layer
    │                    │   - CreateUserUseCase
    │                    │   - Validate business rules
    │                    │
    │                    ├─> Domain Layer
    │                    │   - User Entity
    │                    │   - Email Value Object
    │                    │
    │<───────────────────┤ Adapter (HTTP Response)
    │  { id, name ... }  │
    │                    │

Роли Front и Backend в гексагональной архитектуре

Backend (Hexagonal Architecture):

  1. Domain Layer — бизнес-логика

    • User entity
    • Validation rules
    • Business processes
  2. Application Layer — use cases

    • CreateUserUseCase
    • UpdateUserUseCase
    • DeleteUserUseCase
  3. Ports & Adapters — взаимодействие

    • HTTP Port -> REST API Adapter
    • WebSocket Port -> WebSocket Adapter
    • Database Port -> PostgreSQL Adapter
    • Email Port -> SMTP Adapter

Frontend (не часть backend архитектуры):

// Frontend структура (свои слои)

// UI Layer (Presentation)
function UserForm() {}

// Business Logic Layer
function useCreateUser() {}

// API Layer (Adapter to Backend)
const api = {
  createUser: (data) => fetch('/api/users', { method: 'POST', body: JSON.stringify(data) })
};

// Frontend НЕ должен повторять backend архитектуру
// Фронту нужна простая структура: Components -> Hooks -> API

Правильное взаимодействие

Backend API контракт (Port):

// backend/ports/http_api.py
class UserCreateRequest(BaseModel):
    name: str
    email: str
    
class UserResponse(BaseModel):
    id: UUID
    name: str
    email: str
    created_at: datetime

@app.post('/api/users')
class CreateUserController:
    def __init__(self, use_case: CreateUserUseCase):
        self.use_case = use_case
    
    def handle(self, request: UserCreateRequest) -> UserResponse:
        user = self.use_case.execute(request.name, request.email)
        return UserResponse.from_domain(user)

Frontend потребляет этот Port:

// frontend/api/users.ts
export const createUser = async (data: { name: string; email: string }) => {
  const response = await fetch('https://api.example.com/api/users', {
    method: 'POST',
    headers: { 'Content-Type': 'application/json' },
    body: JSON.stringify(data)
  });
  return response.json(); // UserResponse
};

// frontend/hooks/useCreateUser.ts
export function useCreateUser() {
  const [loading, setLoading] = useState(false);
  const [error, setError] = useState(null);
  
  const create = async (data) => {
    setLoading(true);
    try {
      const user = await createUser(data);
      return user;
    } catch (err) {
      setError(err);
    } finally {
      setLoading(false);
    }
  };
  
  return { create, loading, error };
}

// frontend/components/UserForm.tsx
export function UserForm() {
  const { create, loading, error } = useCreateUser();
  
  const handleSubmit = async (e) => {
    e.preventDefault();
    const user = await create({ name: 'John', email: 'john@example.com' });
  };
  
  return (
    <form onSubmit={handleSubmit}>
      <input type="text" placeholder="Name" />
      <input type="email" placeholder="Email" />
      <button disabled={loading}>Create</button>
      {error && <p>{error.message}</p>}
    </form>
  );
}

Несколько Ports/Adapters для одного Backend

Backend (Hexagonal)
    │
    ├─ HTTP Port ──> REST API Adapter ──> Frontend (React/Vue)
    ├─ HTTP Port ──> GraphQL Adapter ──> Mobile App (Apollo)
    ├─ WebSocket Port ──> WebSocket Adapter ──> Chat App
    ├─ CLI Port ──> CLI Adapter ──> Admin CLI Tool
    └─ Event Bus Port ──> Kafka Adapter ──> Microservices

// Один Domain Layer, много внешних интерфейсов!

Важные принципы

1. Зависимости должны указывать к центру

Frontend (External)
    │
    ├─ Зависит от API
    └─ НЕ должна зависеть от Domain Logic

// ПЛОХО — Frontend знает о Domain
const user = new User('John');
user.validate(); // Domain логика во Frontend!

// ХОРОШО — Frontend только UI + API
const response = await api.createUser({ name: 'John' });
const user = response.data;

2. Backend НЕ должен зависеть от Frontend

# ПЛОХО — Backend знает о Frontend структуре
class CreateUserResponse:
    def to_react_component(self):
        return { ... }

# ХОРОШО — Backend предоставляет Data, Frontend формирует UI
class CreateUserResponse:
    id: UUID
    name: str
    email: str

3. Frontend это Adapter к Domain

Frontend Role = Adapter
    ├─ Render Domain objects (Users, Posts, Comments)
    ├─ Collect User Input (Forms)
    ├─ Send Input to Application Layer (Use Cases)
    └─ Display Results (State Management)

Правила взаимодействия Frontend-Backend

Через HTTP Port:

// Frontend отправляет Request DTO
{
  "name": "John",
  "email": "john@example.com"
}

// Backend возвращает Response DTO
{
  "id": "abc-123",
  "name": "John",
  "email": "john@example.com",
  "created_at": "2025-04-02T10:00:00Z"
}

// Frontend преобразует в свою структуру
const user = {
  id: response.id,
  name: response.name,
  email: response.email,
  formattedDate: formatDate(response.created_at) // Frontend-specific
};

Вывод

Frontend в гексагональной архитектуре:

  1. НЕ часть внутренней архитектуры backend
  2. Является External Actor/Adapter
  3. Взаимодействует через HTTP Port (REST API)
  4. Потребляет API контракт (Request/Response DTOs)
  5. Не повторяет backend архитектуру (не нужны Domain entities в Frontend)

Фrontend = клиент, Backend = сервер. Гексагональная архитектура описывает внутреннее устройство сервера, а Frontend это просто один из адаптеров для взаимодействия с пользователем.

Где в гексагональной архитектуре размещается Frontend? | PrepBro