У меня был старый скрипт синхронизации VirtueMart с VK Market. Написанный очень давно, он работал неплохо, но с одним огромным недостатком — он был очень медленным. Скрипт обновлял товары целиком, даже если ничего не менялось. Синхронизация всех товаров могла занимать более 30 минут.
В какой-то момент стало понятно, что без серьёзной доработки не обойтись. Первые два дня я добавлял новую логику: обработку остатков, работу с ценами, загрузку изображений. Но код разросся до совершенно неприемлемого размера. В одном файле было больше 1700 строк — анализировать и отлаживать это стало невозможно.
Тогда пришла мысль о рефакторинге. И это решение помогло не только навести порядок в коде, но и разобраться с множеством проблем, которые копились годами.
Проблемы старого скрипта
1. Медленная работа
Скрипт обновлял все товары целиком, даже если ничего не изменилось. Это приводило к огромному количеству лишних запросов к VK API и к долгой синхронизации.
2. Монолитная структура
Весь код был в одном файле. Одна функция делала всё: подключалась к БД, выполняла запросы, загружала фото, обновляла товары. Найти ошибку в такой структуре было почти невозможно.
3. Нет контроля изменений
Скрипт не умел определять, что именно изменилось в товаре. В результате обновлялись все поля, даже те, которые не менялись.
4. Проблемы с API VK
Со временем VK изменил свой API, и скрипт перестал корректно работать. Например, поле stock_amount перестало возвращаться в массовых запросах, а old_price стал храниться внутри price.
5. Сложность анализа
Когда код разросся до 1700+ строк, понять логику его работы стало невозможно. Любое изменение могло сломать что-то в другом месте.
Первые два дня: добавление логики
Первые два дня я пытался просто добавить логику в существующий монолитный скрипт. Исправлял проблемы с остатками, добавлял проверку цен, улучшал работу с изображениями.
К концу второго дня код выглядел страшно:
mi55_to_vk_bot.py ├── 1700+ строк кода ├── 5 больших функций ├── Нет никакой структуры ├── Невозможно понять логику └── Страшно менять
Я понял: если продолжать в том же духе, скрипт превратится в неподдерживаемый монстр. Нужно было кардинально менять подход.
День третий: Рефакторинг
На третий день я принял решение: переписать скрипт с нуля, но с правильной архитектурой. Главное, что я хотел получить — возможность чётко видеть, что именно происходит на каждом этапе.
Архитектурное решение: Этапы синхронизации
Я разделил процесс на три чётких этапа. Теперь каждый этап занимается только своим делом:
1. Сбор данных (только чтение, никаких изменений) ↓ 2. Планирование (сравнение, принятие решений) ↓ 3. Выполнение (только запланированные действия)
Этот подход кардинально изменил ситуацию. Теперь я мог видеть, что именно пошло не так, и исправлять проблему локально, не трогая остальной код.
Структура проекта после рефакторинга
mi55_to_vk_bot/ ├── main.py # Только точка входа, запуск этапов ├── config.py # Конфигурация и константы ├── models.py # Dataclass — чёткие структуры данных ├── db.py # Только работа с БД ├── vk_api.py # Только запросы к VK ├── prices.py # Вся логика работы с ценами ├── images.py # Только работа с изображениями ├── sync.py # Планирование синхронизации ├── executor.py # Выполнение плана ├── operations.py # Операции с VK (создать, обновить, скрыть) ├── email_report.py # Отчёты по email └── utils.py # Вспомогательные функции
Каждый модуль отвечает за свою зону ответственности. Мне больше не нужно лезть в логику работы с ценами, чтобы исправить что-то в изображениях.
Что дал рефакторинг
1. Прозрачность
Теперь я вижу, что происходит на каждом этапе. Скрипт выводит детальные логи:
📊 План синхронизации: ➕ Создать: 0 🔄 Обновить: 8 (цены, остатки) ➖ Без изменений: 629 ⏭️ Пропущено (без остатка): 2841
2. Умные обновления
Скрипт теперь сравнивает данные из БД и VK и обновляет только то, что действительно изменилось. Товары перестали обновляться каждый раз без причины.
3. Работа с одним товаром
Появилась возможность синхронизировать один товар, что сильно упростило отладку.
python main.py 12592
4. Email-отчёты
Теперь после каждой синхронизации приходит письмо с полной статистикой. Ошибки не остаются незамеченными.
5. Обработка крайних случаев
Рефакторинг помог найти и исправить множество скрытых проблем:
- VK не возвращает stock_amount в массовых запросах
- old_price лежит внутри price как old_amount
- VK не принимает old_price если она меньше или равна price
- Неопубликованные товары нужно скрывать, а не создавать
Сравнение: до и после
| Параметр | До рефакторинга | После рефакторинга | Улучшение |
|---|---|---|---|
| Время синхронизации | ~30 минут | ~2 минуты | 15x |
| API-запросов на товар | 7-10 | 2-3 | 3x |
| Обновление товара | Всегда | Только при изменениях | ~98% экономии |
| Строк кода | 1700+ | 2700 (в 14 модулях) | Структурировано |
| Возможность отладки | Практически нет | Детальные логи + email | ✓ |
Ключевые технические находки
1. VK не возвращает stock_amount в market.get
При массовой загрузке товаров VK не отдаёт поле stock_amount. Вместо этого нужно использовать availability:
availability = item.get("availability", 0)
stock = 999999 if availability == 0 else 0
2. old_price хранится внутри price
VK хранит старую цену как old_amount внутри объекта price:
price_data = item.get("price", {})
old_price = price_data.get("old_amount") # А не item.get("old_price")
3. VK проверяет old_price > price
VK возвращает ошибку, если old_price меньше или равна price. Нужно проверять это перед отправкой:
if product.old_price is not None and product.old_price > product.price:
data["old_price"] = product.old_price
4. Неопубликованные товары
Товары с published = 0 должны скрываться в VK, а не создаваться:
if db_product.published == 0:
if vk_product:
plan.to_hide.append(db_product)
continue
Что я вынес из этого опыта
Никогда не пиши большие монолитные скрипты. Как только код превышает 500 строк в одном файле — начинай рефакторинг. Это окупится с лихвой.
Разделяй на этапы. Процесс синхронизации — это идеальный кандидат для разделения на этапы. Это делает код прозрачным и легко отлаживаемым.
Используй dataclass. Чёткие структуры данных помогают не запутаться в том, какие данные ты обрабатываешь.
Добавляй email-отчёты. Когда скрипт работает на сервере, единственный способ узнать о проблемах — это получить письмо.
Читай документацию VK. Я потратил много времени на поиск проблем, описанных в документации. Всё, что нужно, там уже есть.
Рефакторинг — это не страшно. Когда код становится неудобным, переписывание с нуля с правильной архитектурой может сэкономить дни отладки в будущем.
Результат
Теперь скрипт работает быстро и предсказуемо:
- 4826 товаров синхронизируются за ~2 минуты
- Обновляются только товары с реальными изменениями
- Все ошибки логируются и отправляются по email
- Отчёт приходит сразу после синхронизации
- Любой этап можно отладить отдельно
Вместо 1700+ строк в одном файле — 14 модулей по 100-400 строк. Вместо непонятного монстра — прозрачная и поддерживаемая архитектура.
Заключение
Иногда лучшее решение — это переписать код с нуля, используя правильную архитектуру. Три дня работы над рефакторингом сэкономили недели будущих проблем.
Если ваш скрипт стал большим и непонятным — не бойтесь рефакторинга. Разбейте на модули, разделите на этапы, сделайте код прозрачным. Это окупится быстрее, чем вы думаете.
P.S. Исходный код доступен в репозитории.