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

553 lines
19 KiB
Markdown

# Архитектурные стили и паттерны
## Навигация
- [🏠 Главная страница курса](../../../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<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);
}
}
```
### Преимущества
- **Простота разработки** — легко начать проект
- **Простота тестирования** — все в одном процессе
- **Простота развертывания** — один артефакт
- **Производительность** — нет сетевых вызовов
### Недостатки
- **Сложность масштабирования** — нужно масштабировать все приложение
- **Технологические ограничения** — привязанность к одному стеку
- **Риск сбоев** — падение одного компонента влияет на все
- **Сложность команд** — команды работают над одним кодом
## Микросервисная архитектура
### Определение
**Микросервисная архитектура** — это архитектурный стиль, при котором приложение разбивается на множество небольших, независимых сервисов.
### Характеристики
- **Независимые сервисы** — каждый сервис работает автономно
- **Отдельные базы данных** — каждый сервис имеет свою БД
- **Разные технологии** — сервисы могут использовать разные стеки
- **Сетевое взаимодействие** — сервисы общаются по сети
### Пример реализации
```java
// 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** — это архитектурный стиль, основанный на производстве, обнаружении, потреблении и реакции на события.
### Характеристики
- **События** — значимые изменения в системе
- **Асинхронность** — события обрабатываются асинхронно
- **Слабая связанность** — компоненты не знают друг о друге
- **Масштабируемость** — легко добавлять новых потребителей
### Пример реализации
```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<OrderSummary> 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<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** — внешние зависимости
### Пример реализации
```java
// 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** — оплата только за использование
### Пример реализации
```java
// 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** — для изоляции бизнес-логики