Навайбкодил приложение для анализа графов

Попробовал создать небольшое приложение с помощью Claude Code. Изначально я был очень скептически настроен, потому что до этого использовал GPT в Copilot, который меня больше бесил, чем делал что‑то полезное. Поэтому я ожидал, что, ну, наверное Claude что‑то сгенерирует, но потом ещё неделю нужно будет вручную допиливать.

Я ошибался, вполне работающее приложение он сгенерировал за час, ещё день ушёл на тестирование и накидывание промптов по доработке. Можно было бы на этом остановиться, но в итоге я потратил ещё три недели на приведение документации, кода и в целом процесса разработки в порядок. Поделюсь этим опытом в статье.

Навайбкодил приложение для анализа графов - 1

Что за приложение?

Я думаю, это важный вопрос, чтобы можно было оценить на сколько оно сложнее, чем «Hello World», на сколько отличается от очередного трекера задач или копи‑пасты open source проектов.

У нас есть такой инструмент моделирования и нужно было прикрутить к нему штуку для анализа связей в моделях, чтобы отвечать на вопросы типа «в каких процессах и для чего используется такая‑то информационная система».

Сгенерированное приложение выглядит так (исходный код):

Навайбкодил приложение для анализа графов - 2

Немного опишу функциональность:

  • Получение моделей через API из репозитория

  • Визуализация моделей в виде графа или таблицы

  • Фильтр по типам объектов и связей

  • Быстрый поиск по названию объекта

  • Разные варианты отображения композиции (вложенные объекты или связи)

  • Легенда

  • Всплывающие подсказки

  • Подсветка связанных объектов

  • Форма свойств

  • Проваливание в объект (drill‑down)

  • Разные алгоритмы компоновки (layout)

  • Экспорт модели в png, svg, csv

  • Возможность поделиться ссылкой на модель со всеми фильтрами и настройками

  • Сохранение текущего состояния приложения в Local Storage

  • Возможность перехода вперед/назад без перезагрузки всей страницы

  • Темная и светлая тема

  • Поддержка разных языков

Несмотря на внешнюю простоту за всеми этими пунктами достаточно замороченные требования. Например, в drill‑down режиме если через фильтр скрыть некоторые объекты или связи, то при этом могут быть скрыты и другие объекты и связи, если они больше недоступны по прямому пути от основного объекта.

Ещё немного об общей архитектуре и используемых технологиях.

Можно было бы реализовать всё это как часть основного приложения, но я побоялся что LLM не осилит всю кодовую базу. Поэтому решили сделать в виде отдельного приложения. И на мой взгляд это очень удобный подход. Есть репозиторий моделей с API, а инструмент для анализа моделей — это простейший фронтенд на HTML, CSS, JavaScript, без всяких фреймков (React, Vue, …), без осточертевшей уже сборки, с минимум внешних зависимостей.

Мне очень нравится такой подход, хотя причины могут быть достаточно спорными:

  • Он максимально простой. Мне не нужно тратить часы чтобы разобраться почему при запуске dev‑сервера всё работает, а в production‑бандле «Uncaught ReferenceError: kakayatoNevedomayaFignya is not defined», а потом найти найти на GitHub сборщика баг, который висит открытым уже много лет со списком костылей как эту проблему обойти, или почему React рендерит страницу 1000 раз вместо одного или почему 8 Гб памяти не хватает для сборки проекта

  • Такой подход даёт максимальную свободу. Например, захотелось запилить реактивное приложение на сигналах — я его запилил. В любом движке (типа React) всегда есть удачные, неудачные или просто странные решения. Я считаю, что чистого HTML, CSS, JavaScript и базовых web API достаточно чтобы делать отличные приложения. Фронтендеры превратили веб‑разработку своими бесконечными фреймвоками и сборщиками просто в какой‑то ад

  • Это прикольный подход к разработке расширений для нашего приложения. Любой человек может достаточно легко сгенерировать или разработать какой угодно инструмент для анализа или редактирования моделей. Если вам годами не хватало какой‑то фичи, то вы можете сделать её сами, не вникая в кодовую базу на сотни тысяч строк, не устанавливая сложные инструменты разработки

Документация

Изначально я накидал в промпте основные идеи и попросил Claude написать спецификацию и сгенерировать по ней код. Затем я активно тестировал приложение и накидывал дополнительные идеи в стиле «хочу, чтобы можно было грабить корованы, обнови спецификацию и код».

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

Монолитный файлик со спецификацией приложения я разбил на несколько документов:

  • Видение продукта

  • Функциональные требования

  • Нефункциональные требования

  • Системные требования

  • Сценарии тестирования

  • Матрица трассировки требований

  • Правила написания документов и кода

