Files
sa-lessons/modules/module1/sections/05-architectural-styles-patterns.md
T
Alexander Abakumov 15e744da49 Initial commit: Complete Software Architecture course with 11 modules
- Added comprehensive course structure with 11 modules
- Included theoretical content, practical examples, and tasks
- Multi-language code examples (Java, Rust, Node.js, Python)
- Detailed analysis of architectural approaches and trade-offs
- Complete caching strategies documentation
- Architecture examples from real-world systems (Twitter, Netflix, Uber)
- Structured navigation and learning path
- Ready for educational use
2025-09-09 22:08:07 +03:00

19 KiB
Raw Blame History

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

Навигация


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

Определение

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

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

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

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

// Монолитное приложение 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);
    }
}

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

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

Недостатки

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

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

Определение

Микросервисная архитектура — это архитектурный стиль, при котором приложение разбивается на множество небольших, независимых сервисов.

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

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

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

// 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);
    }
}

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

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

Недостатки

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

Event-Driven Architecture (EDA)

Определение

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

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

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

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

// Доменное событие
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 — это паттерн, который разделяет операции чтения и записи данных на разные модели.

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

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

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

// 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());
    }
}

Hexagonal Architecture (Ports and Adapters)

Определение

Hexagonal Architecture — это архитектурный паттерн, который изолирует бизнес-логику от внешних зависимостей.

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

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

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

// 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 реализация
    }
}

Layered Architecture

Определение

Layered Architecture — это архитектурный паттерн, который организует код в горизонтальные слои.

Слои

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

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

// 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);
    }
}

Serverless Architecture

Определение

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

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

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

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

// 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();
}

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

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

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

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

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