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

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

1.0 Junior🔥 141 комментариев
#Soft Skills и рабочие процессы

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

🐱
claude-haiku-4.5PrepBro AI2 апр. 2026 г.(ред.)

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

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

Это один из самых важных и часто неправильно понимаемых терминов в разработке. Правильное разделение бизнес-логики от технической реализации критично для качественной архитектуры.

Определение

Бизнес-логика - это правила и процессы, которые реализуют требования бизнеса. Это СУТЬ приложения, то, чего бизнес хочет достичь.

Технические детали - это ВЫ реализуете бизнес-логику (язык программирования, фреймворк, БД и т.д.)

Примеры из реальной жизни

Пример 1: Система скидок в интернет-магазине

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

  • Покупатели с суммой заказа более 1000 рублей получают скидку 10%
  • Постоянные клиенты (5+ покупок) получают дополнительно 5% скидку
  • Скидки не суммируются с промокодами
  • VIP клиенты получают скидку максимум 30%, даже если условия дают больше
// Бизнес-логика (независима от технологии)
function calculateDiscount(customer: Customer, orderAmount: number): number {
  let discount = 0;

  // Правило 1: скидка за сумму заказа
  if (orderAmount > 1000) {
    discount += 10;
  }

  // Правило 2: скидка за постоянных клиентов
  if (customer.purchaseCount >= 5) {
    discount += 5;
  }

  // Правило 3: максимум для VIP
  if (customer.isVIP && discount > 30) {
    discount = 30;
  }

  return discount;
}

// Техническая реализация (может изменяться)
function applyDiscount(price: number, discountPercent: number): number {
  return price * (1 - discountPercent / 100);
}

// Использование в контроллере
router.post('/checkout', async (req, res) => {
  const customer = await getCustomer(req.user.id);
  const discount = calculateDiscount(customer, req.body.orderAmount);
  const finalPrice = applyDiscount(req.body.orderAmount, discount);
  // ...
});

Пример 2: Система заказов такси

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

  • Водитель может принять заказ только если он online
  • Заказ распределяется среди водителей в порядке:
    1. Ближайший водитель (в пределах 5км)
    2. Если нет - расширяем до 10км
    3. Если нет - отмена с возвратом денег клиенту
  • Цена зависит от расстояния, времени суток и спроса
  • Рейтинг водителя влияет на распределение (лучше рейтинг - выше приоритет)
// Бизнес-логика: алгоритм распределения заказа
function findDriverForOrder(order: Order, drivers: Driver[]): Driver | null {
  // Фильтруем online водителей с рейтингом >= 4.0
  const availableDrivers = drivers.filter(
    d => d.isOnline && d.rating >= 4.0
  );

  // Ищем в радиусе 5км
  let candidates = availableDrivers.filter(
    d => getDistance(d.location, order.pickup) <= 5
  );

  if (candidates.length === 0) {
    // Ищем в радиусе 10км
    candidates = availableDrivers.filter(
      d => getDistance(d.location, order.pickup) <= 10
    );
  }

  if (candidates.length === 0) {
    return null; // Нет водителей - отмена заказа
  }

  // Сортируем: сначала по рейтингу, потом по расстоянию
  candidates.sort((a, b) => {
    if (b.rating !== a.rating) return b.rating - a.rating;
    const distA = getDistance(a.location, order.pickup);
    const distB = getDistance(b.location, order.pickup);
    return distA - distB;
  });

  return candidates[0]; // Выбираем лучшего
}

// Бизнес-логика: расчет стоимости
function calculatePrice(
  distance: number,
  timeOfDay: 'peak' | 'normal',
  demandMultiplier: number
): number {
  const BASE_RATE = 50; // рубли
  const PER_KM = 10;    // рубли за км
  const PEAK_MULTIPLIER = 1.5;

  let price = BASE_RATE + distance * PER_KM;

  if (timeOfDay === 'peak') {
    price *= PEAK_MULTIPLIER;
  }

  price *= demandMultiplier;

  return Math.round(price);
}

// Техническая реализация: получение координат через API
function getDistance(from: Coordinates, to: Coordinates): number {
  // Вызываем Google Maps API
  return calculateHaversineDistance(from, to);
}

// REST API endpoint
router.post('/orders', async (req, res) => {
  const order = createOrder(req.body);
  const driver = findDriverForOrder(order, activeDrivers);
  
  if (!driver) {
    refundCustomer(order.customerId, order.amount);
    return res.status(404).json({ error: 'No drivers available' });
  }
  
  assignOrder(order, driver);
  notifyDriver(driver, order);
});

Слои архитектуры и расположение бизнес-логики

Domain Layer (Слой предметной области)

Это чистая бизнес-логика БЕЗ зависимостей от фреймворков.

// domain/services/OrderService.ts
export class OrderService {
  // Чистая бизнес-логика, никаких импортов Express, React и т.д.
  
  calculateTotal(
    items: OrderItem[],
    discountPercent: number,
    taxRate: number
  ): number {
    const subtotal = items.reduce((sum, item) => sum + item.price * item.qty, 0);
    const withDiscount = subtotal * (1 - discountPercent / 100);
    const total = withDiscount * (1 + taxRate / 100);
    return Math.round(total * 100) / 100;
  }

  canApplyPromoCode(customer: Customer, code: string): boolean {
    if (customer.isBlocked) return false;
    if (code.startsWith('VIP_') && !customer.isVIP) return false;
    return true;
  }

  getNextDeliveryDate(currentDate: Date, deliveryDays: number): Date {
    const next = new Date(currentDate);
    
    // Пропускаем выходные
    let count = 0;
    while (count < deliveryDays) {
      next.setDate(next.getDate() + 1);
      const day = next.getDay();
      if (day !== 0 && day !== 6) { // Не суббота и не воскресенье
        count++;
      }
    }
    
    return next;
  }
}

