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

Что такое бизнес-логика?

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

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

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

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

Бизнес-логика: ядро приложения

Бизнес-логика - это набор правил и алгоритмов, которые определяют как работает приложение в соответствии с требованиями бизнеса. Это не представление (UI) и не хранение данных (БД), а само решение проблемы, для которой создано приложение.

Что это и почему важно

Бизнес-логика отвечает на вопросы:

  • Как рассчитать цену товара со скидкой?
  • Когда отправить уведомление пользователю?
  • Какие условия нужны для одобрения кредита?
  • Как распределить заказы между доставщиками?
  • Когда заблокировать аккаунт при подозрении на мошенничество?

Это не UI (кнопки, иконки) и не БД (таблицы, индексы) - это суть приложения.

Примеры бизнес-логики

Пример 1: E-commerce (интернет-магазин)

# Вычисление цены товара с скидкой
def calculate_final_price(base_price, discount_percent, quantity, is_premium_user):
    """Бизнес-логика: вычисление финальной цены"""
    
    # Скидка в зависимости от количества
    if quantity >= 10:
        quantity_discount = 0.1  # 10% скидка
    elif quantity >= 5:
        quantity_discount = 0.05  # 5% скидка
    else:
        quantity_discount = 0
    
    # Премиум пользователи получают ещё 5%
    if is_premium_user:
        premium_discount = 0.05
    else:
        premium_discount = 0
    
    # Общая скидка (максимум 30%)
    total_discount = min(discount_percent + quantity_discount + premium_discount, 0.3)
    
    # Финальная цена
    final_price = base_price * quantity * (1 - total_discount)
    
    return final_price

# Использование
price = calculate_final_price(
    base_price=100,
    discount_percent=0.05,
    quantity=15,
    is_premium_user=True
)
print(f"Финальная цена: {price}")  # 1275 (100 * 15 * (1 - 0.15))

Это бизнес-логика, потому что она содержит правила, определённые бизнесом (скидки, условия и т.д.).

Пример 2: Обработка платежей

# Бизнес-логика: одобрение платежа
def process_payment(user, amount):
    """Проверяет условия и обрабатывает платёж"""
    
    # Правило 1: минимальная сумма платежа
    if amount < 10:
        return {'status': 'rejected', 'reason': 'Amount too small'}
    
    # Правило 2: проверка баланса
    if user.balance < amount:
        return {'status': 'rejected', 'reason': 'Insufficient funds'}
    
    # Правило 3: проверка лимитов (антифрод)
    daily_spent = user.get_daily_spending()
    if daily_spent + amount > user.daily_limit:
        return {'status': 'rejected', 'reason': 'Daily limit exceeded'}
    
    # Правило 4: новые пользователи должны подтвердить email
    if not user.email_verified and user.account_age_days < 7:
        return {'status': 'pending', 'reason': 'Verification required'}
    
    # Все проверки пройдены - можно обработать платёж
    user.balance -= amount
    user.save()
    
    return {'status': 'approved', 'transaction_id': 'TXN123'}

Это бизнес-правила: минимальная сумма, лимиты, проверки.

Структура: где должна жить бизнес-логика

WEB REQUEST
    ↓
[PRESENTATION LAYER]
  └── views.py, serializers
      (Получить данные, вызвать бизнес-логику)
    ↓
[APPLICATION LAYER] ← БИЗНЕС-ЛОГИКА ЗДЕСЬ
  └── services.py, use_cases
      (Вся логика: расчёты, валидация, координация)
    ↓
[DOMAIN LAYER]
  └── models
      (Создание объектов, валидация данных)
    ↓
[INFRASTRUCTURE LAYER]
  └── repositories, database
      (Сохранение в БД, работа с внешними сервисами)
    ↓
WEB RESPONSE

Плохо: бизнес-логика в View

# ❌ ПЛОХО: логика в view
from django.views import View
from django.http import JsonResponse

class PaymentView(View):
    def post(self, request):
        user = request.user
        amount = float(request.POST.get('amount'))
        
        # СЛИШКОМ МНОГО ЛОГИКИ В VIEW!
        if amount < 10:
            return JsonResponse({'error': 'Too small'})
        
        if user.balance < amount:
            return JsonResponse({'error': 'No funds'})
        
        daily_spent = user.transactions.filter(
            created_at__gte=timezone.now().date()
        ).aggregate(Sum('amount'))['amount__sum'] or 0
        
        if daily_spent + amount > 5000:
            return JsonResponse({'error': 'Limit exceeded'})
        
        user.balance -= amount
        user.save()
        
        Transaction.objects.create(
            user=user,
            amount=amount,
            status='completed'
        )
        
        return JsonResponse({'status': 'ok'})

Проблемы:

  • Код невозможно тестировать без Django
  • Бизнес-правила зашиты в view
  • Повторное использование - невозможно
  • Трудно менять правила

Хорошо: бизнес-логика в Service

# ✅ ХОРОШО: логика в отдельном service
from typing import TypedDict

class PaymentResult(TypedDict):
    status: str  # 'approved', 'rejected', 'pending'
    reason: str
    transaction_id: str | None

