Эволюционная архитектура в 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()
Лучшие практики
- Соблюдайте принцип открытости/закрытости — классы должны быть открыты для расширения, но закрыты для модификации
- Используйте инъекцию зависимостей — это делает код более тестируемым и гибким
- Пишите миграции для данных — изменения схемы данных должны быть обратимыми
- Мониторьте производительность — используйте метрики для отслеживания влияния изменений
- Документируйте изменения — ведите историю эволюции архитектуры
Заключение
Эволюционная архитектура в Python — это не конкретная технология, а подход к проектированию, который позволяет вашей системе расти и адаптироваться. Начиная с простой структуры и постепенно усложняя её по мере необходимости, вы создаёте устойчивую к изменениям систему, которая может развиваться вместе с вашим бизнесом.
Ключевой вывод: проектируйте не на годы вперёд, а с возможностью легко изменяться завтра.