Когда использовать нейросети/LLM в помощь программисту?

| рубрика: Программирование | автор: st
Метки: , ,

С простыми задачами в программировании я и сам справляюсь, а со сложными LLM мне помочь не может
(c) Неизвестный автор

В предыдущем тексте с картинками годовалой выдержки я попытался обрисовать слишком оптимистично настроенному читателю принципиальные проблемы использования больших языковых моделей для разработки софта.

За прошедшее время ажиотаж заметно спал, но внимание к теме периодически подогревается очередным новым сервисом и/или дополнением к среде разработке, позволяющем "за несколько секунд сгенерировать работающий код". Однако, никаких серьёзных успехов вроде переноса тяжкого груза наследуемого кода на современные платформы не подаётся. Кобол до сих пор активно используется в экономико-финансовом ПО, есть открытые вакансии даже с последующим обучением, а в прошлом году принят новый стандарт Фортрана.

366 ФМШ,Ленинград, учитель В.М.Паповский, 1980-е годы

Начну с позитивного примера из практики коллег

Приложение на Питоне порядка 3000 строк. Основная функция -- автоматизация собственной профессиональной деятельности, автор -- не профессиональный программист, но специалист в ИТ. Задача сводится к вызовам внешних сервисов для перекладки данных из одного источника в другой. LLM типа "гоп-чат" (конкретный сервис не называю в антирекламных целях) скармливается спецификация API сервисов и словесные описания, в результате многих итераций были сгенерированы исходники. Дальнейшая поддержка не требуется, пока не поменяется API.

В другом известном мне случае с использованием более нового гоп-чата автор -- специалист по 1С, автоматизировал генерацию скриптов 1С по похожему сценарию, также получая хороший для себя результат.

Как можно понять, если формальные спецификации уже существуют, то получать по ним работающий код несложно. В обоих случаях речь идет о клиентском коде для внешних служб вкупе с некоторой внутренней логикой. Будет неуважительным жаргонно назвать такую работу "перекладкой джейсонов", скорее, это склейка-сборка-конструирование из готовых компонентов.

Тем не менее, существует большая разница между одноразовым решением для себя или для заказчика и тиражируемым продуктом для клиентов. Поэтому переходим к примерам, более адекватным теме софтостроения.

На рабочем совещании по разработке конвертера из VBScript в C# было представлено два подхода: обработка исходников регулярными выражениями и использование внешней LLM, которой "скармливается" контекст.

Стандартное решение в этом случае ни первое, и не второе. Грамматика языка VBScript контекстно-свободная, поэтому исходники не могут быть в общем случае разобраны регулярными выражениями. Требуется взять описание грамматики VBA/VBS, сгенерировать по нему синтаксический анализатор (парсер) и далее транслировать скрипты в код на C#, обходя синтаксическое дерево с учетом семантики. Решение не было предложено по причине отсутствия у команды соответствующего опыта, а соответствующую теорию читают только профильным студентам. Но не суть.

Прототип на регулярных выражениях, которые "что-то там трансформируют", ясное дело, представляет собой жуткую лапшу (каюсь, и сам писал такое для решения одноразовых проблем ad hoc), но генерируемый код иногда компилируется. Всё происходит локально и быстро, но требует усилий со стороны программиста.

Второй прототип создан для использования гоп-чат LLM. Кроме, собственно, исходника на VBS, требуется длинный (тысячи строк) файл контекста, описывающий зависимости и сигнатуры, например, API внешних компонентов. Обучение требует многих итераций, но результат примерно такой же, как и регулярными выражениями: каждый скрипт нужно проверять и корректировать в несколько итераций. Разница в том, что за каждую итерацию сервису уходят денежки пропорционально отправляемому числу токенов. Многие ситуации приходится обрабатывать вручную. Например, в VBS переменную можно переиспользовать под разные типы, и без анализа семантики нужно каждый раз это проверять и вводить две переменные C# вместо одной.

В конечном итоге оба подхода, возможно, позволили бы на ручном управлении перетранслировать несколько сотен скриптов за обозримый срок и забыть про этот кошмарный сон. Однако, налицо две проблемы: отсутствие теоретических знаний и опыта по решению проблемы и попытка восполнить их за счет "искусственного интеллекта". Да, ещё интересно, разработчик уверен, что "ИИ нас скоро всех сожрет".

Вышеописанная задача снова близка к одноразовой, но подразумевает активную кодогенерацию: сотни и тысячи новых строк в день.

Однако, реальность большинства программистов совсем иная -- миллионы строк легаси-кода, неявные зависимости и необходимость писать не более нескольких десятков строк в день.

Изменения

Типичный пример добавления новой функциональности. Как можно увидеть, половина изменений -- тесты и документация. Для исправления ошибок изменения в разы скромнее. Иногда даже одна строчка. Чем меньше вносится изменений, тем ниже риск регрессии.

