Files
sa-lessons/modules/module1/sections/05-architectural-styles-patterns.md
Alexander Abakumov fa40a5f1ff Расширены описания архитектурных стилей с подробными принципами и составом
- Добавлены подробные принципы работы для всех архитектурных стилей
- Расширен состав архитектуры с детальным описанием компонентов
- Добавлены технологические решения и конкретные инструменты
- Описаны паттерны интеграции и взаимодействия
- Улучшена структура подачи информации

Архитектурные стили:
- Монолитная архитектура: принципы единого процесса, совместного развертывания
- Микросервисная архитектура: декомпозиция, независимость, отказоустойчивость
- Event-Driven Architecture: события как первоклассные объекты, асинхронность
- CQRS: разделение команд и запросов, оптимизация моделей
- Hexagonal Architecture: изоляция бизнес-логики, порты и адаптеры
- Layered Architecture: разделение ответственности, направление зависимостей
- Serverless Architecture: FaaS, event-driven execution, stateless functions

Каждый стиль теперь содержит:
- Подробные принципы работы (4 основных принципа)
- Детальный состав архитектуры с компонентами
- Технологические решения и инструменты
- Паттерны интеграции и взаимодействия
- Практические аспекты реализации
2025-09-10 01:52:43 +03:00

89 KiB
Raw Permalink Blame History

Архитектурные стили и паттерны

Навигация


Монолитная архитектура

Определение

Монолитная архитектура — это архитектурный стиль, при котором все компоненты приложения объединены в единое развертываемое приложение. Это традиционный подход к разработке программного обеспечения, где все функциональные возможности реализованы в рамках одного процесса.

Принципы работы

1. Единый процесс

  • Все компоненты выполняются в рамках одного процесса операционной системы
  • Общая память и ресурсы для всех модулей
  • Простая отладка и профилирование

2. Совместное развертывание

  • Все изменения развертываются одновременно
  • Единый артефакт (JAR, WAR, EXE файл)
  • Простота управления версиями

3. Прямое взаимодействие

  • Компоненты вызывают друг друга через прямые ссылки
  • Нет сетевых задержек между модулями
  • Высокая производительность внутренних вызовов

4. Общие ресурсы

  • Единая база данных для всех модулей
  • Общие библиотеки и зависимости
  • Централизованное управление конфигурацией

Состав архитектуры

Структурные компоненты:

  1. Презентационный слой — пользовательский интерфейс (UI/API)
  2. Бизнес-логика — основная логика приложения
  3. Слой данных — работа с базой данных
  4. Общие утилиты — вспомогательные функции

Технические компоненты:

  • Веб-сервер — обработка HTTP-запросов
  • Контейнер приложения — управление жизненным циклом
  • ORM/DAO — работа с базой данных
  • Кэш — хранение часто используемых данных
  • Логирование — запись событий и ошибок

Инфраструктурные компоненты:

  • База данных — хранение данных
  • Файловая система — хранение файлов
  • Внешние API — интеграция с внешними сервисами
  • Мониторинг — отслеживание состояния приложения

Характеристики

  • Единое развертывание — все компоненты развертываются вместе
  • Общая база данных — все модули используют одну БД
  • Единый технологический стек — один язык, один фреймворк
  • Прямые вызовы — компоненты вызывают друг друга напрямую

Примеры реализации

🔧 Java (Spring Boot)
// Монолитное приложение e-commerce
@SpringBootApplication
public class EcommerceApplication {
    public static void main(String[] args) {
        SpringApplication.run(EcommerceApplication.class, args);
    }
}

// Все контроллеры в одном приложении
@RestController
@RequestMapping("/api")
public class EcommerceController {
    
    @Autowired
    private UserService userService;
    
    @Autowired
    private OrderService orderService;
    
    @Autowired
    private PaymentService paymentService;
    
    @PostMapping("/orders")
    public ResponseEntity<Order> createOrder(@RequestBody CreateOrderRequest request) {
        // Вся логика в одном месте
        User user = userService.findById(request.getUserId());
        Order order = orderService.createOrder(request);
        PaymentResult payment = paymentService.processPayment(order);
        return ResponseEntity.ok(order);
    }
}
🦀 Rust (Actix Web)
// Монолитное приложение e-commerce
use actix_web::{web, App, HttpServer, Result};
use serde::{Deserialize, Serialize};

#[derive(Serialize, Deserialize)]
pub struct CreateOrderRequest {
    pub user_id: u64,
    pub items: Vec<OrderItem>,
}

#[derive(Serialize, Deserialize)]
pub struct Order {
    pub id: u64,
    pub user_id: u64,
    pub status: String,
    pub total: f64,
}

// Все сервисы в одном приложении
async fn create_order(
    order_data: web::Json<CreateOrderRequest>,
    user_service: web::Data<UserService>,
    order_service: web::Data<OrderService>,
    payment_service: web::Data<PaymentService>,
) -> Result<web::Json<Order>> {
    // Вся логика в одном месте
    let user = user_service.find_by_id(order_data.user_id).await?;
    let order = order_service.create_order(order_data.into_inner()).await?;
    let _payment = payment_service.process_payment(&order).await?;
    
    Ok(web::Json(order))
}

#[actix_web::main]
async fn main() -> std::io::Result<()> {
    HttpServer::new(|| {
        App::new()
            .service(web::resource("/api/orders").route(web::post().to(create_order)))
    })
    .bind("127.0.0.1:8080")?
    .run()
    .await
}
🟨 JavaScript (Node.js)
// Монолитное приложение e-commerce
const express = require('express');
const app = express();

// Все сервисы в одном приложении
class EcommerceService {
    constructor() {
        this.userService = new UserService();
        this.orderService = new OrderService();
        this.paymentService = new PaymentService();
    }
    
    async createOrder(request) {
        // Вся логика в одном месте
        const user = await this.userService.findById(request.userId);
        const order = await this.orderService.createOrder(request);
        const payment = await this.paymentService.processPayment(order);
        return order;
    }
}

app.post('/api/orders', async (req, res) => {
    try {
        const ecommerceService = new EcommerceService();
        const order = await ecommerceService.createOrder(req.body);
        res.json(order);
    } catch (error) {
        res.status(500).json({ error: error.message });
    }
});

app.listen(3000, () => {
    console.log('Monolithic e-commerce app running on port 3000');
});
🐍 Python (FastAPI)
# Монолитное приложение e-commerce
from fastapi import FastAPI, HTTPException
from pydantic import BaseModel
from typing import List

app = FastAPI()

class CreateOrderRequest(BaseModel):
    user_id: int
    items: List[dict]

class Order(BaseModel):
    id: int
    user_id: int
    status: str
    total: float

# Все сервисы в одном приложении
class EcommerceService:
    def __init__(self):
        self.user_service = UserService()
        self.order_service = OrderService()
        self.payment_service = PaymentService()
    
    async def create_order(self, request: CreateOrderRequest) -> Order:
        # Вся логика в одном месте
        user = await self.user_service.find_by_id(request.user_id)
        order = await self.order_service.create_order(request)
        payment = await self.payment_service.process_payment(order)
        return order

@app.post("/api/orders")
async def create_order(request: CreateOrderRequest):
    try:
        ecommerce_service = EcommerceService()
        order = await ecommerce_service.create_order(request)
        return order
    except Exception as e:
        raise HTTPException(status_code=500, detail=str(e))

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

  • Простота разработки — легко начать проект
  • Простота тестирования — все в одном процессе
  • Простота развертывания — один артефакт
  • Производительность — нет сетевых вызовов

Недостатки

  • Сложность масштабирования — нужно масштабировать все приложение
  • Технологические ограничения — привязанность к одному стеку
  • Риск сбоев — падение одного компонента влияет на все
  • Сложность команд — команды работают над одним кодом

Микросервисная архитектура

Определение

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

Принципы работы

1. Декомпозиция по бизнес-функциям

  • Каждый сервис отвечает за одну бизнес-функцию
  • Сервисы организованы вокруг доменных границ
  • Минимизация связанности между сервисами

2. Независимость сервисов

  • Каждый сервис имеет собственный жизненный цикл
  • Независимое развертывание и масштабирование
  • Собственная база данных и технологии

3. Децентрализованное управление

  • Каждая команда отвечает за свои сервисы
  • Разные технологии и подходы к разработке
  • Децентрализованные данные и управление

4. Отказоустойчивость

  • Сервисы должны быть устойчивы к сбоям других сервисов
  • Circuit Breaker и retry механизмы
  • Graceful degradation при недоступности зависимостей

Состав архитектуры

Основные компоненты:

  1. Микросервисы — независимые сервисы с собственной логикой
  2. API Gateway — единая точка входа для клиентов
  3. Service Discovery — механизм поиска и регистрации сервисов
  4. Load Balancer — распределение нагрузки между экземплярами