Пройдём по каждому типу документов более детально.

Видение продукта

Пример документа.

Документ описывает:

  • Что это за приложение

  • Какие проблемы и каким образом приложение решает, зачем оно нужно

  • Целевую аудиторию

  • Аналогичные приложения и отличие от них

  • Критерии успеха

  • Дорожную карту

Функциональные требования

Пример документа.

Документ содержит список функций, которые должно выполнять приложение. Желательно сгруппировать функции по логическим категориям (функциональным блокам) и присвоить уникальные коды для каждой категории и функции, чтобы было удобно ссылаться на них из других документов. Также можно описать в документе что выходит за рамки функциональности приложения.

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

Нефункциональные требования

Пример документа.

Документ содержит список нефункциональных требований по следующим категориям:

  • Производительность

  • Надежность

  • Удобство использования

  • Качество

  • Инфраструктура

  • Соответствие стандартам и нормам

В целом этот документ достаточно типовой для разных приложений, но всё‑таки желательно добавить здесь конкретные метрики, например, что граф из тысячи объектов должен отображаться за 2 секунды, фильтрация и поиск должны работать не дольше 200 мс.

Со всеми документами была такая проблема, но с этим особенно. LLM генерирует просто тонны вроде полезного и осмысленного текста, но если сократить его в 10 раз, то смысл особо не потеряется. Для каждого требования в документе сейчас одна строка, но в первоначальной версии было по целому разделу. Словом, смело сокращайте документы.

Системные требования

Примеры документов. Они уже достаточно объемные, поэтому для каждого функционального блока удобно сделать отдельный документ.

Системные требования в разных компаниях могут описываться очень по‑разному, но у нас используется такой шаблон:

  • Пользовательские сценарии:

    • Код, название и краткое описание сценария

    • Ссылки на функциональные требования, которые этим сценарием закрываются

    • Пользовательская история

    • Шаги сценария с ожидаемыми результатами

    • Краевые случаи

  • Бизнес‑правила

  • Требования к UI/UX

  • Технические примечания

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

Сценарии тестирования

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

Если в системных требованиях сценарии описаны очень поверхностно, то здесь описываем все возможные сценарии для разных специфических ситуаций.

Документ содержит:

  • Код набора сценариев. Удобно если эти коды (например, TC-1.1) выравнены с кодами пользовательских сценариев (SR-1.1)

  • Ссылку на пользовательский сценарий

  • Тестовые сценарии:

    • Код

    • Название

    • Предусловия

    • Шаги с ожидаемыми результатами

    • Тестовые данные

В эти документы я практически не заглядывал, полностью положился на LLM. Но при этом они как‑раз и упрощают больше всего разработку. Для каждого сценария генерируется автотест на Playwright. И весь процесс выглядит следующим образом:

  • Я прошу LLM дополнить системные требования

  • Дополнить сценарии тестирования

  • Доработать автотесты

  • Доработать приложение, чтобы тесты проходили

По сути это водопадная и test‑driven разработка. Очень примитивный подход, который благодаря LLM можно воплотить полностью (без LLM просто времени не хватит чтобы писать все эти документы и тесты).

Я иногда вижу статьи, в которых люди рассказывают про десятки полезных плагинов для Claude, про магические SKILL.md файлы, которые превращают LLM в гениального разработчика, про толпы агентов, которые круглосуточно рецензируют документы и код друг друга, обмениваются сообщениями, делают тонны коммитов в минуту. На мой субъективный взгляд это тупик. Достаточно просто хорошо выстроенного процесса разработки, с понятными шагами и правилами, с документацией и тестированием. Это верно как для людей, так и для ИИ агентов.

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

Матрица трассировки требований

Пример документа.

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

Матрица очень тяжело давалась LLM, поэтому сгенерировал Python‑скрипт, который проходит по всем файлам и обновляет документ. Если какие‑то вещи легко автоматизировать, то лучше это сделать, а не мучить LLM.

Рекомендации по документированию и разработке

Примеры документов.

Пока все эти документы далеки от идеала, я планирую их существенно улучшать. Я только сейчас заметил, что у меня в одной папке совершенно разные по назначению документы, но мне лень их перекладывать. Их можно сгруппировать по категориям.