Поэтому когда читаешь о том, как легко генерировать и менять код с помощью LLM и "вторых пилотов" (co-pilots), закрадываются некоторые сомнения. Создаётся впечатление, что автор пишет тонны кода в день. Зачем?

Даже на стадии написания "с нуля", производить на свет несколько сот строк в день сможет разве что "стахановец"-бракодел, точнее, "багодел". Программирование -- не беспощадное нажимание клавиш вслепую со скоростью профессиональной машинистки. Программирование не зря называют детальным проектированием и сопутствующим ему кодированием. Программирование -- постоянные размышления о декомпозиции, связности модулей, интерфейсах и абстрагировании, повторном использовании, тестируемости и, главное -- соответствии требованиям.

Реальная продуктивность разработчика -- десятки строк в день на сопровождении и несколько больше при написании нового кода. Большого смысла пользоваться генераторами на базе нейросетей для такого объёма не наблюдается. Есть смысл учиться критически подходить к ревизии кода, а не вручную генерировать "лапшу", когда функциональность была нужна "еще вчера.

Заслуженную нелюбовь у разработчиков вызывает "инфраструктурный код", он же "душнина", он же boilerplate code. В монстроидальных Java-фреймворках его объем непринуждённо и легко дойдёт до 80-90 %. Может ли LLM помочь? Отчасти, да, если вы готовы каждый раз проводить ревизию "душнины".

Помоги Даше найти бизнес-логику

Другой давно известный подход MDD или software factory позволяет генерировать boilerplate code по метаописаниям. Для задач типа "добавить поле ввода на форму" еще в 1980-е годы существовали и существуют визуальные средства, позволяющие сделать быстрое изменение дизайна пользовательского интерфейса. Для ревизии кода были и есть статические анализаторы и прочие линтеры.

В 1990-е годы популярным было направление RAD (Rapid Application Development). Среды вертикальной (fullstack) разработки, такие как Delphi, C++Builder, PowerBuilder, Optima++ и другие позволяли создавать достаточно сложные приложения, взаимодействующие с базами данных без написания строчки кода. Стоит сказать, что такой уровень недоступен современным средствам разработки.

Ввиду детерминированности всех перечисленных средств, проверка "на бредогенерацию" фактически не нужна. Нужно знание неявных зависимостей, чтобы добавленное поле не перекосило форму у некоторой группы клиентов со специфичными настройками рабочих мест.

Приведу другой случай из практики.

Возникла необходимость установки в БД значений по умолчанию для всех колонок с заданным наименованием и типом. С помощью гоп-чата после нескольких итераций была сгенерирована процедура на 30 строк, которая после косметических правок прошла локальные тесты и ушла в пакет обновлений.

Однако, у некоторых клиентов накат обновления вызывал ошибку. Эксперт по БД быстро выяснил, что проблема в наличии проекций (view), отсутствующих в стандартной конфигурации.

Процедура была откорректирована и включена в оперативное обновление (hotfix). Риторический вопрос, сколько ресурсов было бы сэкономлено, если бы эти 30 строк изначально писал человек с опытом?

Когда код сгенерирован недетерминированным потенциальным "бредогенератором", ты остаёшься с ним один-на-один. Даже если ты хорошо понимаешь технологию и представляешь собой образец эксперта, готового педантично проверять каждую строку, от человеческого фактора никто не застрахован. Когда ты смотришь на решения со stackoverflow, то, как правило, в комментариях обнаруживается много полезных советов других ревизоров, не раз приводившая меня к корректировке предлагаемых вариантов или даже пересмотру всего решения. К сожалению, есть опасность, что теперь и комментарии могут генерировать. "Белковые" сообщества абсолютно незащищены в этом отношении, пока, по крайней мере.

В заключении отойду от темы софтостроения на ещё одном практическом примере.

В октябре прошлого года я готовил небольшую статью по спортивной тематике. Поиск приносил много материала, на первый взгляд -- слегка странного, состоящего из фрагментарного текста. На второй взгляд материал оказывался сгенерированным LLM. Среди многочисленной дезинформации особенно смешными выглядели фразы "table size was decreased from 5 ft to 152.5 cm wide, and from 9 ft to 274 cm long". Также много раз попадался список-хронология важных изменений правил соревнований, наполовину не соответствующий действительности.

К чему это отступление? Скоро добываемый поиском контент будет забит полуправдой-полувымыслом и откровенной дезинформацией, сгенерированной языковыми моделями. Мы откатываемся в ситуацию конца 1990-х - начала 2000-х годов, когда эксперты работали не с поисковиками, а с собственным каталогом ссылок по профессиональной тематике и специализированными сайтами. Хочется верить, что худо-бедно верифицированный сообществом белковых экспертов stackoverflow и другие будут помогать в работе еще достаточное время. Хотя заполнить его сгенерированными вопросами и комментариями -- дело времени.