Инфраструктурные компоненты:

  • Контейнерная платформа — Docker, Kubernetes
  • Оркестратор — управление жизненным циклом сервисов
  • Мониторинг — отслеживание состояния сервисов
  • Логирование — централизованный сбор логов

Паттерны взаимодействия:

  • Синхронное взаимодействие — REST, GraphQL, gRPC
  • Асинхронное взаимодействие — Message Queues, Event Streaming
  • Saga Pattern — управление распределенными транзакциями
  • CQRS — разделение команд и запросов

Качество и надежность:

  • Circuit Breaker — защита от каскадных сбоев
  • Bulkhead — изоляция ресурсов
  • Timeout — ограничение времени выполнения
  • Retry — повторные попытки при сбоях

Характеристики

  • Независимые сервисы — каждый сервис работает автономно
  • Отдельные базы данных — каждый сервис имеет свою БД
  • Разные технологии — сервисы могут использовать разные стеки
  • Сетевое взаимодействие — сервисы общаются по сети

Примеры реализации

🔧 Java (Spring Boot)
// User Service
@RestController
@RequestMapping("/api/users")
public class UserController {
    @Autowired
    private UserService userService;
    
    @GetMapping("/{id}")
    public ResponseEntity<User> getUser(@PathVariable Long id) {
        return ResponseEntity.ok(userService.findById(id));
    }
}

// Order Service
@RestController
@RequestMapping("/api/orders")
public class OrderController {
    @Autowired
    private OrderService orderService;
    
    @Autowired
    private UserServiceClient userServiceClient;
    
    @PostMapping
    public ResponseEntity<Order> createOrder(@RequestBody CreateOrderRequest request) {
        // Вызов внешнего сервиса
        User user = userServiceClient.getUser(request.getUserId());
        Order order = orderService.createOrder(request);
        return ResponseEntity.ok(order);
    }
}

// Payment Service
@RestController
@RequestMapping("/api/payments")
public class PaymentController {
    @Autowired
    private PaymentService paymentService;
    
    @PostMapping
    public ResponseEntity<PaymentResult> processPayment(@RequestBody PaymentRequest request) {
        PaymentResult result = paymentService.processPayment(request);
        return ResponseEntity.ok(result);
    }
}
🦀 Rust (Actix Web)
// User Service
use actix_web::{web, App, HttpServer, Result};
use serde::{Deserialize, Serialize};

#[derive(Serialize, Deserialize)]
pub struct User {
    pub id: u64,
    pub name: String,
    pub email: String,
}

// User Service
async fn get_user(path: web::Path<u64>) -> Result<web::Json<User>> {
    let user_id = path.into_inner();
    let user = user_service.find_by_id(user_id).await?;
    Ok(web::Json(user))
}

// Order Service
async fn create_order(
    order_data: web::Json<CreateOrderRequest>,
    user_client: web::Data<UserServiceClient>,
) -> Result<web::Json<Order>> {
    // Вызов внешнего сервиса
    let user = user_client.get_user(order_data.user_id).await?;
    let order = order_service.create_order(order_data.into_inner()).await?;
    Ok(web::Json(order))
}

// Payment Service
async fn process_payment(
    payment_data: web::Json<PaymentRequest>,
) -> Result<web::Json<PaymentResult>> {
    let result = payment_service.process_payment(payment_data.into_inner()).await?;
    Ok(web::Json(result))
}
🟨 JavaScript (Node.js)
// User Service
const express = require('express');
const app = express();

class UserService {
    async findById(id) {
        // Логика получения пользователя
        return { id, name: 'John Doe', email: 'john@example.com' };
    }
}

app.get('/api/users/:id', async (req, res) => {
    try {
        const userService = new UserService();
        const user = await userService.findById(req.params.id);
        res.json(user);
    } catch (error) {
        res.status(500).json({ error: error.message });
    }
});

// Order Service
class OrderService {
    constructor(userServiceClient) {
        this.userServiceClient = userServiceClient;
    }
    
    async createOrder(request) {
        // Вызов внешнего сервиса
        const user = await this.userServiceClient.getUser(request.userId);
        const order = { id: Date.now(), userId: user.id, status: 'created' };
        return order;
    }
}

app.post('/api/orders', async (req, res) => {
    try {
        const userServiceClient = new UserServiceClient();
        const orderService = new OrderService(userServiceClient);
        const order = await orderService.createOrder(req.body);
        res.json(order);
    } catch (error) {
        res.status(500).json({ error: error.message });
    }
});
🐍 Python (FastAPI)
# User Service
from fastapi import FastAPI, HTTPException
from pydantic import BaseModel

app = FastAPI()

class User(BaseModel):
    id: int
    name: str
    email: str

class UserService:
    async def find_by_id(self, user_id: int) -> User:
        # Логика получения пользователя
        return User(id=user_id, name="John Doe", email="john@example.com")

@app.get("/api/users/{user_id}")
async def get_user(user_id: int):
    try:
        user_service = UserService()
        user = await user_service.find_by_id(user_id)
        return user
    except Exception as e:
        raise HTTPException(status_code=500, detail=str(e))

# Order Service
class OrderService:
    def __init__(self, user_service_client):
        self.user_service_client = user_service_client
    
    async def create_order(self, request):
        # Вызов внешнего сервиса
        user = await self.user_service_client.get_user(request.user_id)
        order = {"id": 123, "user_id": user.id, "status": "created"}
        return order

@app.post("/api/orders")
async def create_order(request: CreateOrderRequest):
    try:
        user_service_client = UserServiceClient()
        order_service = OrderService(user_service_client)
        order = await order_service.create_order(request)
        return order
    except Exception as e:
        raise HTTPException(status_code=500, detail=str(e))

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

  • Независимое масштабирование — каждый сервис масштабируется отдельно
  • Технологическое разнообразие — разные технологии для разных задач
  • Независимые команды — команды работают над разными сервисами
  • Отказоустойчивость — падение одного сервиса не влияет на другие

Недостатки

  • Сложность разработки — нужно управлять множеством сервисов
  • Сетевая задержка — вызовы между сервисами медленнее
  • Сложность тестирования — нужно тестировать интеграции
  • Сложность развертывания — нужно координировать развертывание

Event-Driven Architecture (EDA)

Определение

Event-Driven Architecture — это архитектурный стиль, основанный на производстве, обнаружении, потреблении и реакции на события. Система реагирует на события, которые происходят в реальном времени, обеспечивая слабую связанность и высокую отзывчивость.

Принципы работы

1. События как первоклассные объекты

  • События представляют факты, которые произошли в системе
  • События неизменяемы и содержат всю необходимую информацию
  • События имеют временную метку и уникальный идентификатор

2. Асинхронная обработка

  • События обрабатываются асинхронно
  • Отправитель не ждет обработки события получателем
  • Высокая производительность и отзывчивость системы

3. Слабая связанность

  • Компоненты не знают друг о друге напрямую
  • Взаимодействие происходит только через события
  • Легкость изменения и расширения системы

4. Eventual Consistency

  • Система стремится к консистентности в конечном итоге
  • Временная несогласованность допустима
  • Компенсирующие действия для восстановления консистентности

Состав архитектуры

Основные компоненты:

  1. Event Producers — компоненты, генерирующие события
  2. Event Store — хранилище событий (Event Sourcing)
  3. Event Bus/Message Broker — транспорт для событий
  4. Event Consumers — компоненты, обрабатывающие события

Паттерны обработки событий:

  • Simple Event Processing — прямая обработка событий
  • Stream Processing — обработка потоков событий
  • Complex Event Processing — анализ сложных паттернов событий
  • Event Sourcing — хранение состояния как последовательности событий

Технологические компоненты:

  • Message Brokers — Apache Kafka, RabbitMQ, AWS SQS
  • Event Streaming — Apache Kafka Streams, Apache Pulsar
  • Event Store — EventStore, Apache Kafka
  • Processing Engines — Apache Storm, Apache Flink

Паттерны интеграции:

  • Event Notification — уведомление о произошедших событиях
  • Event-Carried State Transfer — передача состояния через события
  • Event Sourcing — восстановление состояния из событий
  • CQRS — разделение команд и запросов с событиями

Характеристики

  • События — значимые изменения в системе
  • Асинхронность — события обрабатываются асинхронно
  • Слабая связанность — компоненты не знают друг о друге
  • Масштабируемость — легко добавлять новых потребителей

Примеры реализации

🔧 Java (Spring Boot)
// Доменное событие
public class OrderCreatedEvent {
    private final String orderId;
    private final String customerId;
    private final BigDecimal amount;
    private final LocalDateTime occurredOn;
    
