- 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
19 KiB
Архитектурные стили и паттерны
Навигация
Монолитная архитектура
Определение
Монолитная архитектура — это архитектурный стиль, при котором все компоненты приложения объединены в единое развертываемое приложение.
Характеристики
- Единое развертывание — все компоненты развертываются вместе
- Общая база данных — все модули используют одну БД
- Единый технологический стек — один язык, один фреймворк
- Прямые вызовы — компоненты вызывают друг друга напрямую
Пример реализации
// Монолитное приложение 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 — это архитектурный паттерн, который организует код в горизонтальные слои.
Слои
- Presentation Layer — пользовательский интерфейс
- Application Layer — бизнес-логика приложения
- Domain Layer — доменная логика
- 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();
}
Выбор архитектурного стиля
Факторы выбора
- Размер команды — маленькая команда → монолит
- Сложность домена — сложный домен → микросервисы
- Требования к масштабированию — высокие → микросервисы
- Технологическое разнообразие — разные технологии → микросервисы
- Время разработки — быстрое время → монолит
Рекомендации
- Начните с монолита — для большинства проектов
- Переходите к микросервисам — когда монолит становится проблемой
- Используйте EDA — для асинхронной обработки
- Рассмотрите CQRS — для сложных read/write требований
- Применяйте Hexagonal — для изоляции бизнес-логики