Application Layer (Слой приложения)

Службы приложения, которые координируют бизнес-логику с технической реализацией.

// application/usecases/CreateOrderUseCase.ts
export class CreateOrderUseCase {
  constructor(
    private orderService: OrderService,
    private orderRepository: OrderRepository,
    private paymentGateway: PaymentGateway,
    private notificationService: NotificationService
  ) {}

  async execute(command: CreateOrderCommand): Promise<Order> {
    // Validate
    if (!command.items || command.items.length === 0) {
      throw new ValidationError('Cart is empty');
    }

    // Применяем бизнес-логику (расчет стоимости)
    const total = this.orderService.calculateTotal(
      command.items,
      command.discountPercent,
      TAX_RATE
    );

    // Сохраняем в БД
    const order = await this.orderRepository.create({
      customerId: command.customerId,
      items: command.items,
      total,
      status: 'pending'
    });

    // Обрабатываем платеж
    try {
      const payment = await this.paymentGateway.charge(total);
      order.paymentId = payment.id;
      order.status = 'paid';
      await this.orderRepository.update(order);
    } catch (error) {
      order.status = 'failed';
      await this.orderRepository.update(order);
      throw error;
    }

    // Уведомляем клиента
    await this.notificationService.sendOrderConfirmation(order);

    return order;
  }
}

Presentation Layer (Слой представления)

Управление UI, получение ввода пользователя, вызов use cases.

// presentation/pages/CheckoutPage.tsx
export function CheckoutPage() {
  const [items, setItems] = useState<OrderItem[]>([]);
  const [discount, setDiscount] = useState(0);
  const createOrderUseCase = useCreateOrderUseCase();

  const handleSubmit = async (e: React.FormEvent) => {
    e.preventDefault();
    
    try {
      // Вызываем use case (бизнес-логика)
      const order = await createOrderUseCase.execute({
        items,
        discountPercent: discount,
        customerId: getCurrentUserId()
      });
      
      // Обновляем UI после успеха
      showSuccess(`Order #${order.id} created`);
      navigate(`/orders/${order.id}`);
    } catch (error) {
      showError(error.message);
    }
  };

  return (
    <form onSubmit={handleSubmit}>
      <CartItems items={items} onChange={setItems} />
      <DiscountInput value={discount} onChange={setDiscount} />
      <button type="submit">Checkout</button>
    </form>
  );
}

Признаки, что бизнес-логика в неправильном месте

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

// Компонент смешивает UI и бизнес-логику - ПЛОХО
function ShoppingCart({ items }) {
  const [total, setTotal] = useState(0);

  useEffect(() => {
    // Это бизнес-логика, не место здесь!
    let sum = 0;
    items.forEach(item => {
      let discount = 0;
      if (item.quantity > 10) discount = 0.1;
      if (item.category === 'electronics') discount = 0.05;
      
      const price = item.basePrice * (1 - discount);
      const tax = price * 0.18;
      sum += (price + tax) * item.quantity;
    });
    setTotal(sum);
  }, [items]);

  return <div>Total: {total}</div>;
}

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

// business/services/CartService.ts
export class CartService {
  calculateTotal(items: CartItem[]): number {
    return items.reduce((sum, item) => {
      const discount = this.getDiscount(item);
      const price = item.basePrice * (1 - discount);
      const tax = price * TAX_RATE;
      return sum + (price + tax) * item.quantity;
    }, 0);
  }

  private getDiscount(item: CartItem): number {
    if (item.quantity > 10) return 0.1;
    if (item.category === 'electronics') return 0.05;
    return 0;
  }
}

// presentation/components/ShoppingCart.tsx
function ShoppingCart({ items }) {
  const cartService = useCartService();
  const total = useMemo(
    () => cartService.calculateTotal(items),
    [items, cartService]
  );

  return <div>Total: {total}</div>;
}

Преимущества правильного разделения

1. Переиспользуемость

// OrderService можно использовать везде:
- REST API (Express/FastAPI)
- GraphQL API
- WebSocket handlers
- Очереди сообщений (RabbitMQ/Kafka)
- CLI команды
- Batch процессы

2. Тестируемость

// Тестируем бизнес-логику БЕЗ браузера, БЕЗ сервера
test('calculateTotal should apply discounts', () => {
  const service = new OrderService();
  const items = [{ price: 100, qty: 15, category: 'electronics' }];
  const total = service.calculateTotal(items, 10, 18); // discount, tax
  expect(total).toBe(expectedValue);
});

3. Понятность

// Код читается как описание бизнес-требований
function qualifyForLoan(applicant: Applicant): boolean {
  // Заёмщик должен быть старше 21
  if (applicant.age < 21) return false;
  
  // Зарплата должна быть минимум в 5 раз выше платежа
  if (applicant.salary < monthlyPayment * 5) return false;
  
  // Кредитная история должна быть хорошей
  if (applicant.creditScore < 700) return false;
  
  return true;
}

4. Независимость от технологий

// Если нужно заменить Express на Fastify - бизнес-логика не изменится
// Если нужно заменить PostgreSQL на MongoDB - бизнес-логика не изменится
// Если нужно добавить GraphQL - бизнес-логика не изменится

Заключение

Бизнес-логика - это СУТЬ приложения, то ради чего вы его пишете. Она должна быть:

  1. Отделена от технических деталей
  2. Независима от фреймворков и БД
  3. Тестируема без браузера и сервера
  4. Понятна даже тому, кто не знает код
  5. Переиспользуема в разных контекстах

Правильное разделение бизнес-логики и технической реализации - это признак профессиональной архитектуры и основа масштабируемых приложений.