← Назад к вопросам
В чем разница между доменной сложностью и привнесённой?
2.0 Middle🔥 121 комментариев
#Архитектура и паттерны
Комментарии (1)
🐱
claude-haiku-4.5PrepBro AI22 мар. 2026 г.(ред.)
Ответ сгенерирован нейросетью и может содержать ошибки
Разница между доменной сложностью и привнесённой сложностью
Это важный концепт для архитектуры ПО и принятия технических решений. На русском часто называют "врождённой" и "случайной" сложностью (из книги "No Silver Bullet" Фреда Брукса).
Быстрый ответ
Доменная сложность (Essential Complexity):
- Сложность САМОЙ ПРОБЛЕМЫ
- Это неизбежно, нельзя избежать
- Нужно решить её, чтобы получить результат
- Пример: спроектировать микрочип с 10 млрд транзисторов
Привнесённая сложность (Accidental Complexity):
- Сложность РЕШЕНИЯ (как мы решаем)
- Это можно и нужно избегать
- Результат плохого дизайна, выбора технологий, процессов
- Пример: использование 50 разных framework'ов для одного проекта
1. Определение доменной сложности (Essential)
Это сложность, которая НЕОТЪЕМЛЕМА от проблемы, которую мы решаем.
# Пример 1: e-commerce платформа
# Доменная сложность включает:
# - Инвентарь товаров (нужно отслеживать кол-во)
# - Заказы (нужно управлять жизненный цикл)
# - Платежи (нужна интеграция с платёжными системами)
# - Доставка (координация с логистикой)
# - Возвраты (обработка возвратов)
# - Налоги (разные налоги в разных странах)
# Это сложность самого бизнеса, не способа реализации!
class Product:
def __init__(self, name, price, quantity):
self.name = name
self.price = price
self.quantity = quantity
class Order:
def __init__(self, user_id, items):
self.user_id = user_id
self.items = items # list[Product]
self.status = "pending"
def calculate_total(self):
return sum(item.price * qty for item, qty in self.items)
def apply_taxes(self, tax_rate):
return self.calculate_total() * (1 + tax_rate)
def process_payment(self, payment_info):
# Интеграция с платёжной системой
pass
def arrange_shipping(self, address):
# Интеграция с логистикой
pass
# Эта сложность НЕИЗБЕЖНА - нужно её решить
# Пример 2: система рекомендаций
# Доменная сложность:
# - Алгоритм вычисления схожести (рекомендация похожих товаров)
# - Учёт истории пользователя
# - A/B тестирование рекомендаций
# - Обработка cold-start problem (новые пользователи)
# - Масштабирование на миллионы товаров
# Эта сложность присуща самой проблеме рекомендаций
2. Определение привнесённой сложности (Accidental)
Это сложность, которая мы САМИ добавили, выбирая неправильные инструменты или подход.
# Пример 1: использование неправильного инструмента
# Привнесённая сложность:
# ❌ ПЛОХО: использовать Excel для БД с миллионом строк
# - Открывать файл 30 секунд
# - Медленные вычисления
# - Нет поддержки конкурентного доступа
# - Нет backup'ов
# ✅ ПРАВИЛЬНО: использовать PostgreSQL
# Убирает привнесённую сложность! (но доменная остаётся)
# Пример 2: плохая архитектура
# ❌ ПЛОХО: написать всё в одном файле (monolith)
app.py (5000 строк):
- HTTP handlers
- Business logic
- Database queries
- Email sending
- Payment processing
- File uploads
- Authentication
# Невозможно понять какой класс за что отвечает
# Привнесённая сложность!
# ✅ ПРАВИЛЬНО: разделить по слоям (clean architecture)
app/
├── presentation/ # HTTP interface
├── application/ # Business logic
├── domain/ # Models
└── infrastructure/ # Database, emails, payments
# Проще ориентироваться, тестировать, масштабировать
# Убирает привнесённую сложность!
# Пример 3: неправильные зависимости
# ❌ ПЛОХО: зависимость от внешней библиотеки для простой функции
from heavy_library import calculate_age
def get_user_age(birth_date):
return calculate_age(birth_date) # Простая функция требует huge библиотеку
# ✅ ПРАВИЛЬНО: написать самому
def get_user_age(birth_date):
from datetime import date
return (date.today() - birth_date).days // 365
# Убрали привнесённую сложность! (и зависимость)
3. Визуальное сравнение
┌─────────────────────────────────────────────────────┐
│ Доменная сложность (Essential) │
│ │
│ - Требования бизнеса │
│ - Алгоритмы для решения проблемы │
│ - Трудные математические задачи │
│ - Правила бизнес-логики │
│ - Невозможно избежать │
│ - ДОЛЖНЫ решить её, чтобы доставить ценность │
└─────────────────────────────────────────────────────┘
ВНА ВЫПОЛНЕННОГО ПРОЕКТА (100%)
= Доменная сложность (50-70%)
+ Привнесённая сложность (30-50%)
Хороший архитект минимизирует привнесённую!
┌─────────────────────────────────────────────────────┐
│ Привнесённая сложность (Accidental) │
│ │
│ - Плохой выбор технологий │
│ - Плохая архитектура │
│ - Дублирование кода │
│ - Неправильные зависимости │
│ - Технический долг │
│ - МОЖНО избежать │
│ - Результат плохого дизайна │
└─────────────────────────────────────────────────────┘
4. Примеры в реальном коде
Пример 1: Система учёта сотрудников
# ДОМЕННАЯ сложность (обязательна):
# - Расчёт зарплаты с налогами
# - Управление отпусками
# - Отслеживание часов работы
# - Управление льготами
# Это сложность самого бизнеса!
class PayrollCalculator:
def calculate_salary(self, employee, hours_worked, overtime_hours):
base_pay = employee.hourly_rate * hours_worked
overtime_pay = employee.hourly_rate * 1.5 * overtime_hours
gross_salary = base_pay + overtime_pay
# Налоги зависят от страны/штата
taxes = self._calculate_taxes(gross_salary, employee.tax_bracket)
benefits_deduction = self._calculate_benefits(employee.benefits)
net_salary = gross_salary - taxes - benefits_deduction
return {
'gross': gross_salary,
'taxes': taxes,
'benefits': benefits_deduction,
'net': net_salary
}
def _calculate_taxes(self, salary, tax_bracket):
# Сложная логика с льготами и прогрессивными налогами
pass
def _calculate_benefits(self, benefits):
# Вычисление вычитаемых льгот
pass
# ПРИВНЕСЁННАЯ сложность (можно избежать):
# ❌ ПЛОХО: использовать Excel
# ❌ ПЛОХО: писать SQL запросы в HTML файлах
# ❌ ПЛОХО: хранить данные в CSV
# ✅ ПРАВИЛЬНО: использовать БД + API + структурированный код
Пример 2: Микросервисная архитектура
# ДОМЕННАЯ сложность:
# - Обработка заказов (сложный бизнес-процесс)
# - Управление инвентарём
# - Интеграция платежей
class OrderService:
def create_order(self, items, user_id):
# Доменная сложность: проверка наличия товара
inventory = self.check_inventory(items)
if not inventory:
raise OutOfStockError()
# Доменная сложность: расчёт доставки
shipping_cost = self.calculate_shipping(items, user.address)
# Доменная сложность: обработка платежа
payment = self.process_payment(items, shipping_cost)
order = Order.create(items, payment)
return order
# ПРИВНЕСЁННАЯ сложность (можно минимизировать):
# ❌ ПЛОХО: микросервисная архитектура для маленького проекта
# ❌ ПЛОХО: использовать 5 разных языков программирования
# ❌ ПЛОХО: распределённые транзакции через RabbitMQ
# ✅ ПРАВИЛЬНО: monolith с хорошей архитектурой
# Привнесённая сложность растёт с каждым микросервисом:
# - Сетевые задержки
# - Распределённые транзакции
# - Версионирование API
# - Мониторинг
# Это не надо добавлять, если доменная сложность это не требует!
5. Как минимизировать привнесённую сложность
# 1. YAGNI (You Aren't Gonna Need It)
# ❌ ПЛОХО: добавлять функции "на будущее"
class User:
def __init__(self, name, email):
self.name = name
self.email = email
self.bio = None
self.phone = None
self.address = None
self.preferences = {}
self.settings = {}
self.metadata = {}
# 50 полей, которые "может быть понадобятся"
# Привнесённая сложность!
# ✅ ПРАВИЛЬНО: добавлять только нужное
class User:
def __init__(self, name, email):
self.name = name
self.email = email
# Добавим потом, когда понадобится
# 2. DRY (Don't Repeat Yourself)
# ❌ ПЛОХО: одна логика в 10 местах
def validate_email_1():
return '@' in email and '.' in email.split('@')[1]
def validate_email_2():
return '@' in email and '.' in email.split('@')[1]
def validate_email_3():
return '@' in email and '.' in email.split('@')[1]
# ✅ ПРАВИЛЬНО: одна функция
def validate_email(email: str) -> bool:
return '@' in email and '.' in email.split('@')[1]
# 3. Правильный выбор инструментов
# ❌ ПЛОХО: использовать GraphQL когда нужен REST
# ❌ ПЛОХО: использовать MongoDB для реляционных данных
# ✅ ПРАВИЛЬНО: выбрать инструмент по задаче
# 4. Clean Code
# ❌ ПЛОХО: имена переменных x, y, z
for x in users:
if x[5] > 100:
y.append(x[0])
# ✅ ПРАВИЛЬНО: понятные имена
for user in users:
if user['balance'] > 100:
premium_users.append(user['id'])
# 5. Тестируемость
# ❌ ПЛОХО: всё намешано в одном классе
class UserService:
def register_user(self, email):
# HTTP запрос
# Парсинг JSON
# Валидация
# Сохранение в БД
# Отправка email
# Логирование
# Все вместе - невозможно тестировать!
# ✅ ПРАВИЛЬНО: разделить на слои
class RegisterUserUseCase:
def execute(self, email: str) -> User: # Только бизнес-логика
pass
@app.post('/register')
def register_endpoint(request): # Только HTTP
pass
6. Когда привнесённая сложность оправдана
# Иногда стоит добавить привнесённую сложность, чтобы:
# 1. Миграция на лучший инструмент
# ❌ Старо: Python 2
# ✅ Ново: Python 3
# Это добавляет временную привнесённую сложность
# Но окупается долгосрочно
# 2. Масштабирование требует архитектуры
# ❌ Монолит достаточен для 1000 пользователей
# ✅ Микросервисы нужны для 1 млн пользователей
# Добавляем привнесённую сложность потому что доменная требует масштаба
# 3. Требования безопасности
# ❌ Простая аутентификация для локального приложения
# ✅ OAuth, 2FA для production
# Добавляем сложность потому что бизнес требует
# Правило: добавляй привнесённую сложность ТОЛЬКО если она решает реальную доменную проблему
7. Как определить, какая сложность где
# Вопрос 1: "Нужно ли это для решения проблемы?"
# ДА → Доменная сложность (нужна)
# НЕТ → Привнесённая сложность (убери)
# Вопрос 2: "Это требование бизнеса?"
# ДА → Доменная
# НЕТ → Привнесённая (возможно убрать)
# Вопрос 3: "Может ли быть проще?"
# ДА → Привнесённая (упростить!)
# НЕТ → Доменная (необходимо)
# Пример: e-commerce
# "Нужно подерживать 10 валют" → Доменная (бизнес требует)
# "Написать на 5 языках программирования" → Привнесённая (выбери 1)
# "Сложные алгоритмы рекомендаций" → Доменная (бизнес требует)
# "Использовать самый новый framework" → Привнесённая (выбери проверенный)
8. Практическое применение
# Архитектурное решение:
# На день 1: Минимальное решение
# - Монолит на Flask
# - PostgreSQL
# - Простые endpoints
# Минимум привнесённой сложности!
app = Flask(__name__)
@app.route('/users', methods=['POST'])
def create_user():
email = request.json['email']
if not validate_email(email):
return {'error': 'Invalid email'}, 400
user = User(email=email)
db.session.add(user)
db.session.commit()
return {'id': user.id}, 201
# На день 100: Когда доменная сложность требует масштаба
# - Микросервисы
# - Message queues
# - Caching
# - Мониторинг
# Добавляем привнесённую сложность потому что масштаб требует
# НО! Только когда действительно нужно!
9. Вывод
Доменная сложность (Essential):
- Неизбежна
- Это сложность самой проблемы
- Должна быть решена
- Пример: расчёт налогов в e-commerce
Привнесённая сложность (Accidental):
- Результат наших выборов
- Должна быть МИНИМИЗИРОВАНА
- Пример: использование 5 framework'ов для одного проекта
Правило архитектора:
Минимизируй привнесённую сложность
Концентрируйся на доменной сложности
Добавляй сложность только когда она решает реальную проблему
Цитата Фреда Брукса:
"Нет серебряной пули. Нельзя побороть доменную сложность, но можно минимизировать привнесённую."
Хороший разработчик знает разницу и выбирает инструменты, которые минимизируют привнесённую сложность, позволяя сконцентрироваться на доменной!