← Назад к вопросам

Какие знаешь архитектурные паттерны сервисов?

3.0 Senior🔥 161 комментариев
#Архитектура и паттерны

Комментарии (1)

🐱
claude-haiku-4.5PrepBro AI22 мар. 2026 г.(ред.)

Ответ сгенерирован нейросетью и может содержать ошибки

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

Архитектурные паттерны определяют структуру и взаимодействие компонентов системы. Рассмотрю основные паттерны, которые используются в современной разработке.

1. Монолит (Monolithic Architecture)

Описание: Весь код в одном приложении, все модули запускаются вместе.

┌──────────────────────────────────────┐
│        Single Application             │
│  ┌────────┬──────────┬──────────┐   │
│  │ Users  │ Products │ Orders   │   │
│  │ Module │ Module   │ Module   │   │
│  └────────┴──────────┴──────────┘   │
└──────────────────────────────────────┘
         Single Database

Плюсы:

  • Простота разработки и развертывания
  • Легче отладить
  • Хороший performance (нет сетевых вызовов)

Минусы:

  • Сложно масштабировать части отдельно
  • Любой баг может сломать всё приложение
  • Сложно менять технологический стек

Когда использовать: Стартапы, pequeños проекты, MVP.

2. Микросервисы (Microservices)

Описание: Множество независимых сервисов, каждый отвечает за одну функцию.

┌──────────────┐  ┌──────────────┐  ┌──────────────┐
│ User Service │  │Product Service│  │Order Service │
│   :8001      │  │    :8002      │  │    :8003     │
└──────────────┘  └──────────────┘  └──────────────┘
       │                │                  │
   [MySQL]        [PostgreSQL]        [MongoDB]

Плюсы:

  • Независимое масштабирование
  • Отказоустойчивость (падение одного сервиса не ломает всё)
  • Разные технологии для разных сервисов
  • Разные команды могут работать независимо

Минусы:

  • Сложность в разработке
  • Сложная отладка (distributed tracing)
  • Network latency
  • Consensus проблемы (distributed transactions)

Когда использовать: Крупные системы, разные команды, разные требования к масштабируемости.

3. Слоистая архитектура (Layered Architecture)

Описание: Код разделён на слои — presentation, business logic, data access.

┌─────────────────────────────────┐
│      Presentation Layer         │
│   (Controllers, REST API)       │
├─────────────────────────────────┤
│     Application Layer           │
│     (Services, Use Cases)       │
├─────────────────────────────────┤
│      Domain Layer               │
│    (Business Rules, Models)     │
├─────────────────────────────────┤
│  Infrastructure Layer           │
│  (Database, External APIs)      │
└─────────────────────────────────┘

Плюсы:

  • Легко понять структуру
  • Хорошее разделение ответственности
  • Легко тестировать

Минусы:

  • Может стать "толстым слоем" (много кода в одном слое)
  • Зависимости могут быть циклические

Python пример:

# Presentation layer
from fastapi import FastAPI

app = FastAPI()

@app.get("/users/{user_id}")
def get_user(user_id: int, service: UserService = Depends()):
    return service.get_user(user_id)  # Application layer

# Application layer
class UserService:
    def __init__(self, repository: UserRepository):
        self.repo = repository
    
    def get_user(self, user_id: int):
        return self.repo.find_by_id(user_id)  # Infrastructure layer

# Infrastructure layer
class UserRepository:
    def find_by_id(self, user_id: int):
        return db.query(User).filter(User.id == user_id).first()

4. Луковая архитектура (Onion Architecture / DDD)

Описание: Слои организованы концентрически, внешние зависят от внутренних.

         ┌─────────────────────────────┐
         │   Presentation (UI, API)    │
         ├─────────────────────────────┤
         │  Application (Use Cases)    │
         ├─────────────────────────────┤
         │   Domain (Business Rules)   │
         ├─────────────────────────────┤
         │  Infrastructure (DB, APIs)  │
         └─────────────────────────────┘

Главное правило: Зависимости только вовнутрь!

# Domain (самый внутренний, без зависимостей)
class User:
    def __init__(self, name: str, email: str):
        self.name = name
        self.email = email
    
    def is_valid(self) -> bool:
        return len(self.name) > 0 and "@" in self.email