    public OrderCreatedEvent(String orderId, String customerId, BigDecimal amount) {
        this.orderId = orderId;
        this.customerId = customerId;
        this.amount = amount;
        this.occurredOn = LocalDateTime.now();
    }
    
    // Геттеры
}

// Публикация события
@Service
public class OrderService {
    
    @Autowired
    private ApplicationEventPublisher eventPublisher;
    
    public Order createOrder(CreateOrderRequest request) {
        Order order = new Order(request);
        order = orderRepository.save(order);
        
        // Публикация события
        eventPublisher.publishEvent(new OrderCreatedEvent(
            order.getId(),
            order.getCustomerId(),
            order.getAmount()
        ));
        
        return order;
    }
}

// Обработка события
@Component
public class OrderCreatedEventHandler {
    
    @Autowired
    private InventoryService inventoryService;
    
    @Autowired
    private NotificationService notificationService;
    
    @EventListener
    public void handleOrderCreated(OrderCreatedEvent event) {
        // Резервирование товара
        inventoryService.reserveItems(event.getOrderId());
        
        // Отправка уведомления
        notificationService.sendOrderConfirmation(event.getCustomerId());
    }
}
🦀 Rust (Actix Web + Tokio)
use serde::{Deserialize, Serialize};
use tokio::sync::mpsc;
use std::collections::HashMap;

// Доменное событие
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct OrderCreatedEvent {
    pub order_id: String,
    pub customer_id: String,
    pub amount: f64,
    pub occurred_on: chrono::DateTime<chrono::Utc>,
}

// Event Publisher
pub struct EventPublisher {
    sender: mpsc::UnboundedSender<OrderCreatedEvent>,
}

impl EventPublisher {
    pub fn new(sender: mpsc::UnboundedSender<OrderCreatedEvent>) -> Self {
        Self { sender }
    }
    
    pub fn publish_event(&self, event: OrderCreatedEvent) -> Result<(), String> {
        self.sender.send(event).map_err(|_| "Failed to send event".to_string())
    }
}

// Order Service
pub struct OrderService {
    event_publisher: EventPublisher,
}

impl OrderService {
    pub async fn create_order(&self, request: CreateOrderRequest) -> Result<Order, String> {
        let order = Order::new(request);
        // Сохранение заказа
        
        // Публикация события
        let event = OrderCreatedEvent {
            order_id: order.id.clone(),
            customer_id: order.customer_id.clone(),
            amount: order.amount,
            occurred_on: chrono::Utc::now(),
        };
        
        self.event_publisher.publish_event(event)?;
        Ok(order)
    }
}

// Event Handler
pub struct OrderCreatedEventHandler {
    inventory_service: InventoryService,
    notification_service: NotificationService,
}

impl OrderCreatedEventHandler {
    pub async fn handle_order_created(&self, event: OrderCreatedEvent) {
        // Резервирование товара
        self.inventory_service.reserve_items(&event.order_id).await;
        
        // Отправка уведомления
        self.notification_service.send_order_confirmation(&event.customer_id).await;
    }
}
🟨 JavaScript (Node.js + EventEmitter)
const EventEmitter = require('events');

// Доменное событие
class OrderCreatedEvent {
    constructor(orderId, customerId, amount) {
        this.orderId = orderId;
        this.customerId = customerId;
        this.amount = amount;
        this.occurredOn = new Date();
    }
}

// Event Publisher
class EventPublisher extends EventEmitter {
    publishEvent(event) {
        this.emit('orderCreated', event);
    }
}

// Order Service
class OrderService {
    constructor(eventPublisher) {
        this.eventPublisher = eventPublisher;
    }
    
    async createOrder(request) {
        const order = new Order(request);
        // Сохранение заказа
        
        // Публикация события
        const event = new OrderCreatedEvent(
            order.id,
            order.customerId,
            order.amount
        );
        
        this.eventPublisher.publishEvent(event);
        return order;
    }
}

// Event Handler
class OrderCreatedEventHandler {
    constructor(inventoryService, notificationService) {
        this.inventoryService = inventoryService;
        this.notificationService = notificationService;
    }
    
    handleOrderCreated(event) {
        // Резервирование товара
        this.inventoryService.reserveItems(event.orderId);
        
        // Отправка уведомления
        this.notificationService.sendOrderConfirmation(event.customerId);
    }
}

// Настройка обработчиков
const eventPublisher = new EventPublisher();
const orderService = new OrderService(eventPublisher);
const eventHandler = new OrderCreatedEventHandler(
    new InventoryService(),
    new NotificationService()
);

eventPublisher.on('orderCreated', (event) => {
    eventHandler.handleOrderCreated(event);
});
🐍 Python (FastAPI + asyncio)
import asyncio
from datetime import datetime
from typing import Dict, Any
from dataclasses import dataclass

# Доменное событие
@dataclass
class OrderCreatedEvent:
    order_id: str
    customer_id: str
    amount: float
    occurred_on: datetime

# Event Publisher
class EventPublisher:
    def __init__(self):
        self._handlers = []
    
    def subscribe(self, handler):
        self._handlers.append(handler)
    
    async def publish_event(self, event: OrderCreatedEvent):
        for handler in self._handlers:
            await handler(event)

# Order Service
class OrderService:
    def __init__(self, event_publisher: EventPublisher):
        self.event_publisher = event_publisher
    
    async def create_order(self, request):
        order = Order(request)
        # Сохранение заказа
        
        # Публикация события
        event = OrderCreatedEvent(
            order_id=order.id,
            customer_id=order.customer_id,
            amount=order.amount,
            occurred_on=datetime.now()
        )
        
        await self.event_publisher.publish_event(event)
        return order

# Event Handler
class OrderCreatedEventHandler:
    def __init__(self, inventory_service, notification_service):
        self.inventory_service = inventory_service
        self.notification_service = notification_service
    
    async def __call__(self, event: OrderCreatedEvent):
        # Резервирование товара
        await self.inventory_service.reserve_items(event.order_id)
        
        # Отправка уведомления
        await self.notification_service.send_order_confirmation(event.customer_id)

# Настройка
event_publisher = EventPublisher()
order_service = OrderService(event_publisher)
event_handler = OrderCreatedEventHandler(
    InventoryService(),
    NotificationService()
)

event_publisher.subscribe(event_handler)

CQRS (Command Query Responsibility Segregation)

Определение

CQRS — это паттерн, который разделяет операции чтения и записи данных на разные модели. Это позволяет оптимизировать каждую сторону независимо, обеспечивая лучшую производительность и масштабируемость.

Принципы работы

1. Разделение ответственности

  • Commands — операции изменения состояния (Create, Update, Delete)
  • Queries — операции чтения данных (Read, Search, Report)
  • Разные модели для разных операций
  • Специализированные обработчики для каждого типа

2. Оптимизация моделей

  • Write Model — нормализованная структура для консистентности
  • Read Model — денормализованная структура для производительности
  • Разные схемы баз данных для чтения и записи
  • Специализированные индексы и структуры данных

3. Асинхронная синхронизация

  • Изменения в Write Model асинхронно синхронизируются с Read Model
  • Event-driven обновление Read Model
  • Eventual consistency между моделями
  • Компенсирующие действия при сбоях синхронизации

4. Независимое масштабирование

  • Write и Read стороны масштабируются независимо
  • Разные технологии для разных задач
  • Оптимизация ресурсов под конкретные нагрузки
  • Горизонтальное масштабирование каждой стороны

Состав архитектуры

Основные компоненты:

  1. Command Side — обработка команд изменения данных
  2. Query Side — обработка запросов чтения данных
  3. Event Bus — синхронизация между сторонами
  4. Projection Handlers — обновление Read Model

Command Side компоненты:

  • Command Handlers — обработчики команд
  • Domain Models — бизнес-логика и валидация
  • Write Database — основное хранилище данных
  • Event Store — хранение событий изменений

Query Side компоненты:

  • Query Handlers — обработчики запросов
  • Read Models — оптимизированные модели для чтения
  • Read Database — специализированные хранилища
  • Caching Layer — кэширование часто запрашиваемых данных

Синхронизация:

  • Event Publishers — публикация событий изменений
  • Event Subscribers — подписка на события
  • Projection Services — обновление Read Model
  • Reconciliation — восстановление консистентности

Технологические решения:

  • Message Brokers — Apache Kafka, RabbitMQ для событий
  • Databases — PostgreSQL для Write, MongoDB для Read
  • Caching — Redis для кэширования Read Model
  • Search Engines — Elasticsearch для сложных запросов

Характеристики

  • Разделение команд и запросов — разные модели для записи и чтения
  • Оптимизация — модели оптимизированы для своих задач
  • Масштабируемость — можно масштабировать чтение и запись отдельно
  • Сложность — увеличивает сложность системы