class PaymentService:
    """Сервис обработки платежей - чистая бизнес-логика"""
    
    MIN_AMOUNT = 10
    MAX_DAILY_LIMIT = 5000
    
    def process_payment(self, user, amount) -> PaymentResult:
        # Валидация
        if amount < self.MIN_AMOUNT:
            return {
                'status': 'rejected',
                'reason': f'Minimum amount is {self.MIN_AMOUNT}',
                'transaction_id': None
            }
        
        # Проверка баланса
        if user.balance < amount:
            return {
                'status': 'rejected',
                'reason': 'Insufficient funds',
                'transaction_id': None
            }
        
        # Проверка лимитов
        daily_spent = self._get_daily_spending(user)
        if daily_spent + amount > self.MAX_DAILY_LIMIT:
            return {
                'status': 'rejected',
                'reason': 'Daily limit exceeded',
                'transaction_id': None
            }
        
        # Обработка платежа
        transaction_id = self._create_transaction(user, amount)
        user.balance -= amount
        user.save()
        
        return {
            'status': 'approved',
            'reason': 'Payment processed',
            'transaction_id': transaction_id
        }
    
    def _get_daily_spending(self, user) -> float:
        """Получить сумму трат пользователя за день"""
        from django.utils import timezone
        from django.db.models import Sum
        
        result = user.transactions.filter(
            created_at__date=timezone.now().date()
        ).aggregate(Sum('amount'))['amount__sum']
        
        return result or 0
    
    def _create_transaction(self, user, amount) -> str:
        """Создать запись о транзакции"""
        from .models import Transaction
        transaction = Transaction.objects.create(
            user=user,
            amount=amount,
            status='completed'
        )
        return str(transaction.id)

# View теперь простой
from django.views import View
from django.http import JsonResponse

class PaymentView(View):
    def post(self, request):
        amount = float(request.POST.get('amount'))
        
        # View ТОЛЬКО получает данные и вызывает бизнес-логику
        service = PaymentService()
        result = service.process_payment(request.user, amount)
        
        status_code = 200 if result['status'] == 'approved' else 400
        return JsonResponse(result, status=status_code)

Тестирование бизнес-логики

Код в Service легко тестировать:

import pytest
from django.test import TestCase
from .services import PaymentService
from .models import User

class TestPaymentService(TestCase):
    def setUp(self):
        self.service = PaymentService()
        self.user = User.objects.create(
            username='john',
            balance=1000
        )
    
    def test_payment_too_small(self):
        """Платёж меньше минимума отклоняется"""
        result = self.service.process_payment(self.user, 5)
        assert result['status'] == 'rejected'
        assert 'Minimum' in result['reason']
    
    def test_insufficient_funds(self):
        """Платёж при недостаточных средствах отклоняется"""
        result = self.service.process_payment(self.user, 2000)
        assert result['status'] == 'rejected'
        assert 'funds' in result['reason'].lower()
    
    def test_successful_payment(self):
        """Успешный платёж обрабатывается"""
        result = self.service.process_payment(self.user, 100)
        assert result['status'] == 'approved'
        assert result['transaction_id'] is not None
        
        # Баланс должен уменьшиться
        self.user.refresh_from_db()
        assert self.user.balance == 900

Принципы написания бизнес-логики

  1. Отделение - бизнес-логика отделена от View, Model, БД
  2. Чистота - функции чистые (для одного входа один выход)
  3. Тестируемость - можно тестировать без Django
  4. Переиспользуемость - одна функция используется в разных местах
  5. Читаемость - код отражает бизнес-правила

Где писать бизнес-логику в Django

project/
└── myapp/
    ├── services/          ← ВСЯ БИЗНЕС-ЛОГИКА ЗДЕСЬ
    │   ├── __init__.py
    │   ├── payment.py
    │   ├── user.py
    │   └── order.py
    ├── models.py          ← Структуры данных
    ├── views.py           ← Обработка запросов (тонкий слой)
    ├── serializers.py     ← Валидация и сериализация
    └── urls.py

Реальный пример: расчёт налога

# services/tax.py - ВСЯ БИЗНЕС-ЛОГИКА ЗДЕСЬ
class TaxCalculator:
    """Расчёт налогов в зависимости от региона и суммы"""
    
    TAX_RATES = {
        'CA': 0.0725,  # 7.25%
        'TX': 0.0625,  # 6.25%
        'NY': 0.0800,  # 8.00%
    }
    
    def calculate_tax(self, amount, state):
        rate = self.TAX_RATES.get(state, 0.07)
        return amount * rate
    
    def calculate_total(self, subtotal, state):
        tax = self.calculate_tax(subtotal, state)
        return subtotal + tax

# Тест
def test_tax_calculator():
    calc = TaxCalculator()
    
    # Без Django, просто Python
    tax = calc.calculate_tax(100, 'CA')
    assert tax == 7.25
    
    total = calc.calculate_total(100, 'TX')
    assert total == 106.25

Вывод

Бизнес-логика:

  1. Это ядро приложения - решение задачи
  2. НЕ зависит от Django, БД, фреймворков
  3. Должна жить в Service слое отдельно от View
  4. Легко тестируется (unit тесты без Django)
  5. Переиспользуется в разных частях приложения
  6. Легко меняется (правила обновляются в одном месте)
  7. Это то, за что платит клиент, а не UI красота

Хороший разработчик отделяет бизнес-логику от технических деталей!

Что такое бизнес-логика? | PrepBro