# Application
class CreateUserUseCase:
    def __init__(self, repository: UserRepository):
        self.repo = repository
    
    def execute(self, name: str, email: str):
        user = User(name, email)
        if not user.is_valid():
            raise ValueError("Invalid user")
        return self.repo.save(user)

# Infrastructure
class UserRepository:
    def save(self, user: User):
        db.session.add(user)
        db.session.commit()

# Presentation
@app.post("/users")
def create_user(dto: UserDTO, use_case: CreateUserUseCase = Depends()):
    return use_case.execute(dto.name, dto.email)

5. CQRS (Command Query Responsibility Segregation)

Описание: Разделить операции на чтение (Query) и запись (Command).

┌──────────────┐
│    Client    │
└──────┬───────┘
       │
    ┌──┴──┐
    │     │
 ┌──▼─┐ ┌─▼──┐
 │Cmd │ │Qry │
 └──┬─┘ └─┬──┘
    │     │
┌───▼─────▼────┐
│   Database   │
└──────────────┘

Пример:

# Command (изменение состояния)
class CreateOrderCommand:
    def __init__(self, user_id: int, items: List[Item]):
        self.user_id = user_id
        self.items = items

class CreateOrderCommandHandler:
    def handle(self, cmd: CreateOrderCommand):
        order = Order(user_id=cmd.user_id)
        for item in cmd.items:
            order.add_item(item)
        db.session.add(order)
        db.session.commit()
        return order.id

# Query (чтение)
class GetOrderQuery:
    def __init__(self, order_id: int):
        self.order_id = order_id

class GetOrderQueryHandler:
    def handle(self, query: GetOrderQuery):
        return db.query(Order).filter(Order.id == query.order_id).first()

# API
@app.post("/orders")  # Command
def create_order(cmd: CreateOrderCommand):
    handler = CreateOrderCommandHandler()
    return {"order_id": handler.handle(cmd)}

@app.get("/orders/{order_id}")  # Query
def get_order(order_id: int):
    handler = GetOrderQueryHandler()
    return handler.handle(GetOrderQuery(order_id))

6. Event-Driven Architecture

Описание: Компоненты взаимодействуют через события.

┌────────────┐
│  Service A │ ──┐
└────────────┘   │ publishes
                 │ Event
┌────────────┐   │  ┌───────────────┐
│  Service B │ ◄─┼──│ Event Broker  │
└────────────┘   │  │  (Kafka, RMQ) │
                 │  └───────────────┘
┌────────────┐   │
│  Service C │ ◄─┘
└────────────┘

Python пример с Celery:

from celery import Celery

app = Celery('tasks')

# Publisher
from myapp.tasks import send_email_task

def create_order(order_data):
    order = Order.create(**order_data)
    # Emit event
    send_email_task.delay(order.id, order.user.email)
    return order

# Subscriber
@app.task
def send_email_task(order_id, email):
    order = Order.get(order_id)
    send_email(email, f"Your order #{order_id} is confirmed")

7. Serverless (FaaS - Function as a Service)

Описание: Код запускается как функции без управления сервером.

# AWS Lambda
import json

def lambda_handler(event, context):
    user_id = event['pathParameters']['user_id']
    user = db.get_user(user_id)
    
    return {
        'statusCode': 200,
        'body': json.dumps(user.__dict__)
    }

Плюсы: Автоматическое масштабирование, платим только за использование.

Минусы: Cold start, ограничения по памяти и CPU, сложнее отладить.

Сравнение паттернов

ПаттернСложностьМасштабируемостьPerformanceКогда использовать
МонолитНизкаяПлохаяОтличноеMVP, стартап
МикросервисыВысокаяОтличнаяХорошееКрупные системы
СлоистаяСредняяСредняяХорошееCRUD приложения
ЛуковаяВысокаяСредняяХорошееСложная логика
CQRSВысокаяОтличнаяОтличноеАсимметричные Чтения/Писания
Event-DrivenВысокаяОтличнаяХорошееСлабо связанные сервисы
ServerlessСредняяОтличнаяЗависитПериодические задачи

Практические рекомендации

  • Начните с монолита — это проще и меньше overhead
  • Переходите на микросервисы когда монолит становится слишком большим
  • Используйте правильный паттерн для правильной проблемы
  • Комбинируйте паттерны — например, слоистая архитектура внутри микросервиса
  • Документируйте выбор паттерна и причины