Примеры реализации

🔧 Java (Spring Boot)
// Command Model (Write)
@Entity
@Table(name = "orders")
public class Order {
    @Id
    private String id;
    private String customerId;
    private OrderStatus status;
    private BigDecimal amount;
    private LocalDateTime createdAt;
    
    // Методы для изменения состояния
    public void confirm() {
        this.status = OrderStatus.CONFIRMED;
    }
    
    public void cancel() {
        this.status = OrderStatus.CANCELLED;
    }
}

// Query Model (Read)
@Entity
@Table(name = "order_summaries")
public class OrderSummary {
    @Id
    private String id;
    private String customerName;
    private String customerEmail;
    private OrderStatus status;
    private BigDecimal amount;
    private LocalDateTime createdAt;
    private int itemCount;
    
    // Только геттеры для чтения
}

// Command Handler
@Service
public class OrderCommandHandler {
    
    @Autowired
    private OrderRepository orderRepository;
    
    @Autowired
    private OrderSummaryRepository orderSummaryRepository;
    
    public void handle(CreateOrderCommand command) {
        // Создание заказа
        Order order = new Order(command);
        orderRepository.save(order);
        
        // Обновление read model
        OrderSummary summary = new OrderSummary(order);
        orderSummaryRepository.save(summary);
    }
}

// Query Handler
@Service
public class OrderQueryHandler {
    
    @Autowired
    private OrderSummaryRepository orderSummaryRepository;
    
    public List<OrderSummary> handle(GetOrdersQuery query) {
        return orderSummaryRepository.findByCustomerId(query.getCustomerId());
    }
}
🦀 Rust (Actix Web + Diesel)
use diesel::prelude::*;
use serde::{Deserialize, Serialize};

// Command Model (Write)
#[derive(Insertable, Queryable, Serialize, Deserialize)]
#[table_name = "orders"]
pub struct Order {
    pub id: String,
    pub customer_id: String,
    pub status: String,
    pub amount: f64,
    pub created_at: chrono::DateTime<chrono::Utc>,
}

impl Order {
    pub fn confirm(&mut self) {
        self.status = "CONFIRMED".to_string();
    }
    
    pub fn cancel(&mut self) {
        self.status = "CANCELLED".to_string();
    }
}

// Query Model (Read)
#[derive(Queryable, Serialize, Deserialize)]
#[table_name = "order_summaries"]
pub struct OrderSummary {
    pub id: String,
    pub customer_name: String,
    pub customer_email: String,
    pub status: String,
    pub amount: f64,
    pub created_at: chrono::DateTime<chrono::Utc>,
    pub item_count: i32,
}

// Command Handler
pub struct OrderCommandHandler {
    order_repository: OrderRepository,
    order_summary_repository: OrderSummaryRepository,
}

impl OrderCommandHandler {
    pub async fn handle(&self, command: CreateOrderCommand) -> Result<(), String> {
        // Создание заказа
        let order = Order::new(command);
        self.order_repository.save(order.clone()).await?;
        
        // Обновление read model
        let summary = OrderSummary::from_order(order);
        self.order_summary_repository.save(summary).await?;
        
        Ok(())
    }
}

// Query Handler
pub struct OrderQueryHandler {
    order_summary_repository: OrderSummaryRepository,
}

impl OrderQueryHandler {
    pub async fn handle(&self, query: GetOrdersQuery) -> Result<Vec<OrderSummary>, String> {
        self.order_summary_repository.find_by_customer_id(&query.customer_id).await
    }
}
🟨 JavaScript (Node.js + MongoDB)
// Command Model (Write)
class Order {
    constructor(data) {
        this.id = data.id;
        this.customerId = data.customerId;
        this.status = data.status;
        this.amount = data.amount;
        this.createdAt = new Date();
    }
    
    confirm() {
        this.status = 'CONFIRMED';
    }
    
    cancel() {
        this.status = 'CANCELLED';
    }
}

// Query Model (Read)
class OrderSummary {
    constructor(order) {
        this.id = order.id;
        this.customerName = order.customerName;
        this.customerEmail = order.customerEmail;
        this.status = order.status;
        this.amount = order.amount;
        this.createdAt = order.createdAt;
        this.itemCount = order.items.length;
    }
}

// Command Handler
class OrderCommandHandler {
    constructor(orderRepository, orderSummaryRepository) {
        this.orderRepository = orderRepository;
        this.orderSummaryRepository = orderSummaryRepository;
    }
    
    async handle(command) {
        // Создание заказа
        const order = new Order(command);
        await this.orderRepository.save(order);
        
        // Обновление read model
        const summary = new OrderSummary(order);
        await this.orderSummaryRepository.save(summary);
    }
}

// Query Handler
class OrderQueryHandler {
    constructor(orderSummaryRepository) {
        this.orderSummaryRepository = orderSummaryRepository;
    }
    
    async handle(query) {
        return await this.orderSummaryRepository.findByCustomerId(query.customerId);
    }
}
🐍 Python (FastAPI + SQLAlchemy)
from sqlalchemy import Column, String, Float, DateTime, Integer
from sqlalchemy.ext.declarative import declarative_base
from datetime import datetime

Base = declarative_base()

# Command Model (Write)
class Order(Base):
    __tablename__ = "orders"
    
    id = Column(String, primary_key=True)
    customer_id = Column(String, nullable=False)
    status = Column(String, nullable=False)
    amount = Column(Float, nullable=False)
    created_at = Column(DateTime, default=datetime.utcnow)
    
    def confirm(self):
        self.status = "CONFIRMED"
    
    def cancel(self):
        self.status = "CANCELLED"

# Query Model (Read)
class OrderSummary(Base):
    __tablename__ = "order_summaries"
    
    id = Column(String, primary_key=True)
    customer_name = Column(String, nullable=False)
    customer_email = Column(String, nullable=False)
    status = Column(String, nullable=False)
    amount = Column(Float, nullable=False)
    created_at = Column(DateTime, nullable=False)
    item_count = Column(Integer, nullable=False)

# Command Handler
class OrderCommandHandler:
    def __init__(self, order_repository, order_summary_repository):
        self.order_repository = order_repository
        self.order_summary_repository = order_summary_repository
    
    async def handle(self, command):
        # Создание заказа
        order = Order(command)
        await self.order_repository.save(order)
        
        # Обновление read model
        summary = OrderSummary.from_order(order)
        await self.order_summary_repository.save(summary)

# Query Handler
class OrderQueryHandler:
    def __init__(self, order_summary_repository):
        self.order_summary_repository = order_summary_repository
    
    async def handle(self, query):
        return await self.order_summary_repository.find_by_customer_id(query.customer_id)

Hexagonal Architecture (Ports and Adapters)

Определение

Hexagonal Architecture — это архитектурный паттерн, который изолирует бизнес-логику от внешних зависимостей. Также известен как "Ports and Adapters" или "Clean Architecture", он обеспечивает независимость бизнес-логики от внешних технологий и инфраструктуры.

Принципы работы

1. Изоляция бизнес-логики

  • Бизнес-логика находится в центре архитектуры
  • Не зависит от внешних технологий и фреймворков
  • Чистые доменные модели без внешних зависимостей
  • Легкость тестирования и изменения

2. Порты и адаптеры

  • Порты — интерфейсы, определяющие контракты взаимодействия
  • Адаптеры — реализации портов для конкретных технологий
  • Инверсия зависимостей — бизнес-логика определяет интерфейсы
  • Внешние компоненты реализуют эти интерфейсы

3. Направление зависимостей

  • Зависимости направлены внутрь, к бизнес-логике
  • Внешние слои зависят от внутренних
  • Бизнес-логика не знает о внешних технологиях
  • Легкость замены внешних компонентов

4. Тестируемость

  • Бизнес-логика тестируется изолированно
  • Mock-объекты для внешних зависимостей
  • Unit-тесты без внешних ресурсов
  • Интеграционные тесты с реальными адаптерами

Состав архитектуры

Структурные слои:

  1. Domain Layer — бизнес-логика и доменные модели
  2. Application Layer — координация бизнес-операций
  3. Infrastructure Layer — внешние зависимости и технологии
  4. Presentation Layer — пользовательский интерфейс

Domain Layer компоненты:

  • Entities — основные бизнес-объекты
  • Value Objects — неизменяемые объекты
  • Domain Services — бизнес-логика, не принадлежащая сущностям
  • Domain Events — события домена
  • Repositories (Ports) — интерфейсы для работы с данными

Application Layer компоненты:

  • Use Cases — координация бизнес-операций
  • Application Services — оркестрация доменных объектов
  • Command/Query Handlers — обработка команд и запросов
  • Ports — интерфейсы для внешних сервисов

