Дисклеймер
Статья носит в основном технический характер, поэтому для бизнес-пользователей мы будем вставлять картинки, чтобы они не уснули. Если что — можно сразу пролистать к выводам в конце.
Задача
Клиенту нужно было перенести каталог техники в веб-приложение. Звучит просто, пока не выясняется, что каталог живет внутри старого Windows-приложения без API, без документации и с частью логики, зашитой внутри самого приложения. При этом перенести нужно было не только данные, но и всю структуру каталога:
- дерево машин;
- разделы;
- иллюстрации;
- hotspot-точки;
- PDF-документы;
- изображения;
- служебные связи между объектами.
Проблема была в том, что данные находились сразу в нескольких местах:
- в базе данных;
- в файлах (PDF, изображения);
- внутри логики приложения;
- частично в зашитых внутренних структурах.
То есть данные вроде бы есть, но выглядят как огромная рассыпанная мозаика, инструкция по сборке которой хранится в закрытом ящике, ключ от которого лежит в яйце, яйцо в утке и так далее. И мозаика эта весьма внушительных размеров.
Как решать?
Подход №1. Раскопать базу данных
Самая очевидная идея — подключиться напрямую к базе и вытащить все необходимые данные оттуда. Подход хороший, но результат оказался не очень хорошим. Достаточно быстро выяснилось, что значительная часть логики отображения хранится внутри самого приложения. По структуре таблиц далеко не всегда было понятно, как именно собираются данные для пользователя. Конечно, мы дополнительно проанализировали запросы, которые приложение выполняет к базе данных. Это позволило лучше понять внутреннюю модель и получить часть информации, но результат все еще был далек от того, чем хотелось бы пользоваться в продакшене.
Подход №2. Автоматизация desktop-приложения
Следующая идея — использовать само приложение. Написать инструмент, который будет автоматически нажимать кнопки, открывать разделы и собирать отображаемые данные. Подход оказался рабочим и позволил получить довольно много информации. Но возникла другая проблема: часть данных отображалась через кастомные Windows-компоненты, содержимое которых стандартными средствами прочитать не получилось. Мы уперлись в очередной тупик.
Подход №3. OCR и распознавание текста
Если данные нельзя получить напрямую, можно попробовать получить их через экран. Идея была простой:
- автоматически открывать нужные разделы;
- делать скриншоты;
- распознавать текст;
- парсить результат;
- сохранять в новую систему.
Технически решение вполне жизнеспособное. Практически — слишком медленное для объема данных, с которым мы работали. Этот вариант мы оставили как запасной план на самый крайний случай.
Подход №4. Подключиться к самому приложению
В какой-то момент стало понятно: если логика сборки данных находится внутри приложения, значит нужно использовать именно эту логику. Возникла идея написать обертку над DLL-библиотеками приложения и превратить их в обычный REST API. Была только одна проблема. В команде не было разработчиков, работающих с C#/.NET. Поэтому для реверс-инжиниринга и подготовки обертки мы активно использовали LLM-инструменты. Нейросети помогли быстро собрать основу проекта, после чего началась серия итераций: анализ DLL, проверка гипотез, отладка и доработка кода. Через некоторое количество инженерной археологии мы получили небольшой exe-файл, который запускался рядом с исходным приложением и выступал REST-прослойкой между нашим кодом и внутренними DLL системы.
Решение
В итоге у нас появился x86 API-сервер на C#/.NET. Он запускается рядом с установленным desktop-приложением, загружает его DLL-библиотеки и обращается к данным практически так же, как это делает оригинальная программа. Получившийся bridge предоставляет наружу обычные HTTP-эндпоинты:
- каталог;
- дерево разделов;
- схемы;
- документы;
- изображения;
- hotspot-точки;
- служебные данные.
Для остальной системы это выглядит как обычный API. Под капотом же работают старые DLL, внутренние классы и некоторое количество инженерной магии. Главное преимущество такого подхода — мы получили не разовый экспорт, а воспроизводимый механизм получения данных. Если каталог изменился или нужно импортировать новые машины, больше не приходится заново разбираться в устройстве системы.
Нюансы реализации
Получить данные оказалось только половиной задачи. Информация находилась на разных уровнях дерева каталога, имела разные форматы и требовала дополнительной обработки перед загрузкой в новую систему. Для этого пришлось реализовать отдельный слой преобразований — маппинги. Маппинги определяли:
- откуда брать данные;
- как их преобразовывать;
- куда помещать результат;
- какие связи между объектами необходимо сохранить.
Работать с длинными списками идентификаторов и сложными деревьями данных вручную оказалось не слишком удобно. Возник закономерный вопрос: может быть, написать админку? Еще несколько лет назад подобная идея означала бы дополнительные недели разработки. Сегодня ситуация немного другая. Если инструмент используется многократно и является частью рабочего процесса, современные AI-инструменты позволяют создать его достаточно быстро и с минимальными затратами. Поэтому мы пошли именно этим путем.
Админка для импорта
В какой-то момент стало понятно, что выгрузка данных — это только половина задачи. Нужен был способ управлять импортом, повторять его и контролировать результат. Поэтому поверх API появилась отдельная веб-админка, которая закрывает весь процесс — от настройки маппинга до выгрузки на продакшн. Админка позволяет:
- получать данные через API-обертку desktop-приложения и просматривать их;
- настраивать маппинги;
- импортировать данные из исходной системы;
- загружать PDF-файлы и изображения;
- синхронизировать файлы через rsync;
- выгружать базу данных на сервер;
- запускать импорт непосредственно на продакшн-сервере через отдельный API.
В результате весь процесс стал полностью повторяемым:
- Открываем каталог источника.
- Выбираем нужные машины.
- Настраиваем маппинг.
- Импортируем данные и файлы.
- Проверяем результат локально.
- Выгружаем изменения на сервер.
Главный результат проекта — не то, что мы один раз достали данные. Главный результат — инструмент, которым можно пользоваться дальше. Добавлять новые машины. Исправлять маппинги. Повторять импорт документов. Проверять результат. Выгружать обновления без ручной работы и поиска инструкций в духе «а какую кнопку нужно нажать третьей?».
Выводы
Главный результат этого проекта — не импорт каталога. Главный результат — превращение закрытой legacy-системы в управляемый источник данных. Вместо разового экспорта мы получили процесс, который можно повторять: добавлять новые машины, обновлять документы, исправлять маппинги и публиковать изменения без ручной работы.
И, пожалуй, самый интересный вывод: задачи, которые еще несколько лет назад потребовали бы отдельной команды специалистов по .NET и реверс-инжинирингу, сегодня можно решить силами небольшой команды за считанные дни, если правильно комбинировать инженерный опыт и современные AI-инструменты.
Если у вас есть данные, которые необходимо встроить в существующие бизнес-процессы, интегрировать с новой системой или просто вытащить из старого программного обеспечения — такие задачи нам особенно интересны. Любим сложные интеграции, legacy-системы и данные, которые на первый взгляд невозможно достать
Потрачено на разработку: 32 часа.
