Ревью вайб-кода, который притворяется оптимизированным C++

Ревью вайб-кода, который притворяется оптимизированным C++

Ценность квалифицированного программиста сегодня всё больше смещается в сторону умения проводить обзоры кода. Генерировать код стало проще, но проверка его качества — по декомпозиции, корректности, эффективности и безопасности — остаётся критически важной. Рассмотрим на примере проекта markus, созданного с помощью Claude Opus, почему нельзя слепо доверять сгенерированному коду, даже если он выглядит оптимизированным и аккуратным.

Проект markus

markus — это single-header библиотека на C++20 для парсинга текста и его конвертации в HTML. Проект сгенерирован с помощью Claude Opus и состоит из одного файла markus.h объёмом 6484 строки. Библиотека выглядит впечатляюще: компактная, с использованием современных возможностей языка, включая if constexpr, [[unlikely]], std::pmr и табличные методы оптимизации.

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

Проблематика вайб-кодинга

Генерация кода с помощью ИИ может очаровать, особенно тех, кто не сталкивался с долгосрочным сопровождением больших проектов. Главная задача — не написать код, а сделать его поддерживаемым и эффективным. Как отмечал Роберт Мартин:

Без присмотра AI будет нагромождать код поверх кода. У него нет чувства большой картины. Архитектура, вероятно, за пределами его возможностей.

Особая опасность вайб-кодинга — излишнее доверие к сгенерированному коду. Убедившись, что ИИ хорошо справляется с простыми задачами, разработчики теряют критичность. Кажется, что и в сложных случаях код будет качественным. Но это не так.

Автор проекта markus честно предупреждает:

DO NOT USE IN PRODUCTION. This is completely vibe coded and has not undergone any reviews for memory safety. Its performance is also 2-3x slower than cmark.

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

Нужен ли эксперт?

Можно ли обойтись без экспертизы кода? Только если выполняются все условия:

  1. Ошибки не приведут к убыткам или вреду.
  2. Код не представляет интереса для атак.
  3. Производительность не важна.
  4. Проект не будет развиваться долгое время.

Во всех остальных случаях — особенно при использовании C++ — требуется строгая проверка. К вайб-коду нужно применять те же стандарты, что и к любому другому: SSDLC, РБПО, статический и динамический анализ.

SIMD-friendly код: иллюзия оптимизации

Функция IsSpanBlank позиционируется как «SIMD-friendly» — якобы подготовлена для векторизации. Код обрабатывает по 8 символов в цикле, что создаёт впечатление продуманной оптимизации.

Однако на практике байты обрабатываются последовательно. Вложенный цикл не даёт реального выигрыша. Эксперименты с GCC, Clang и MSVC показали: простой цикл работает быстрее, чем «оптимизированный» вариант от ИИ.

Даже замена || на | улучшает производительность — но это уже исправление ошибки, а не оптимизация. Более эффективные решения требуют интринсиков (SSE/AVX), но они снижают переносимость.

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

Сравнение строк: цветочки

Анализатор PVS-Studio выявил избыточную проверку:

Она безвредна — компилятор её уберёт, но портит читаемость. Более серьёзная проблема — неэффективное сравнение строк без учёта регистра. Вместо создания временной строки в верхнем регистре, лучше использовать специальную функцию, например starts_with_insensitive.

Это устраняет лишние аллокации и ускоряет выполнение. Small String Optimization может смягчить удар, но не отменяет необходимости писать эффективный код.

Сравнение строк: ягодки

Ещё хуже — использование вектора строк type1_tags для проверки тегов. При каждой проверке создаются временные строки с добавлением угловой скобки <, а затем — ещё одна строка для сравнения без учёта регистра.

В худшем случае создаётся до восьми временных строк. Это абсурд с точки зрения производительности.

Решение простое: хранить готовые префиксы в std::array<std::string_view, N> и использовать starts_with_insensitive. Код сокращается вдвое, а производительность растёт в разы.

Цена красоты

Один из самых «элегантных» фрагментов — сериализация с использованием std::variant и паттерна «визитор». Код типобезопасный, короткий и красиво оформленный.

Однако за этой красотой — катастрофическая неэффективность. std::variant выделяет память под самый большой тип — в данном случае Image, который занимает до 120 байт. Вместе с управляющей информацией — 128 байт на каждый элемент, даже если это пустой SoftBreak.

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

Решение со std::unique_ptr<Node> было бы легче и эффективнее. Использование std::variant здесь — антипаттерн, замаскированный под современный C++.

Кроме того, в коде есть неиспользуемое перечисление NodeType и поле kType, которые можно удалить, сократив код на сотню строк.

Другие проблемы

Повторные проверки: ИИ ставит [[unlikely]], но потом проверяет то же условие снова. Например, !input.empty() проверяется дважды — это бессмысленно.

Бесполезные присваивания: Переменной prev_line_had_content присваивается true, хотя она и так уже true. Комментарий просто повторяет код — типичный антипаттерн.

Неправильное использование push_back: Вместо emplace_back везде используется push_back, что приводит к лишним вызовам конструкторов перемещения. Хотя выигрыш небольшой, это системная ошибка проектирования.

Копирование вместо перемещения: Переменные вроде content копируются, хотя дальше не используются. Нужно использовать std::move.

Неэффективная вставка в map: Проверка существования ключа перед insert приводит к двойному поиску. Лучше использовать try_emplace, который делает это за один проход.

Заключение

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

Выводы:

  1. Оценка кода экспертом остаётся необходимой.
  2. Архитектура и декомпозиция важнее, чем синтаксическая изощрённость.
  3. Эффективность нужно измерять, а не предполагать.
  4. Статические анализаторы — важный инструмент, но они не заменяют человека.
  5. Вайб-код — не враг, но и не панацея. Это инструмент, требующий контроля.

Чем больше кода генерируется ИИ, тем выше ценность разработчика, способного отличить качественный код от имитации. В мире C++ эффективность — не опция. И если вы не готовы это проверять, возможно, C++ — не ваш выбор.

Читать оригинал