Эволюционная архитектура в Python

Эволюционная архитектура в Python


Что такое эволюционная архитектура?

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

Основные принципы

1. Постепенное развитие

Архитектура меняется небольшими шагами, а не большими скачками.

2. Независимость компонентов

Компоненты системы слабо связаны и могут развиваться отдельно.

3. Автоматизированное тестирование

Тесты обеспечивают безопасность изменений.

Практическая реализация в Python

Модульная структура проекта

my_project/
├── src/
│   ├── users/
│   │   ├── __init__.py
│   │   ├── models.py
│   │   └── services.py
│   ├── orders/
│   │   ├── __init__.py
│   │   └── models.py
│   └── shared/
│       ├ __init__.py
│       └── database.py
├── tests/
└── requirements/

Пример: эволюция сервиса пользователей

Версия 1.0 — простой подход

# users/services.py (начальная версия)
class UserService:
    def create_user(self, username, password):
        # Простая логика создания пользователя
        user = User(username=username)
        user.set_password(password)
        user.save()
        return user

Версия 2.0 — добавляем валидацию

# users/services.py (улучшенная версия)
class UserService:
    def __init__(self, email_service=None):
        self.email_service = email_service
    
    def create_user(self, username, password, email=None):
        # Добавляем валидацию без ломания старого API
        self._validate_user_data(username, password, email)
        
        user = User(username=username, email=email)
        user.set_password(password)
        user.save()
        
        if email and self.email_service:
            self.email_service.send_welcome_email(email)
        
        return user
    
    def _validate_user_data(self, username, password, email):
        if len(username) < 3:
            raise ValueError("Username too short")
        # Дополнительная валидация...

Использование абстракций

from abc import ABC, abstractmethod

# Абстракция для хранилища пользователей
class UserRepository(ABC):
    @abstractmethod
    def save(self, user):
        pass
    
    @abstractmethod
    def find_by_id(self, user_id):
        pass

# Реализация для базы данных
class DatabaseUserRepository(UserRepository):
    def save(self, user):
        # Реализация для SQL базы
        pass
    
    def find_by_id(self, user_id):
        # Реализация для SQL базы
        pass

# Реализация для in-memory хранилища (для тестов)
class InMemoryUserRepository(UserRepository):
    def __init__(self):
        self.users = {}
    
    def save(self, user):
        self.users[user.id] = user
    
    def find_by_id(self, user_id):
        return self.users.get(user_id)

Конфигурация и зависимости

# config/dependencies.py
class Container:
    def __init__(self):
        self._services = {}
    
    def register(self, name, service):
        self._services[name] = service
    
    def resolve(self, name):
        return self._services[name]()

# Настройка зависимостей
container = Container()
container.register('user_repository', lambda: DatabaseUserRepository())
container.register('email_service', lambda: SMTPEmailService())

# Использование в сервисе
class UserService:
    def __init__(self, container):
        self.user_repository = container.resolve('user_repository')
        self.email_service = container.resolve('email_service')

Стратегии эволюционного развития

1. Strangler Fig Pattern

Постепенная замена старой системы новой:

# Старый код
def process_order_legacy(order_data):
    # Старая логика
    pass

# Новый код
def process_order_new(order_data):
    # Новая улучшенная логика
    pass

# Фасад, который направляет трафик
def process_order(order_data):
    if self.use_new_system(order_data):
        return process_order_new(order_data)
    else:
        return process_order_legacy(order_data)

2. Feature Flags

# features.py
class FeatureFlags:
    def __init__(self):
        self.flags = {
            'new_payment_system': False,
            'advanced_analytics': True
        }
    
    def is_enabled(self, feature_name):
        return self.flags.get(feature_name, False)

# Использование
flags = FeatureFlags()

def process_payment(order):
    if flags.is_enabled('new_payment_system'):
        return new_payment_processor(order)
    else:
        return legacy_payment_processor(order)

Тестирование эволюционной архитектуры

# tests/test_user_service.py
import pytest
from users.services import UserService
from users.repositories import InMemoryUserRepository

class TestUserService:
    def test_create_user(self):
        # Используем in-memory репозиторий для изоляции тестов
        repository = InMemoryUserRepository()
        service = UserService(user_repository=repository)
        
        user = service.create_user("testuser", "password")
        
        assert user.username == "testuser"
        assert repository.find_by_id(user.id) == user

Миграция данных

# migrations/migration_v1_to_v2.py
class DataMigration:
    def migrate_users_to_new_schema(self):
        # Постепенная миграция пользователей
        old_users = OldUser.objects.all()
        
        for old_user in old_users:
            new_user = NewUser(
                username=old_user.username,
                email=old_user.email,
                # преобразование данных...
            )
            new_user.save()

Лучшие практики

  1. Соблюдайте принцип открытости/закрытости — классы должны быть открыты для расширения, но закрыты для модификации
  2. Используйте инъекцию зависимостей — это делает код более тестируемым и гибким
  3. Пишите миграции для данных — изменения схемы данных должны быть обратимыми
  4. Мониторьте производительность — используйте метрики для отслеживания влияния изменений
  5. Документируйте изменения — ведите историю эволюции архитектуры

Заключение

Эволюционная архитектура в Python — это не конкретная технология, а подход к проектированию, который позволяет вашей системе расти и адаптироваться. Начиная с простой структуры и постепенно усложняя её по мере необходимости, вы создаёте устойчивую к изменениям систему, которая может развиваться вместе с вашим бизнесом.

Ключевой вывод: проектируйте не на годы вперёд, а с возможностью легко изменяться завтра.