Общие рекомендации, не привязанные к конкретному проекту:

  • Процесс разработки — была идея, чтобы ИИ‑агент координировал подагентов по этой инструкции. Пишешь ему запрос «реализуй такую‑то фичу», а он запускает подагентов для каждого шага. Но пока мне не очень нравится этот документ и проще отправить несколько промптов вручную чем через координатора

  • Рекомендации по ведению документации — это детальное описание назначения и структуры каждого документа. Например, там важно упомянуть, что системные требования пишутся аналитиком, а не разработчиком и там не должно быть кусков кода

  • Соглашения о написании кода — этот документ мне нравится больше всего, я активно использовал его при рефакторинге. Пишешь агенту «оцени код на соответствие соглашению, и создай новый документ с планом рефакторинга», а затем «выполни рефакторинг кода в соответствии с планом». Я сделал несколько таких итераций рефакторинга, это реально очень удобно. В этом документе не должно быть тривиальных вещей, которые легко проверяются линтером или исправляются автоформатированием кода

Относительно универсальные документы, но которые в принципе могут содержать проектную специфику:

Архитектурные документы, специфические для конкретного проекта (они все важны, но я в них даже толком не заглядывал, не стоит использовать их в качестве примера):

Зачем тогда я их генерировал, если даже не смотрел? Системные требования были перегружены техническими деталями, вынес их отдельно, так эти документы и появились.

Код

То, что LLM умеют генерировать тонны документов вы и так знаете, а что насчет кода?

Как я уже говорил, приложение изначально было вполне работающее. Но естественно на первой итерации это был один большой HTML‑файл, в котором было всё — и CSS, и JavaScript. Я постепенно с помощью LLM раскладывал его на отдельные файлы. Поначалу всё шло неплохо, но в какой‑то момент между модулями из‑за сильной связности начали появляться циклические зависимости.

И Claude мне предолжил гениальную идею: можно уменьшить связность через кастомные события. Но когда количество событий достигло трех десятков, то приложение стало работать совсем нестабильно, всё больше токенов тратилось на попытки разобраться почему валятся автотесты и как их исправить. Я понял, что архитектура неудачная и решил всё переделать на реактивной сервисной архитектуре.

Идея максимально примитивная. Всё приложение строится из сервисов (которые хранят данные и отвечают за их обработку) и из визуальных компонентов (которые отвечают за рендеринг и обработку событий от пользователя). Для хранения данных в сервисах используются сигналы. Сигнал — это значение (строка, число, массив, объект, …) и список подписчиков на это значение. Когда значение сигнала изменяется, то он уведомляет об этом всех своих подписчиков, которые либо пересчитывают какие‑нибудь зависимые данные (если подписчик — это сервис), либо обновляют интерфейс (если подписчик — это визуальный компонент).

Такой подход хорош тем, что упрощает отладку кода и исправление ошибок. Плюс он достаточно универсальный, LLM не нужно принимать решение как что‑то реализовать, всё реализуется по единому шаблону.

Скорее всего, у меня вообще не возникло бы таких проблем, если бы я использовал готовый движок типа Angular или React + Preact Signals. Но я хотел приложение без сборки и с минимальными зависимостями. В итоге я просто сгенерировал свою реализацию сигналов, ровно такую какую мне нужно.

Я не могу сказать, что архитектура сейчас прямо идеальная. Например, в коде многовато эффектов, которые подписываются на сигналы и обновляют интерфейс. Но в принципе понятно как их зарефакторить с помощью LLM.

Разумеется стоит включить все мыслимые проверки линтера и автоформатирование кода. Если вы ещё не перешли на oxlint и oxfmt, обязательно попробуйте, они работают просто с космической скоростью.

Заключение

В итоге этого эксперимента я пришёл к следующему.

На мой максимально субъективный взгляд, Claude пишет код лучше, чем среднестатистический разработчик, пишет документы лучше, чем среднестатистический аналитик, пишет тесты лучше, чем среднестатистический тестировщик. Безусловно он делает ошибки, но я насмотрелся таких отвратительных документов и кода, написанных людьми, что LLM уже не может меня ничем шокировать.

Более того, в плане скорости и объёма работы лично у меня просто ноль шансов против LLM.

Но, тем не менее, LLM безусловно уступает людям в плане идей и здравого смысла. Даже для такого простого приложения мне пришлось потратить три недели, чтобы приложение оставалось адекватным, выполняло полезные функции и им было приятно пользоваться. LLM вообще без разницы будет в приложении 2 простых экрана и 5 кнопок или 10 вложенных диалогов. Как и без разницы сгенерировать документ на 10 или 1000 страниц.

Также LLM вряд ли осознает, что структура документов или архитектура приложения — полный бред. И вместо того, чтобы два часа упорно добавлять всё новые костыли в приложение, нужно просто изменить архитектуру.

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

Но… с другой стороны… мне хочется написать, что, нет, не заменит, ведь… но я не знаю как закончить статью, пойду спрошу у ИИ…

Автор: Ares_ekb

Источник

Оставить комментарий