Приходится ли вам сравнивать файлы? Риторический вопрос: очевидно, приходится. Я лично команду "git diff" выдаю тысячу раз за день. Всем классический diff хорош, кроме одного: не различает
перестановку фрагмента. Показывает только удаления и вставки. Если же часть текста переехала в другое место, diff учитывает его дважды: и как удаление, и как вставку.
Для некоторых применений такое не годится. Представьте, что вы хранитель коллекции ценных документов. И вдруг с одним файлом что-то случилось. Стандартный diff говорит, что всё пропало, документ полностью испорчен. А просто строки перемешались, ничего на самом деле не потеряно. Надо только порядок восстановить. В эпоху перфокарт такое сплошь и рядом происходило, когда колоду рассыпали и собрали впопыхах. Или кто-то решил навести порядок и переставил главы в тексте.
45 лет назад мой коллега Рид Котлер сделал утилиту сравнения файлов: "
Text File Comparator". Трудился он тогда молодым студентом на компанию Intermetrics по контракту NASA. Сохранилось упоминание на странице 117 журнала NASA Tech Briefs Winter 1982 Vol. 7, No. 2:
https://ntrs.nasa.gov/api/citations/20100028127/downloads/20100028127.pdf
Программа сравнивает два файла и выводит список их различий.
Программа сравнения файлов IFCOMP — это сравнение текстовых файлов для систем, совместимых с IBM OS/VS. IFCOMP принимает на вход два текстовых файла и выводит список их различий в форме псевдообновления. Все различия представлены в виде строк, которые следует удалить, заменить, вставить или переместить в первом входном файле для преобразования его во второй входной файл. Также выводится сводка с указанием количества строк, затронутых каждым типом изменений.
IFCOMP позволяет игнорировать номера строк и конечные пробелы при сравнении файлов с записями разной длины. IFCOMP может быть очень полезен для мониторинга изменений, вносимых в программное обеспечение, на уровне исходного кода. При таком использовании IFCOMP позволяет проводить прямое сравнение исходного кода для единообразного выявления изменений.
Программа IFCOMP написана на языке XPL (расширенный язык PLI, для которого поставляются исполняемые файлы компилятора) для пакетного выполнения и была реализована на компьютере IBM серии 370 с объёмом центральной памяти около 46 КБ 8-битных байт. IFCOMP была разработана в 1979 году.
Эта программа была написана Ридом С. Котлером из Intermetrics, Inc. для Космического центра имени Джонсона. Для получения дополнительной информации обведите кружком S на карточке запроса COSMIC.
Алгоритм подробно описан в статье: "
A Technique for Isolating Differences Between Files", Paul Heckel 1978.
Исходники на языке XPL утеряны, увы. Но сохранился
вариант, переписанный Томом Пенелло на Си. Его я и решил поковырять. С ним Рид мне прислал четыре теста, и они работали. Но на некоторых других файлах программа выдавала внутреннюю ошибку или циклилась. Ошибка там неочевидная.
Я подумал: хороший случай применить ИИ для отладки. Интересно, как неестественный ум справится, скажем Cursor или Cline. Получился увлекательный сеанс. 😀
В целом программирование с помощью современного AI-агента напоминает походовую стратегическую игру. Если помните первую
Empire, ещё в текстовом виде. Из неё потом выросла
Civilization. Здесь нечто похожее, только без карты и в диалоге. Стратегически плодите и размещаете юнит тесты, и постепенно боретесь за расширение функционала и покрытия.
Благо, ИИ агент теперь удобно встроен в VS Code. Работает с файлами прямо в вашем локальном git-репозитории. Или даже прямо на Гитхабе, вам решать. Компилирует, запускает, пишет документацию, находит причины ошибок посредством юнит тестов, чинит, и по новому кругу. Вы внимательно наблюдаете за "сражением" и адресно вмешиваетесь в критические моменты.
Первый "подход к штанге" мы с Курсором продули. 😀 Для начала насоздавали несколько десятков юнит тестов, из которых больше половины не проходили. Хорошо, значит покрытие приемлемое. После этого несколько часов бились все эти тесты пройти. Курсор кромсал код без жалости. Объём Си-шных текстов увеличился вдвое, но справиться с глюками не удавалось. Стало понятно, что зашли в тупик.
Второй подход я распланировал иначе. Сначала переписываем всё с Си на Си++, чтобы уменьшить базовую сложность кода. Вместо доморощенных строк и примитивного выделения памяти переходим на стандартные строки и контейнеры из библиотеки Си++. После этого начинаем покрывать юнит тестами и отлаживать размеренно, по стадиям. Благо алгоритм имеет чёткое разделение на восемь проходов: от pass1() до pass8().
Главная бага обнаружилась на стадии pass6(). При слиянии двух блоков криво обновлялось дерево. Но проявлялся глюк только на уровне pass8(). Тесты уровней pass6 и pass7 багу не ловили. Курсор пытался "чинить" сначала уровень pass8, потом догадывался вернуться и сделать что-то с pass7, и даже заглядывал с сомнением в pass6, но тут его чутья не хватало. Как только я догадался скомандовать создать юнит тест, воспроизводящий нужную багу на уровне pass6, дело пошло на лад. Починка остального была уже делом техники.
Все исходники здесь:
github.com/sergev/ifcomp