Infrastructure Layer компоненты:

  • Repository Implementations — реализация репозиториев
  • External Service Adapters — адаптеры для внешних API
  • Database Adapters — работа с базами данных
  • Message Queue Adapters — работа с очередями сообщений

Presentation Layer компоненты:

  • Controllers — обработка HTTP-запросов
  • View Models — модели представления
  • API Adapters — адаптеры для внешних API
  • UI Components — компоненты пользовательского интерфейса

Паттерны интеграции:

  • Dependency Injection — внедрение зависимостей
  • Factory Pattern — создание объектов
  • Observer Pattern — обработка событий
  • Strategy Pattern — выбор алгоритмов

Характеристики

  • Порты — интерфейсы для взаимодействия с внешним миром
  • Адаптеры — реализации портов для конкретных технологий
  • Изоляция — бизнес-логика не зависит от внешних технологий
  • Тестируемость — легко тестировать с mock-объектами

Примеры реализации

🔧 Java (Spring Boot)
// Domain Layer (внутренний круг)
public class Order {
    private String id;
    private String customerId;
    private OrderStatus status;
    private BigDecimal amount;
    
    public void confirm() {
        this.status = OrderStatus.CONFIRMED;
    }
}

// Ports (интерфейсы)
public interface OrderRepository {
    void save(Order order);
    Optional<Order> findById(String id);
}

public interface PaymentService {
    PaymentResult processPayment(PaymentRequest request);
}

public interface NotificationService {
    void sendNotification(String recipient, String message);
}

// Application Layer
@Service
public class OrderService {
    private final OrderRepository orderRepository;
    private final PaymentService paymentService;
    private final NotificationService notificationService;
    
    public OrderService(OrderRepository orderRepository,
                       PaymentService paymentService,
                       NotificationService notificationService) {
        this.orderRepository = orderRepository;
        this.paymentService = paymentService;
        this.notificationService = notificationService;
    }
    
    public void processOrder(Order order) {
        // Бизнес-логика
        order.confirm();
        orderRepository.save(order);
        
        // Внешние сервисы через порты
        PaymentResult payment = paymentService.processPayment(
            new PaymentRequest(order.getAmount())
        );
        
        if (payment.isSuccess()) {
            notificationService.sendNotification(
                order.getCustomerId(),
                "Order confirmed"
            );
        }
    }
}

// Adapters (внешний круг)
@Repository
public class JpaOrderRepository implements OrderRepository {
    @Override
    public void save(Order order) {
        // JPA реализация
    }
    
    @Override
    public Optional<Order> findById(String id) {
        // JPA реализация
        return Optional.empty();
    }
}

@Component
public class StripePaymentService implements PaymentService {
    @Override
    public PaymentResult processPayment(PaymentRequest request) {
        // Stripe API реализация
        return new PaymentResult(true, "Payment processed");
    }
}

@Component
public class EmailNotificationService implements NotificationService {
    @Override
    public void sendNotification(String recipient, String message) {
        // Email реализация
    }
}
🦀 Rust (Actix Web + Dependency Injection)
use std::sync::Arc;
use async_trait::async_trait;

// Domain Layer (внутренний круг)
#[derive(Debug, Clone)]
pub struct Order {
    pub id: String,
    pub customer_id: String,
    pub status: String,
    pub amount: f64,
}

impl Order {
    pub fn confirm(&mut self) {
        self.status = "CONFIRMED".to_string();
    }
}

// Ports (интерфейсы)
#[async_trait]
pub trait OrderRepository: Send + Sync {
    async fn save(&self, order: &Order) -> Result<(), String>;
    async fn find_by_id(&self, id: &str) -> Result<Option<Order>, String>;
}

#[async_trait]
pub trait PaymentService: Send + Sync {
    async fn process_payment(&self, request: PaymentRequest) -> Result<PaymentResult, String>;
}

#[async_trait]
pub trait NotificationService: Send + Sync {
    async fn send_notification(&self, recipient: &str, message: &str) -> Result<(), String>;
}

// Application Layer
pub struct OrderService {
    order_repository: Arc<dyn OrderRepository>,
    payment_service: Arc<dyn PaymentService>,
    notification_service: Arc<dyn NotificationService>,
}

impl OrderService {
    pub fn new(
        order_repository: Arc<dyn OrderRepository>,
        payment_service: Arc<dyn PaymentService>,
        notification_service: Arc<dyn NotificationService>,
    ) -> Self {
        Self {
            order_repository,
            payment_service,
            notification_service,
        }
    }
    
    pub async fn process_order(&self, mut order: Order) -> Result<(), String> {
        // Бизнес-логика
        order.confirm();
        self.order_repository.save(&order).await?;
        
        // Внешние сервисы через порты
        let payment = self.payment_service.process_payment(
            PaymentRequest::new(order.amount)
        ).await?;
        
        if payment.is_success {
            self.notification_service.send_notification(
                &order.customer_id,
                "Order confirmed"
            ).await?;
        }
        
        Ok(())
    }
}

// Adapters (внешний круг)
pub struct PostgresOrderRepository {
    pool: sqlx::PgPool,
}

#[async_trait]
impl OrderRepository for PostgresOrderRepository {
    async fn save(&self, order: &Order) -> Result<(), String> {
        sqlx::query!(
            "INSERT INTO orders (id, customer_id, status, amount) VALUES ($1, $2, $3, $4)",
            order.id, order.customer_id, order.status, order.amount
        )
        .execute(&self.pool)
        .await
        .map_err(|e| e.to_string())?;
        Ok(())
    }
    
    async fn find_by_id(&self, id: &str) -> Result<Option<Order>, String> {
        let row = sqlx::query!(
            "SELECT id, customer_id, status, amount FROM orders WHERE id = $1",
            id
        )
        .fetch_optional(&self.pool)
        .await
        .map_err(|e| e.to_string())?;
        
        Ok(row.map(|r| Order {
            id: r.id,
            customer_id: r.customer_id,
            status: r.status,
            amount: r.amount,
        }))
    }
}
🟨 JavaScript (Node.js + Dependency Injection)
// Domain Layer (внутренний круг)
class Order {
    constructor(data) {
        this.id = data.id;
        this.customerId = data.customerId;
        this.status = data.status;
        this.amount = data.amount;
    }
    
    confirm() {
        this.status = 'CONFIRMED';
    }
}

// Ports (интерфейсы)
class OrderRepository {
    async save(order) {
        throw new Error('Not implemented');
    }
    
    async findById(id) {
        throw new Error('Not implemented');
    }
}

class PaymentService {
    async processPayment(request) {
        throw new Error('Not implemented');
    }
}

class NotificationService {
    async sendNotification(recipient, message) {
        throw new Error('Not implemented');
    }
}

// Application Layer
class OrderService {
    constructor(orderRepository, paymentService, notificationService) {
        this.orderRepository = orderRepository;
        this.paymentService = paymentService;
        this.notificationService = notificationService;
    }
    
    async processOrder(order) {
        // Бизнес-логика
        order.confirm();
        await this.orderRepository.save(order);
        
        // Внешние сервисы через порты
        const payment = await this.paymentService.processPayment({
            amount: order.amount
        });
        
        if (payment.isSuccess) {
            await this.notificationService.sendNotification(
                order.customerId,
                'Order confirmed'
            );
        }
    }
}

// Adapters (внешний круг)
class MongoOrderRepository extends OrderRepository {
    constructor(mongoClient) {
        super();
        this.mongoClient = mongoClient;
    }
    
    async save(order) {
        const db = this.mongoClient.db('ecommerce');
        await db.collection('orders').replaceOne(
            { id: order.id },
            order,
            { upsert: true }
        );
    }
    
    async findById(id) {
        const db = this.mongoClient.db('ecommerce');
        const order = await db.collection('orders').findOne({ id });
        return order ? new Order(order) : null;
    }
}

class StripePaymentService extends PaymentService {
    constructor(stripeClient) {
        super();
        this.stripeClient = stripeClient;
    }
    
    async processPayment(request) {
        // Интеграция со Stripe
        const paymentIntent = await this.stripeClient.paymentIntents.create({
            amount: request.amount * 100,
            currency: 'usd',
        });
        
        return {
            isSuccess: paymentIntent.status === 'succeeded',
            message: 'Payment successful'
        };
    }
}

class EmailNotificationService extends NotificationService {
    constructor(emailClient) {
        super();
        this.emailClient = emailClient;
    }
    
    async sendNotification(recipient, message) {
        await this.emailClient.send({
            to: recipient,
            subject: 'Order Update',
            text: message
        });
    }
}
🐍 Python (FastAPI + Dependency Injection)
from abc import ABC, abstractmethod
from typing import Optional
from dataclasses import dataclass

