# Архитектурные стили и паттерны ## Навигация - [🏠 Главная страница курса](../../../README.md) - [📚 Модуль 1](../README.md) --- ## Монолитная архитектура ### Определение **Монолитная архитектура** — это архитектурный стиль, при котором все компоненты приложения объединены в единое развертываемое приложение. Это традиционный подход к разработке программного обеспечения, где все функциональные возможности реализованы в рамках одного процесса. ### Принципы работы #### 1. **Единый процесс** - Все компоненты выполняются в рамках одного процесса операционной системы - Общая память и ресурсы для всех модулей - Простая отладка и профилирование #### 2. **Совместное развертывание** - Все изменения развертываются одновременно - Единый артефакт (JAR, WAR, EXE файл) - Простота управления версиями #### 3. **Прямое взаимодействие** - Компоненты вызывают друг друга через прямые ссылки - Нет сетевых задержек между модулями - Высокая производительность внутренних вызовов #### 4. **Общие ресурсы** - Единая база данных для всех модулей - Общие библиотеки и зависимости - Централизованное управление конфигурацией ### Состав архитектуры #### **Структурные компоненты:** 1. **Презентационный слой** — пользовательский интерфейс (UI/API) 2. **Бизнес-логика** — основная логика приложения 3. **Слой данных** — работа с базой данных 4. **Общие утилиты** — вспомогательные функции #### **Технические компоненты:** - **Веб-сервер** — обработка HTTP-запросов - **Контейнер приложения** — управление жизненным циклом - **ORM/DAO** — работа с базой данных - **Кэш** — хранение часто используемых данных - **Логирование** — запись событий и ошибок #### **Инфраструктурные компоненты:** - **База данных** — хранение данных - **Файловая система** — хранение файлов - **Внешние API** — интеграция с внешними сервисами - **Мониторинг** — отслеживание состояния приложения ### Характеристики - **Единое развертывание** — все компоненты развертываются вместе - **Общая база данных** — все модули используют одну БД - **Единый технологический стек** — один язык, один фреймворк - **Прямые вызовы** — компоненты вызывают друг друга напрямую ### Примеры реализации
🔧 Java (Spring Boot) ```java // Монолитное приложение 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 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) ```rust // Монолитное приложение 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, } #[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, user_service: web::Data, order_service: web::Data, payment_service: web::Data, ) -> Result> { // Вся логика в одном месте 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) ```javascript // Монолитное приложение 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) ```python # Монолитное приложение 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) ```java // User Service @RestController @RequestMapping("/api/users") public class UserController { @Autowired private UserService userService; @GetMapping("/{id}") public ResponseEntity 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 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 processPayment(@RequestBody PaymentRequest request) { PaymentResult result = paymentService.processPayment(request); return ResponseEntity.ok(result); } } ```
🦀 Rust (Actix Web) ```rust // 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) -> Result> { 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, user_client: web::Data, ) -> Result> { // Вызов внешнего сервиса 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, ) -> Result> { let result = payment_service.process_payment(payment_data.into_inner()).await?; Ok(web::Json(result)) } ```
🟨 JavaScript (Node.js) ```javascript // 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) ```python # 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) ```java // Доменное событие 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) ```rust 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, } // Event Publisher pub struct EventPublisher { sender: mpsc::UnboundedSender, } impl EventPublisher { pub fn new(sender: mpsc::UnboundedSender) -> 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 { 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) ```javascript 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) ```python 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) ```java // 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 handle(GetOrdersQuery query) { return orderSummaryRepository.findByCustomerId(query.getCustomerId()); } } ```
🦀 Rust (Actix Web + Diesel) ```rust 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, } 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, 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, String> { self.order_summary_repository.find_by_customer_id(&query.customer_id).await } } ```
🟨 JavaScript (Node.js + MongoDB) ```javascript // 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) ```python 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) ```java // 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 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 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) ```rust 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, String>; } #[async_trait] pub trait PaymentService: Send + Sync { async fn process_payment(&self, request: PaymentRequest) -> Result; } #[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, payment_service: Arc, notification_service: Arc, } impl OrderService { pub fn new( order_repository: Arc, payment_service: Arc, notification_service: Arc, ) -> 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, 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) ```javascript // 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) ```python 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) ```java // Presentation Layer @RestController @RequestMapping("/api/orders") public class OrderController { @Autowired private OrderApplicationService orderService; @PostMapping public ResponseEntity 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) ```rust 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, order_service: web::Data, ) -> Result> { let response = order_service.create_order(request.into_inner()).await?; Ok(web::Json(response)) } // Application Layer pub struct OrderApplicationService { order_repository: Arc, payment_service: Arc, } impl OrderApplicationService { pub async fn create_order(&self, request: CreateOrderRequest) -> Result { // Применение бизнес-правил 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) ```javascript 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) ```python 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) ```java // AWS Lambda функция public class OrderProcessor implements RequestHandler { @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> request, ExecutionContext context) { String orderData = request.getBody().orElse(""); // Обработка заказа Order order = processOrderData(orderData); return "Order processed: " + order.getId(); } ```
🦀 Rust (AWS Lambda + Cloudflare Workers) ```rust 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) -> Result { 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 { // Логика обработки заказа 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 { 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) ```javascript // 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) ```python 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** — для изоляции бизнес-логики