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

Как использовал монолит на проектах?

1.7 Middle🔥 131 комментариев
#Python Core

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

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

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

Как использовал монолит на проектах?

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

1. Что такое монолит и когда он полезен

Монолит — это архитектура, где:

  • Весь код в одном приложении
  • Одна база данных
  • Единая точка развертывания
  • Все компоненты связаны импортами
# Структура типичного монолита
my_app/
├── users/              # Модуль пользователей
│   ├── models.py
│   ├── views.py
│   ├── services.py
│   └── serializers.py
├── products/           # Модуль товаров
│   ├── models.py
│   ├── views.py
│   └── services.py
├── orders/             # Модуль заказов
│   ├── models.py
│   ├── views.py
│   └── services.py
└── shared/             # Общий код
    ├── middleware.py
    ├── decorators.py
    └── utils.py

2. Преимущества монолита, которые я использовал

Простота разработки на старте:

# Все под одной крышей — легко импортировать
from users.services import UserService
from products.services import ProductService
from orders.models import Order

class OrderService:
    def __init__(self):
        self.user_service = UserService()
        self.product_service = ProductService()
    
    def create_order(self, user_id, product_id, quantity):
        # Легко использовать сервисы из других модулей
        user = self.user_service.get_user(user_id)
        product = self.product_service.get_product(product_id)
        return Order.objects.create(
            user=user,
            product=product,
            quantity=quantity
        )

Производительность при вызовах между модулями:

# Нет сетевых задержек — прямые вызовы функций
user = user_service.get_user(1)  # Быстро
product = product_service.get_product(1)  # Быстро

# В микросервисах это были бы HTTP запросы
import requests
user = requests.get('http://user-service/users/1').json()  # Медленнее
product = requests.get('http://product-service/products/1').json()  # Медленнее

Единая база данных — проще транзакции:

from django.db import transaction

class OrderService:
    @transaction.atomic
    def create_order_with_payment(self, user_id, product_id):
        # Всё в одной транзакции
        order = Order.objects.create(user_id=user_id, product_id=product_id)
        payment = Payment.objects.create(order=order, amount=100)
        notification = Notification.objects.create(
            user_id=user_id,
            text=f"Order {order.id} created"
        )
        return order, payment, notification

Простое развертывание:

# Одна команда — и всё работает
python manage.py migrate
gunicorn myapp.wsgi --workers 4

# Не нужно координировать развертывание 10 микросервисов

3. Как я структурировал код в монолите

Слоистая архитектура (layered):

# models.py — слой данных
class User(models.Model):
    name = models.CharField(max_length=100)
    email = models.EmailField(unique=True)

# services.py — бизнес-логика
class UserService:
    def create_user(self, name, email):
        if User.objects.filter(email=email).exists():
            raise ValueError("User already exists")
        return User.objects.create(name=name, email=email)
    
    def get_user_with_orders(self, user_id):
        user = User.objects.get(id=user_id)
        orders = Order.objects.filter(user=user)
        return {"user": user, "orders": orders}

# views.py — представления
class UserViewSet(viewsets.ModelViewSet):
    queryset = User.objects.all()
    serializer_class = UserSerializer
    
    def perform_create(self, serializer):
        # Используем сервис
        service = UserService()
        user = service.create_user(
            name=serializer.validated_data['name'],
            email=serializer.validated_data['email']
        )
        return user

4. Управление зависимостями в монолите

Как я избегал циклических импортов:

# ❌ Плохо — циклическая зависимость
# users/services.py
from products.services import ProductService  # Проблема!

# products/services.py
from users.services import UserService  # Циклическая зависимость

# ✅ Хорошо — зависимость передается через аргументы
# users/services.py
class UserService:
    def __init__(self, product_service):
        self.product_service = product_service
    
    def get_user_recommendations(self, user_id):
        user = self.get_user(user_id)
        return self.product_service.get_products()

# В точке инициализации
product_service = ProductService()
user_service = UserService(product_service)

5. Тестирование в монолите

Интеграционные тесты проще:

import pytest
from django.test import TransactionTestCase
from users.services import UserService
from orders.services import OrderService

class TestOrderCreation(TransactionTestCase):
    def test_full_order_workflow(self):
        # Создаём пользователя
        user_service = UserService()
        user = user_service.create_user("John", "john@example.com")
        
        # Создаём заказ
        order_service = OrderService(user_service)
        order = order_service.create_order(user.id, product_id=1)
        
        # Проверяем всю цепочку
        assert order.user.id == user.id
        assert order.status == "pending"

6. Проблемы монолита, которые я встретил

Рост базы кода:

# Со временем файл становится слишком большим
# views.py вырастает до 5000+ строк

# Решение: разделить на подмодули
views/
├── user_views.py
├── product_views.py
├── order_views.py
└── __init__.py

Сложность масштабирования:

# Если один модуль нужен часто, а другой редко,
# все равно масштабируется всё приложение

# Решение на старте монолита:
# 1. Кэширование часто используемых данных
from django.views.decorators.cache import cache_page

@cache_page(60)  # Кэш на 60 секунд
def get_products(request):
    return JsonResponse(Product.objects.all())

# 2. Асинхронные задачи для тяжёлых операций
from celery import shared_task

@shared_task
def send_email_notification(order_id):
    # Выполняется в фоне, не блокирует запрос
    order = Order.objects.get(id=order_id)
    send_email(order.user.email)

7. Когда я перешёл на микросервисы

Признаки, что монолит разросся:

  • Время развертывания > 10 минут
  • Изменение в одном модуле требует перезапуска всего
  • Разные команды конфликтуют при разработке
  • Разные модули требуют разных языков/фреймворков

Переход выглядел так:

# Шаг 1: Выделяем API монолита
# myapp/api/users.py
from rest_framework import viewsets

class UserAPI(viewsets.ModelViewSet):
    # Чистый API, без бизнес-логики
    queryset = User.objects.all()
    serializer_class = UserSerializer

# Шаг 2: Эту API начинают вызывать из других сервисов
import requests
users = requests.get('http://user-service/api/users/').json()

# Шаг 3: Постепенно выделяем микросервис
# Копируем UserService в отдельный репо
# Заменяем импорты на HTTP запросы

8. Заключение и рекомендации

Монолит хорошо подходит:

  • На начальном этапе стартапа
  • Для command-line утилит
  • Для внутренних систем с < 10 разработчиков
  • Когда большинство модулей часто взаимодействуют

Признак, что нужны микросервисы:

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

Best Practices монолита:

  1. Четкая структура модулей
  2. Минимизация циклических зависимостей
  3. Кэширование и асинхронность
  4. Хорошее тестирование
  5. Продуманная архитектура с самого начала

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

Как использовал монолит на проектах? | PrepBro