# Архитектурные стили и паттерны ## Навигация - [🏠 Главная страница курса](../../../README.md) - [📚 Модуль 1](../README.md) --- ## Монолитная архитектура ### Определение **Монолитная архитектура** — это архитектурный стиль, при котором все компоненты приложения объединены в единое развертываемое приложение. ### Характеристики - **Единое развертывание** — все компоненты развертываются вместе - **Общая база данных** — все модули используют одну БД - **Единый технологический стек** — один язык, один фреймворк - **Прямые вызовы** — компоненты вызывают друг друга напрямую ### Пример реализации ```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); } } ``` ### Преимущества - **Простота разработки** — легко начать проект - **Простота тестирования** — все в одном процессе - **Простота развертывания** — один артефакт - **Производительность** — нет сетевых вызовов ### Недостатки - **Сложность масштабирования** — нужно масштабировать все приложение - **Технологические ограничения** — привязанность к одному стеку - **Риск сбоев** — падение одного компонента влияет на все - **Сложность команд** — команды работают над одним кодом ## Микросервисная архитектура ### Определение **Микросервисная архитектура** — это архитектурный стиль, при котором приложение разбивается на множество небольших, независимых сервисов. ### Характеристики - **Независимые сервисы** — каждый сервис работает автономно - **Отдельные базы данных** — каждый сервис имеет свою БД - **Разные технологии** — сервисы могут использовать разные стеки - **Сетевое взаимодействие** — сервисы общаются по сети ### Пример реализации ```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); } } ``` ### Преимущества - **Независимое масштабирование** — каждый сервис масштабируется отдельно - **Технологическое разнообразие** — разные технологии для разных задач - **Независимые команды** — команды работают над разными сервисами - **Отказоустойчивость** — падение одного сервиса не влияет на другие ### Недостатки - **Сложность разработки** — нужно управлять множеством сервисов - **Сетевая задержка** — вызовы между сервисами медленнее - **Сложность тестирования** — нужно тестировать интеграции - **Сложность развертывания** — нужно координировать развертывание ## Event-Driven Architecture (EDA) ### Определение **Event-Driven Architecture** — это архитектурный стиль, основанный на производстве, обнаружении, потреблении и реакции на события. ### Характеристики - **События** — значимые изменения в системе - **Асинхронность** — события обрабатываются асинхронно - **Слабая связанность** — компоненты не знают друг о друге - **Масштабируемость** — легко добавлять новых потребителей ### Пример реализации ```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()); } } ``` ## CQRS (Command Query Responsibility Segregation) ### Определение **CQRS** — это паттерн, который разделяет операции чтения и записи данных на разные модели. ### Характеристики - **Разделение команд и запросов** — разные модели для записи и чтения - **Оптимизация** — модели оптимизированы для своих задач - **Масштабируемость** — можно масштабировать чтение и запись отдельно - **Сложность** — увеличивает сложность системы ### Пример реализации ```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()); } } ``` ## Hexagonal Architecture (Ports and Adapters) ### Определение **Hexagonal Architecture** — это архитектурный паттерн, который изолирует бизнес-логику от внешних зависимостей. ### Характеристики - **Порты** — интерфейсы для взаимодействия с внешним миром - **Адаптеры** — реализации портов для конкретных технологий - **Изоляция** — бизнес-логика не зависит от внешних технологий - **Тестируемость** — легко тестировать с mock-объектами ### Пример реализации ```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 реализация } } ``` ## Layered Architecture ### Определение **Layered Architecture** — это архитектурный паттерн, который организует код в горизонтальные слои. ### Слои 1. **Presentation Layer** — пользовательский интерфейс 2. **Application Layer** — бизнес-логика приложения 3. **Domain Layer** — доменная логика 4. **Infrastructure Layer** — внешние зависимости ### Пример реализации ```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); } } ``` ## Serverless Architecture ### Определение **Serverless Architecture** — это архитектурный стиль, при котором приложение состоит из функций, которые выполняются в ответ на события. ### Характеристики - **FaaS** — Functions as a Service - **Event-driven** — функции запускаются по событиям - **Auto-scaling** — автоматическое масштабирование - **Pay-per-use** — оплата только за использование ### Пример реализации ```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(); } ``` ## Выбор архитектурного стиля ### Факторы выбора 1. **Размер команды** — маленькая команда → монолит 2. **Сложность домена** — сложный домен → микросервисы 3. **Требования к масштабированию** — высокие → микросервисы 4. **Технологическое разнообразие** — разные технологии → микросервисы 5. **Время разработки** — быстрое время → монолит ### Рекомендации - **Начните с монолита** — для большинства проектов - **Переходите к микросервисам** — когда монолит становится проблемой - **Используйте EDA** — для асинхронной обработки - **Рассмотрите CQRS** — для сложных read/write требований - **Применяйте Hexagonal** — для изоляции бизнес-логики