# Domain Layer (внутренний круг)
@dataclass
class Order:
    id: str
    customer_id: str
    status: str
    amount: float
    
    def confirm(self):
        self.status = "CONFIRMED"

# Ports (интерфейсы)
class OrderRepository(ABC):
    @abstractmethod
    async def save(self, order: Order) -> None:
        pass
    
    @abstractmethod
    async def find_by_id(self, order_id: str) -> Optional[Order]:
        pass

class PaymentService(ABC):
    @abstractmethod
    async def process_payment(self, request: PaymentRequest) -> PaymentResult:
        pass

class NotificationService(ABC):
    @abstractmethod
    async def send_notification(self, recipient: str, message: str) -> None:
        pass

# Application Layer
class OrderService:
    def __init__(
        self,
        order_repository: OrderRepository,
        payment_service: PaymentService,
        notification_service: NotificationService
    ):
        self.order_repository = order_repository
        self.payment_service = payment_service
        self.notification_service = notification_service
    
    async def process_order(self, order: Order) -> None:
        # Бизнес-логика
        order.confirm()
        await self.order_repository.save(order)
        
        # Внешние сервисы через порты
        payment = await self.payment_service.process_payment(
            PaymentRequest(amount=order.amount)
        )
        
        if payment.is_success:
            await self.notification_service.send_notification(
                order.customer_id,
                "Order confirmed"
            )

# Adapters (внешний круг)
class PostgresOrderRepository(OrderRepository):
    def __init__(self, db_pool):
        self.db_pool = db_pool
    
    async def save(self, order: Order) -> None:
        async with self.db_pool.acquire() as conn:
            await conn.execute(
                "INSERT INTO orders (id, customer_id, status, amount) VALUES ($1, $2, $3, $4) "
                "ON CONFLICT (id) DO UPDATE SET customer_id = $2, status = $3, amount = $4",
                order.id, order.customer_id, order.status, order.amount
            )
    
    async def find_by_id(self, order_id: str) -> Optional[Order]:
        async with self.db_pool.acquire() as conn:
            row = await conn.fetchrow(
                "SELECT id, customer_id, status, amount FROM orders WHERE id = $1",
                order_id
            )
            if row:
                return Order(
                    id=row['id'],
                    customer_id=row['customer_id'],
                    status=row['status'],
                    amount=row['amount']
                )
            return None

class StripePaymentService(PaymentService):
    def __init__(self, stripe_client):
        self.stripe_client = stripe_client
    
    async def process_payment(self, request: PaymentRequest) -> PaymentResult:
        # Интеграция со Stripe
        payment_intent = await self.stripe_client.payment_intents.create(
            amount=int(request.amount * 100),
            currency='usd'
        )
        
        return PaymentResult(
            is_success=payment_intent.status == 'succeeded',
            message='Payment successful'
        )

class EmailNotificationService(NotificationService):
    def __init__(self, email_client):
        self.email_client = email_client
    
    async def send_notification(self, recipient: str, message: str) -> None:
        await self.email_client.send_email(
            to=recipient,
            subject='Order Update',
            body=message
        )

Layered Architecture

Определение

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

Принципы работы

1. Разделение ответственности

  • Каждый слой имеет четко определенную ответственность
  • Слои изолированы друг от друга
  • Изменения в одном слое не влияют на другие
  • Легкость понимания и поддержки кода

2. Направление зависимостей

  • Зависимости направлены вниз (к более низким слоям)
  • Высокие слои зависят от низких
  • Низкие слои не знают о высоких
  • Инверсия зависимостей через интерфейсы

3. Инкапсуляция

  • Детали реализации скрыты внутри слоя
  • Внешние слои взаимодействуют через интерфейсы
  • Изменения в реализации не влияют на клиентов
  • Легкость замены компонентов

4. Повторное использование

  • Низкие слои могут использоваться разными высокими слоями
  • Общая функциональность выносится в отдельные слои
  • Компоненты могут быть переиспользованы
  • Модульность и расширяемость

Состав архитектуры

Основные слои:

1. Presentation Layer (Слой представления)
  • Ответственность: Пользовательский интерфейс и взаимодействие
  • Компоненты: Controllers, Views, API endpoints, UI components
  • Технологии: REST controllers, GraphQL resolvers, Web UI
  • Взаимодействие: Получает запросы от пользователей, делегирует обработку Application Layer
2. Application Layer (Слой приложения)
  • Ответственность: Координация бизнес-операций и оркестрация
  • Компоненты: Application Services, Use Cases, Command/Query Handlers
  • Технологии: Service classes, Transaction management
  • Взаимодействие: Координирует работу Domain Layer, управляет транзакциями
3. Domain Layer (Доменный слой)
  • Ответственность: Бизнес-логика и доменные правила
  • Компоненты: Entities, Value Objects, Domain Services, Business Rules
  • Технологии: Domain models, Business logic
  • Взаимодействие: Содержит основную бизнес-логику, не зависит от внешних слоев
4. Infrastructure Layer (Инфраструктурный слой)
  • Ответственность: Внешние зависимости и техническая реализация
  • Компоненты: Repositories, External APIs, Database, File System
  • Технологии: ORM, HTTP clients, Database drivers
  • Взаимодействие: Реализует интерфейсы, определенные в Domain Layer

Дополнительные слои:

Cross-Cutting Concerns (Сквозные аспекты)
  • Логирование — запись событий и ошибок
  • Безопасность — аутентификация и авторизация
  • Кэширование — хранение часто используемых данных
  • Мониторинг — отслеживание производительности
Integration Layer (Слой интеграции)
  • Внешние API — интеграция с внешними сервисами
  • Message Queues — асинхронная обработка сообщений
  • Event Handlers — обработка внешних событий
  • Data Transformation — преобразование данных между системами

Слои

  1. Presentation Layer — пользовательский интерфейс
  2. Application Layer — бизнес-логика приложения
  3. Domain Layer — доменная логика
  4. Infrastructure Layer — внешние зависимости

Примеры реализации

🔧 Java (Spring Boot)
// Presentation Layer
@RestController
@RequestMapping("/api/orders")
public class OrderController {
    
    @Autowired
    private OrderApplicationService orderService;
    
    @PostMapping
    public ResponseEntity<OrderResponse> createOrder(@RequestBody CreateOrderRequest request) {
        OrderResponse response = orderService.createOrder(request);
        return ResponseEntity.ok(response);
    }
}

// Application Layer
@Service
public class OrderApplicationService {
    
    @Autowired
    private OrderRepository orderRepository;
    
    @Autowired
    private PaymentService paymentService;
    
    public OrderResponse createOrder(CreateOrderRequest request) {
        // Применение бизнес-правил
        Order order = new Order(request);
        
        // Обработка платежа
        PaymentResult payment = paymentService.processPayment(order);
        
        if (payment.isSuccess()) {
            order.confirm();
            orderRepository.save(order);
        }
        
        return OrderResponse.fromOrder(order);
    }
}

// Domain Layer
public class Order {
    private String id;
    private String customerId;
    private OrderStatus status;
    private BigDecimal amount;
    
    public void confirm() {
        if (this.status != OrderStatus.DRAFT) {
            throw new IllegalStateException("Cannot confirm non-draft order");
        }
        this.status = OrderStatus.CONFIRMED;
    }
}

// Infrastructure Layer
@Repository
public class JpaOrderRepository implements OrderRepository {
    
    @PersistenceContext
    private EntityManager entityManager;
    
    @Override
    public void save(Order order) {
        entityManager.persist(order);
    }
}
🦀 Rust (Actix Web + Layered Structure)
use actix_web::{web, App, HttpServer, Result};
use serde::{Deserialize, Serialize};

// Presentation Layer
#[derive(Deserialize)]
pub struct CreateOrderRequest {
    pub customer_id: String,
    pub amount: f64,
}

#[derive(Serialize)]
pub struct OrderResponse {
    pub id: String,
    pub status: String,
    pub amount: f64,
}

async fn create_order(
    request: web::Json<CreateOrderRequest>,
    order_service: web::Data<OrderApplicationService>,
) -> Result<web::Json<OrderResponse>> {
    let response = order_service.create_order(request.into_inner()).await?;
    Ok(web::Json(response))
}

// Application Layer
pub struct OrderApplicationService {
    order_repository: Arc<dyn OrderRepository>,
    payment_service: Arc<dyn PaymentService>,
}

impl OrderApplicationService {
    pub async fn create_order(&self, request: CreateOrderRequest) -> Result<OrderResponse, String> {
        // Применение бизнес-правил
        let mut order = Order::new(request);
        
        // Обработка платежа
        let payment = self.payment_service.process_payment(&order).await?;
        
        if payment.is_success {
            order.confirm();
            self.order_repository.save(&order).await?;
        }
        
        Ok(OrderResponse::from(order))
    }
}

