Transaction Script

Простая бизнес-логика в процедурах

Что такое Transaction Script?

Transaction Script — паттерн, при котором бизнес-логика организована в виде процедур (скриптов), каждая из которых обрабатывает одну транзакцию или запрос.

🔹 Transaction Script vs Domain Model

# Transaction Script — процедурный подход
def create_user(name: str, email: str):
    # Валидация
    if not name:
        raise ValueError("Name is required")
    if "@" not in email:
        raise ValueError("Invalid email")
    
    # Сохранение
    db.execute("INSERT INTO users (name, email) VALUES (?, ?)", (name, email))
    return {"status": "created"}

# Domain Model — объектно-ориентированный подход
class User:
    def __init__(self, name: str, email: Email):
        self.name = name
        self.email = email
    
    def save(self):
        db.execute("INSERT INTO users (name, email) VALUES (?, ?)", 
                   (self.name, self.email.address))

🔹 Когда использовать Transaction Script?

  • Простая бизнес-логика — нет сложных правил
  • Быстрая разработка — нужно быстро создать прототип
  • Простые CRUD операции — создание, чтение, обновление, удаление
  • Небольшие приложения — простая система
  • Сложная бизнес-логика — лучше Domain Model

Примеры Transaction Script

🔹 Простой Transaction Script

# user_script.py
def create_user(name: str, email: str, password: str):
    # Валидация
    if not name:
        raise ValueError("Name is required")
    if "@" not in email:
        raise ValueError("Invalid email")
    if len(password) < 8:
        raise ValueError("Password must be at least 8 characters")
    
    # Проверка существования
    existing = db.fetch_one("SELECT id FROM users WHERE email = ?", (email,))
    if existing:
        raise ValueError("User already exists")
    
    # Создание
    user_id = db.execute(
        "INSERT INTO users (name, email, password_hash) VALUES (?, ?, ?) RETURNING id",
        (name, email, hash_password(password))
    )
    
    return {"user_id": user_id, "status": "created"}

def get_user(user_id: int):
    row = db.fetch_one("SELECT * FROM users WHERE id = ?", (user_id,))
    if not row:
        raise ValueError("User not found")
    return {
        "id": row['id'],
        "name": row['name'],
        "email": row['email']
    }

🔹 Transaction Script с классами

class UserService:
    def create_user(self, name: str, email: str, password: str):
        # Валидация
        self._validate_user(name, email, password)
        
        # Проверка существования
        if self._user_exists(email):
            raise ValueError("User already exists")
        
        # Создание
        user_id = self._save_user(name, email, password)
        
        # Побочные эффекты
        self._send_welcome_email(email)
        
        return {"user_id": user_id, "status": "created"}
    
    def _validate_user(self, name: str, email: str, password: str):
        if not name:
            raise ValueError("Name is required")
        if "@" not in email:
            raise ValueError("Invalid email")
        if len(password) < 8:
            raise ValueError("Password must be at least 8 characters")
    
    def _user_exists(self, email: str) -> bool:
        row = db.fetch_one("SELECT id FROM users WHERE email = ?", (email,))
        return row is not None
    
    def _save_user(self, name: str, email: str, password: str) -> int:
        return db.execute(
            "INSERT INTO users (name, email, password_hash) VALUES (?, ?, ?) RETURNING id",
            (name, email, hash_password(password))
        )
    
    def _send_welcome_email(self, email: str):
        email_service.send(email, "Welcome!", "Welcome to our service!")

Преимущества Transaction Script

  • Простота — легко понять и написать
  • Быстрая разработка — быстро создать прототип
  • Нет overhead — нет лишних слоёв абстракции
  • Прямолинейность — логика в одном месте

Недостатки Transaction Script

  • Дублирование кода — логика может дублироваться
  • Сложность поддержки — сложно поддерживать при росте
  • Тестируемость — сложнее тестировать
  • Переиспользование — сложнее переиспользовать логику

💡 Когда использовать Transaction Script?

Сценарий Рекомендация
Простой CRUD ✅ Подходит
Прототип/MVP ✅ Подходит
Скрипты ✅ Подходит
Сложная бизнес-логика ❌ Используйте Domain Model
Долгосрочный проект ⚠️ Рассмотрите Domain Model

🎯 Transaction Script vs Domain Model

Критерий Transaction Script Domain Model
Сложность Низкая Высокая
Скорость разработки Быстро Медленнее
Поддержка Сложнее Проще
Тестируемость Сложнее Проще
Использование Простые случаи Сложные случаи
"Transaction Script — это не про сложность. Это про простоту.
Используйте его для простых случаев, но не бойтесь перейти к Domain Model, когда бизнес-логика усложняется."