Releases: r1natt/vk_social_graph
Refactoring
Цели рефакторинга заключались в создании устойчивой, расширяемой и легко поддерживаемой архитектуры проекта. Для этого были реализованы следующие подходы:
1. Максимальное соответствие принципам SOLID
SOLID включает в себя 5 основных принципов, которые были описаны Робертом Мартиным. Подход чистого кода подразумевает простой подход к дополнению и обслуживанию написанного ПО (по его задумке).
Данный рефакторинг частично выполнялся с отсылкой на книгу "Чистый код", чтобы дальнейшее дополнение существующего кода проходила быстрее и эффективнее.
2. Разделение на модули
Кодовая база структурирована по смысловым модулям:
- запросы (utils/reqs.py).
- работа с базой данных (db/).
- парсинг (service/), включает в себя парсинг вк и составление графа.
3. Обдуманный выбор имён
Особое внимание уделялось выбору имён для модулей, классов, функций и переменных.
Имена отражают суть и назначение сущностей.
Подробнее про каждую логику
Модели данных и обмен информацией между модулями
В проекте реализован новый подход к обмену данными между модулями. Для этого используются следующие инструменты:
- Pydantic-модели
Все основные структуры данных (ответы API, записи в базе) описаны через pydantic-модели (BaseResponse, FriendsResponse, UserResponse, BaseRecord, FriendsRecord, UserRecord).
- Dataclass
Для описания структур, связанных с обработкой ошибок и ответов API (например, APIError, APIResponse), используются dataclass.
Это облегчило создание простых контейнеров данных с минимальным количеством кода.
- Enum
Для определения констант, статусов, типов запросов и ресурсов API применяются перечисления (Enum, IntEnum).
Это делает код более читаемым, защищает от ошибок, связанных с "магическими строками" и числами, и облегчает поддержку.
Модуль запросов (utils/reqs.py)
Архитектура и принципы
Модуль построен на принципах разделения ответственности. Вся логика работы с запросами к VK API инкапсулирована в отдельные абстракции, что обеспечивает расширяемость, тестируемость и простоту поддержки.
Основные компоненты
1. Абстракции и интерфейсы
- RequestTracker / SynchronousRequestTracker
Абстракция и синхронная реализация трекера частоты запросов (RPS).
Вместо отдельного процесса (как было с TPS bucket), теперь лимит запросов реализован через очередь с временными метками прямо в основном процессе.
Это упрощает архитектуру и устраняет накладные расходы на межпроцессное взаимодействие.
- ErrorClassifier / VKAPIErrorClassifier
Абстрактный и конкретный классы для классификации ошибок VK API по степени критичности и возможности повторной попытки.
Это позволяет централизованно управлять обработкой ошибок и легко расширять логику при необходимости.
- ResponseParser / JSONResponseParser
Интерфейс и реализация для парсинга HTTP-ответов.
Позволяет отделить логику разбора ответа от остального кода, что облегчает тестирование и замену формата ответа.
- RetryStrategy / ExponentialBackoffRetryStrategy
Интерфейс и реализация стратегии повторных попыток с экспоненциальной задержкой.
Позволяет гибко управлять политикой повторов при ошибках.
2. Клиенты и интерфейсы
- APIClient
Универсальный клиент для выполнения HTTP-запросов с поддержкой трекинга RPS, обработки ошибок, повторных попыток и парсинга ответов.
Все зависимости внедряются через конструктор.
- VKAPIClient
Специализированный клиент для VK API, использующий все вышеописанные абстракции.
Инкапсулирует базовый URL, параметры авторизации и версию API.
- VKAPIInterface / VKAPICodeInterface
Высокоуровневые интерфейсы для работы с VK API: получение друзей, пользователей, а также выполнение кода на VKScript через метод execute.
Используют конвертеры для преобразования ответов в pydantic-модели.
- APIResponseToPydanticConverter
Класс для преобразования "сырых" ответов API в pydantic-модели (FriendsResponse, UserResponse), что облегчает дальнейшую работу с данными.
Ограничение частоты запросов (RPS/TPS)
Практически все API имеют лимит запросов за промежуток времени.
Ранее для ограничения частоты запросов использовался отдельный процесс с TPS bucket (Token Bucket), что приводило к дополнительным накладным расходам на межпроцессное взаимодействие.
Теперь реализован синхронный RPS tracker, который отслеживает количество запросов непосредственно в основном процессе.
Такой подход упрощает архитектуру и делает поведение системы более предсказуемым.
Итоги
В результате модуль стал легко расширяемым, тестируемым и соответствующим современным архитектурным стандартам.
Запросы были переработаны с учетом принципов SOLID. Ответственность разделена между абстрактными базовыми классами и конкретными реализациями, каждая из которых отвечает только за свою зону ответственности.
Теперь добавление новых типов запросов или изменение логики не затрагивает остальной код, что соответствует принципу открытости/закрытости.
Вся логика работы с запросами стала более атомарной и расширяемой.
Работа с базой данных (db/db.py)
Основные компоненты
- MongoMethods
Ранее вся работа парсера с бд осуществлялась через единый класс, в котором были методы ко всем коллекциям. Сейчас операции с коллекциями выделены в отдельный объект MongoMethods, а все функции более высокого уровня выделены в отдельные объекты, которые наследуются от MongoMethods.
- Коллекции данных (
FriendsCollection,UserCollection)
FriendsCollection
Класс для работы с коллекцией друзей пользователя.
-
Поддерживает политику обновления: если включена, обновляет существующую запись, иначе создает новую.
-
Ведет историю посещений и отслеживает изменения в списке друзей (добавление, удаление, восстановление).
-
Логика обновления реализована через отдельные методы для вычисления восстановленных и удалённых друзей, а также для фиксации новых визитов.
UserCollection
Класс для работы с коллекцией пользователей.
-
Сохраняет новых пользователей, если их еще нет в базе.
-
Ведет историю посещений пользователя.
- Фабрика коллекций
Класс-фабрика для создания экземпляров коллекций (FriendsCollection, UserCollection) с нужными параметрами (например, политика обновления, период обновления).
- Позволяет централизованно управлять созданием и сбросом коллекций.
- Поддерживает возможность сброса всех коллекций (например, для тестирования или инициализации).
Парсинг и обход графа (service/)
Раньше для парсинга и обхода графа использовалась рекурсивная реализация. Такой подход затруднял отслеживание состояния обхода, усложнял отладку, сопровождение и масштабирование алгоритма (особенно при глубоком обходе из-за риска переполнения стека).
Теперь реализован отдельный модуль с универсальным алгоритмом обхода графа (BFS — поиск в ширину), который инкапсулирован в абстрактном классе и его наследниках.
Это позволило явно контролировать очередь обхода и посещённые вершины, расширять и переиспользовать алгоритм для разных задач (парсинг, построение графа для визуализации и т.д.);
Основные компоненты
- Алгоритм обхода графа (service/graph_search.py)
- GraphSearch (ABC):
Абстрактный базовый класс для реализации различных стратегий обхода графа.
- BFS:
Класс реализует обход графа в ширину с помощью приоритетной очереди и явного хранения посещённых вершин.
Метод search принимает стартовый VK ID и максимальную глубину обхода, а также вызывает абстрактный метод action для обработки каждой вершины.
Такой подход позволяет реализовать различные сценарии обхода, не меняя сам алгоритм.
- UserTask:
Структура для хранения информации о текущей задаче обхода (ID пользователя и глубина обхода).
- Парсер данных (service/parser.py)
- VKParser (наследник BFS):
Класс для парсинга данных о пользователях и их друзьях с помощью обхода графа.
-
Использует интерфейсы для работы с запросами и коллекциями БД.
-
В методе action для каждой вершины (пользователя) получает и сохраняет информацию о пользователе и его друзьях.
-
Логика получения и сохранения данных инкапсулирована в отдельных методах (get_user, get_friends).
Такой подход позволяет легко модифицировать стратегию парсинга, не затрагивая сам алгоритм обхода.
- Формирование графа для визуализации (service/gephi.py)
- GexfGraph (наследник BFS):
Класс для построения графа пользователей и их связей с последующим экспортом в форматы, поддерживаемые Gephi (GEXF, GML, GraphML).
-
В методе action для каждой вершины добавляет узел и рёбра в граф, используя данные из БД.
-
Реализованы методы для фильтрации узлов по степени, задания цвета в зависимости от расстояния, и сохранения графа в файл.
Такой подход позволяет быстро и гибко формировать графы для анализа и визуализации.
First release!
This the first release with minimal functional of save friends relationships and creating graph of user relations