// Domain Layer
#[derive(Debug, Clone)]
pub struct Order {
    pub id: String,
    pub customer_id: String,
    pub status: String,
    pub amount: f64,
}

impl Order {
    pub fn new(request: CreateOrderRequest) -> Self {
        Self {
            id: uuid::Uuid::new_v4().to_string(),
            customer_id: request.customer_id,
            status: "DRAFT".to_string(),
            amount: request.amount,
        }
    }
    
    pub fn confirm(&mut self) {
        if self.status != "DRAFT" {
            panic!("Cannot confirm non-draft order");
        }
        self.status = "CONFIRMED".to_string();
    }
}

// Infrastructure Layer
pub struct PostgresOrderRepository {
    pool: sqlx::PgPool,
}

#[async_trait]
impl OrderRepository for PostgresOrderRepository {
    async fn save(&self, order: &Order) -> Result<(), String> {
        sqlx::query!(
            "INSERT INTO orders (id, customer_id, status, amount) VALUES ($1, $2, $3, $4)",
            order.id, order.customer_id, order.status, order.amount
        )
        .execute(&self.pool)
        .await
        .map_err(|e| e.to_string())?;
        Ok(())
    }
}
🟨 JavaScript (Node.js + Express)
const express = require('express');
const app = express();

// Presentation Layer
class OrderController {
    constructor(orderService) {
        this.orderService = orderService;
    }
    
    async createOrder(req, res) {
        try {
            const response = await this.orderService.createOrder(req.body);
            res.json(response);
        } catch (error) {
            res.status(500).json({ error: error.message });
        }
    }
}

// Application Layer
class OrderApplicationService {
    constructor(orderRepository, paymentService) {
        this.orderRepository = orderRepository;
        this.paymentService = paymentService;
    }
    
    async createOrder(request) {
        // Применение бизнес-правил
        const order = new Order(request);
        
        // Обработка платежа
        const payment = await this.paymentService.processPayment(order);
        
        if (payment.isSuccess) {
            order.confirm();
            await this.orderRepository.save(order);
        }
        
        return new OrderResponse(order);
    }
}

// Domain Layer
class Order {
    constructor(data) {
        this.id = data.id || Date.now().toString();
        this.customerId = data.customerId;
        this.status = 'DRAFT';
        this.amount = data.amount;
    }
    
    confirm() {
        if (this.status !== 'DRAFT') {
            throw new Error('Cannot confirm non-draft order');
        }
        this.status = 'CONFIRMED';
    }
}

class OrderResponse {
    constructor(order) {
        this.id = order.id;
        this.status = order.status;
        this.amount = order.amount;
    }
}

// Infrastructure Layer
class MongoOrderRepository {
    constructor(mongoClient) {
        this.mongoClient = mongoClient;
    }
    
    async save(order) {
        const db = this.mongoClient.db('ecommerce');
        await db.collection('orders').replaceOne(
            { id: order.id },
            order,
            { upsert: true }
        );
    }
}

// Настройка маршрутов
app.post('/api/orders', async (req, res) => {
    const orderRepository = new MongoOrderRepository(mongoClient);
    const paymentService = new StripePaymentService(stripeClient);
    const orderService = new OrderApplicationService(orderRepository, paymentService);
    const orderController = new OrderController(orderService);
    
    await orderController.createOrder(req, res);
});
🐍 Python (FastAPI + Layered Structure)
from fastapi import FastAPI, HTTPException, Depends
from pydantic import BaseModel
import uuid

app = FastAPI()

# Presentation Layer
class CreateOrderRequest(BaseModel):
    customer_id: str
    amount: float

class OrderResponse(BaseModel):
    id: str
    status: str
    amount: float

@app.post("/api/orders")
async def create_order(
    request: CreateOrderRequest,
    order_service: OrderApplicationService = Depends(get_order_service)
):
    try:
        response = await order_service.create_order(request)
        return response
    except Exception as e:
        raise HTTPException(status_code=500, detail=str(e))

# Application Layer
class OrderApplicationService:
    def __init__(self, order_repository: OrderRepository, payment_service: PaymentService):
        self.order_repository = order_repository
        self.payment_service = payment_service
    
    async def create_order(self, request: CreateOrderRequest) -> OrderResponse:
        # Применение бизнес-правил
        order = Order(request)
        
        # Обработка платежа
        payment = await self.payment_service.process_payment(order)
        
        if payment.is_success:
            order.confirm()
            await self.order_repository.save(order)
        
        return OrderResponse.from_order(order)

# Domain Layer
class Order:
    def __init__(self, data):
        self.id = str(uuid.uuid4())
        self.customer_id = data.customer_id
        self.status = "DRAFT"
        self.amount = data.amount
    
    def confirm(self):
        if self.status != "DRAFT":
            raise ValueError("Cannot confirm non-draft order")
        self.status = "CONFIRMED"

# Infrastructure Layer
class PostgresOrderRepository:
    def __init__(self, db_pool):
        self.db_pool = db_pool
    
    async def save(self, order: Order) -> None:
        async with self.db_pool.acquire() as conn:
            await conn.execute(
                "INSERT INTO orders (id, customer_id, status, amount) VALUES ($1, $2, $3, $4) "
                "ON CONFLICT (id) DO UPDATE SET customer_id = $2, status = $3, amount = $4",
                order.id, order.customer_id, order.status, order.amount
            )

# Dependency Injection
def get_order_service() -> OrderApplicationService:
    order_repository = PostgresOrderRepository(db_pool)
    payment_service = StripePaymentService(stripe_client)
    return OrderApplicationService(order_repository, payment_service)

Serverless Architecture

Определение

Serverless Architecture — это архитектурный стиль, при котором приложение состоит из функций, которые выполняются в ответ на события. Разработчики не управляют серверами напрямую, а полагаются на облачные провайдеры для управления инфраструктурой, масштабированием и развертыванием.

Принципы работы

1. Functions as a Service (FaaS)

  • Код выполняется в виде отдельных функций
  • Функции запускаются по требованию
  • Автоматическое управление жизненным циклом
  • Изоляция выполнения функций

2. Event-driven execution

  • Функции запускаются в ответ на события
  • Различные триггеры: HTTP-запросы, сообщения, файлы, расписания
  • Асинхронная обработка событий
  • Высокая отзывчивость системы

3. Stateless functions

  • Функции не сохраняют состояние между вызовами
  • Все данные передаются через параметры
  • Внешние хранилища для персистентности
  • Горизонтальное масштабирование

4. Pay-per-execution

  • Оплата только за фактическое выполнение
  • Нет платы за простаивающие ресурсы
  • Экономическая эффективность для переменных нагрузок
  • Автоматическое масштабирование до нуля

Состав архитектуры

Основные компоненты:

1. Function Runtime (Среда выполнения функций)
  • AWS Lambda — Amazon Web Services
  • Azure Functions — Microsoft Azure
  • Google Cloud Functions — Google Cloud Platform
  • Cloudflare Workers — Cloudflare
  • Vercel Functions — Vercel
2. Event Sources (Источники событий)
  • HTTP Triggers — REST API, Webhooks
  • Message Queues — SQS, Service Bus, Pub/Sub
  • File Storage — S3, Blob Storage, Cloud Storage
  • Database Events — DynamoDB Streams, Cosmos DB
  • Scheduled Events — CloudWatch Events, Timer Triggers
3. Backend Services (Backend-сервисы)
  • Database as a Service — DynamoDB, Cosmos DB, Firestore
  • Storage Services — S3, Blob Storage, Cloud Storage
  • Message Services — SNS, Event Grid, Pub/Sub
  • Authentication — Cognito, Azure AD, Firebase Auth
  • API Gateway — AWS API Gateway, Azure API Management

Паттерны архитектуры:

1. Event-Driven Processing
  • Event Sourcing — хранение состояния как событий
  • CQRS — разделение команд и запросов
  • Saga Pattern — управление распределенными транзакциями
  • Event Streaming — обработка потоков событий
2. Microservices Patterns
  • Function per Service — одна функция на сервис
  • Function per Use Case — одна функция на use case
  • Function per Domain — группировка по доменам
  • Function Composition — композиция функций
3. Integration Patterns
  • API Gateway — единая точка входа
  • Service Mesh — управление сервисами
  • Event Bus — шина событий
  • Message Routing — маршрутизация сообщений

Технологические решения:

Cloud Providers:
  • AWS — Lambda, API Gateway, DynamoDB, S3
  • Azure — Functions, Logic Apps, Cosmos DB, Blob Storage
  • Google Cloud — Cloud Functions, Cloud Run, Firestore
  • Multi-cloud — Serverless Framework, Terraform
Development Tools:
  • Frameworks — Serverless Framework, AWS SAM, Azure Functions Core Tools
  • Testing — LocalStack, SAM Local, Azure Functions Core Tools
  • Monitoring — CloudWatch, Application Insights, Stackdriver
  • CI/CD — GitHub Actions, Azure DevOps, AWS CodePipeline

Характеристики

  • FaaS — Functions as a Service
  • Event-driven — функции запускаются по событиям
  • Auto-scaling — автоматическое масштабирование
  • Pay-per-use — оплата только за использование

Примеры реализации

🔧 Java (AWS Lambda + Azure Functions)
// AWS Lambda функция
public class OrderProcessor implements RequestHandler<OrderEvent, String> {
    
    @Override
    public String handleRequest(OrderEvent event, Context context) {
        // Обработка заказа
        Order order = processOrder(event);
        
        // Отправка уведомления
        sendNotification(order);
        
        return "Order processed successfully";
    }
    
    private Order processOrder(OrderEvent event) {
        // Логика обработки заказа
        return new Order(event);
    }
    
    private void sendNotification(Order order) {
        // Отправка уведомления
    }
}

// Azure Functions
@FunctionName("ProcessOrder")
public String processOrder(
    @HttpTrigger(name = "req", methods = {HttpMethod.POST}, authLevel = AuthorizationLevel.ANONYMOUS) 
    HttpRequestMessage<Optional<String>> request,
    ExecutionContext context) {
    
    String orderData = request.getBody().orElse("");
    
    // Обработка заказа
    Order order = processOrderData(orderData);
    
    return "Order processed: " + order.getId();
}
🦀 Rust (AWS Lambda + Cloudflare Workers)
use lambda_runtime::{service_fn, Error, LambdaEvent};
use serde::{Deserialize, Serialize};

// AWS Lambda функция
#[derive(Deserialize)]
struct OrderEvent {
    order_id: String,
    customer_id: String,
    amount: f64,
}

#[derive(Serialize)]
struct OrderResponse {
    message: String,
    order_id: String,
}

async fn order_processor(event: LambdaEvent<OrderEvent>) -> Result<OrderResponse, Error> {
    let order = event.payload;
    
    // Обработка заказа
    let processed_order = process_order(&order).await?;
    
    // Отправка уведомления
    send_notification(&processed_order).await?;
    
    Ok(OrderResponse {
        message: "Order processed successfully".to_string(),
        order_id: order.order_id,
    })
}

async fn process_order(event: &OrderEvent) -> Result<Order, Error> {
    // Логика обработки заказа
    Ok(Order {
        id: event.order_id.clone(),
        customer_id: event.customer_id.clone(),
        amount: event.amount,
        status: "PROCESSED".to_string(),
    })
}

async fn send_notification(order: &Order) -> Result<(), Error> {
    // Отправка уведомления через SNS или другой сервис
    println!("Notification sent for order: {}", order.id);
    Ok(())
}

#[tokio::main]
async fn main() -> Result<(), Error> {
    lambda_runtime::run(service_fn(order_processor)).await
}

// Cloudflare Workers
use worker::*;

#[event(fetch)]
async fn main(req: Request, env: Env, _ctx: Context) -> Result<Response> {
    let router = Router::new();
    
    router
        .post_async("/process-order", |mut req, _ctx| async move {
            let order_data: OrderEvent = req.json().await?;
            
            // Обработка заказа
            let order = process_order_worker(&order_data).await?;
            
            // Отправка уведомления
            send_notification_worker(&order).await?;
            
            Response::ok("Order processed successfully")
        })
        .run(req, env)
        .await
}
🟨 JavaScript (AWS Lambda + Vercel Functions)
// AWS Lambda функция
const AWS = require('aws-sdk');
const sns = new AWS.SNS();

exports.handler = async (event) => {
    try {
        // Обработка заказа
        const order = await processOrder(event);
        
        // Отправка уведомления
        await sendNotification(order);
        
        return {
            statusCode: 200,
            body: JSON.stringify({
                message: 'Order processed successfully',
                orderId: order.id
            })
        };
    } catch (error) {
        return {
            statusCode: 500,
            body: JSON.stringify({ error: error.message })
        };
    }
};

async function processOrder(event) {
    // Логика обработки заказа
    return {
        id: event.orderId,
        customerId: event.customerId,
        amount: event.amount,
        status: 'PROCESSED'
    };
}

async function sendNotification(order) {
    // Отправка уведомления через SNS
    const params = {
        Message: `Order ${order.id} has been processed`,
        TopicArn: process.env.SNS_TOPIC_ARN
    };
    
    await sns.publish(params).promise();
}

// Vercel Functions
export default async function handler(req, res) {
    if (req.method !== 'POST') {
        return res.status(405).json({ error: 'Method not allowed' });
    }
    
    try {
        const orderData = req.body;
        
        // Обработка заказа
        const order = await processOrderVercel(orderData);
        
        // Отправка уведомления
        await sendNotificationVercel(order);
        
        res.status(200).json({
            message: 'Order processed successfully',
            orderId: order.id
        });
    } catch (error) {
        res.status(500).json({ error: error.message });
    }
}

async function processOrderVercel(orderData) {
    // Логика обработки заказа
    return {
        id: orderData.orderId,
        customerId: orderData.customerId,
        amount: orderData.amount,
        status: 'PROCESSED'
    };
}

async function sendNotificationVercel(order) {
    // Отправка уведомления через внешний API
    await fetch(process.env.NOTIFICATION_WEBHOOK_URL, {
        method: 'POST',
        headers: { 'Content-Type': 'application/json' },
        body: JSON.stringify({
            message: `Order ${order.id} has been processed`,
            orderId: order.id
        })
    });
}
🐍 Python (AWS Lambda + Google Cloud Functions)
import json
import boto3
from typing import Dict, Any

# AWS Lambda функция
def lambda_handler(event: Dict[str, Any], context: Any) -> Dict[str, Any]:
    try:
        # Обработка заказа
        order = process_order(event)
        
        # Отправка уведомления
        send_notification(order)
        
        return {
            'statusCode': 200,
            'body': json.dumps({
                'message': 'Order processed successfully',
                'orderId': order['id']
            })
        }
    except Exception as e:
        return {
            'statusCode': 500,
            'body': json.dumps({'error': str(e)})
        }

def process_order(event: Dict[str, Any]) -> Dict[str, Any]:
    # Логика обработки заказа
    return {
        'id': event['orderId'],
        'customerId': event['customerId'],
        'amount': event['amount'],
        'status': 'PROCESSED'
    }

def send_notification(order: Dict[str, Any]) -> None:
    # Отправка уведомления через SNS
    sns = boto3.client('sns')
    sns.publish(
        TopicArn=os.environ['SNS_TOPIC_ARN'],
        Message=f"Order {order['id']} has been processed"
    )

# Google Cloud Functions
from google.cloud import pubsub_v1
import functions_framework

@functions_framework.http
def process_order_gcp(request):
    if request.method != 'POST':
        return 'Method not allowed', 405
    
    try:
        order_data = request.get_json()
        
        # Обработка заказа
        order = process_order_gcp_logic(order_data)
        
        # Отправка уведомления
        send_notification_gcp(order)
        
        return {
            'message': 'Order processed successfully',
            'orderId': order['id']
        }
    except Exception as e:
        return {'error': str(e)}, 500

def process_order_gcp_logic(order_data: Dict[str, Any]) -> Dict[str, Any]:
    # Логика обработки заказа
    return {
        'id': order_data['orderId'],
        'customerId': order_data['customerId'],
        'amount': order_data['amount'],
        'status': 'PROCESSED'
    }

def send_notification_gcp(order: Dict[str, Any]) -> None:
    # Отправка уведомления через Pub/Sub
    publisher = pubsub_v1.PublisherClient()
    topic_path = publisher.topic_path(
        os.environ['GCP_PROJECT_ID'],
        os.environ['PUBSUB_TOPIC_NAME']
    )
    
    message_data = f"Order {order['id']} has been processed".encode('utf-8')
    publisher.publish(topic_path, message_data)

Выбор архитектурного стиля

Факторы выбора

  1. Размер команды — маленькая команда → монолит
  2. Сложность домена — сложный домен → микросервисы
  3. Требования к масштабированию — высокие → микросервисы
  4. Технологическое разнообразие — разные технологии → микросервисы
  5. Время разработки — быстрое время → монолит

Рекомендации

  • Начните с монолита — для большинства проектов
  • Переходите к микросервисам — когда монолит становится проблемой
  • Используйте EDA — для асинхронной обработки
  • Рассмотрите CQRS — для сложных read/write требований
  • Применяйте Hexagonal — для изоляции бизнес-логики