Привет, коллеги!
Сегодня мы копнем в самую суть инженерного подхода. На повестке дня — сравнение двух кардинально разных философий создания сложного UI-компонента. Это не просто рассказ о DatePicker, это анализ стратегического выбора, который каждая команда делает каждый день: скорость в ущерб предсказуемости или наоборот?
Исходный код доступен по ссылке: https://github.com/Codesrc-public-ru/ralf-datapicker
За основу мы возьмем два реальных кейса. Первый — «AI-драфтинг», отлично описанный нашей статье «Создаем WCAG-доступный DatePicker на React: как Claude пишет основу, а мы доводим до ума«. Идея: получить 80% кода от нейросети, а остальное довести вручную. Это путь быстрых итераций и реактивного решения проблем.
Второй — «Системный инжиниринг», подход описан в этой документации к инструменту https://github.com/snarktank/ralph. Идея: сначала детальное проектирование, потом итеративная работа модели. Это путь проактивного управления сложностью.
Оба приводят к результату. Но какой ценой? И что скрывается под капотом каждого из них? Давайте разберем.
Подход №1: AI-драфтинг. Реактивная разработка
Этот подход напоминает скоростную сборку прототипа. Берется детальный промпт, основанный на WAI-ARIA APG, и скармливается Claude. На выходе — практически готовый компонент. Кажется, победа, но, как показывает опыт коллег, именно здесь начинается самое интересное.
Проблемы, с которыми они столкнулись, — это классические интеграционные баги:
-
Конфликт спецификации и реальности: слепое следование APG (ячейки-<td> без button внутри) привело к менее надежной работе скринридеров, чем осознанное отступление от гайда.
-
Неявное управление состоянием: «моргающий» диалог при повторном клике — типичный баг, когда несколько обработчиков событий (onBlur, onClick) конфликтуют в непредсказуемой последовательности.
-
Тонкости a11y: проблема с aria-live=»polite» против assertive — это не то, что может предсказать AI. Это нюанс UX, который выясняется только при реальном тестировании со скринридером.
Это путь, где продукт создается методом последовательного приближения, а архитектура возникает «случайно» (эмерджентно) в процессе латания дыр.
Подход №2: Не кодер, а система. Как мы запрягли AI-агента.
Наш путь был другим. Мы сразу решили, что управлять разработкой будет не один большой промпт, а целая инженерная система, в которой AI — дисциплинированный исполнитель, а не свободный художник.
В роли исполнителя у нас был подход Ralph цикла — кастомный автономный агент на базе codex cli с моделью gpt 5.4-mini. Чтобы он не «фантазировал», мы написали ему жесткий системный промпт, который был буквально впечатан в его «личность» (AGENTS.md):
-
# Accessible DatePicker — Project Architecture & Coding Rules
You are a senior frontend engineer and software architect working on a production-grade, accessible DatePicker component for React + TypeScript.
Полный промпт находится вот тут.
Его реальным «мозгом» и «памятью» стал набор внешних файлов, который мы подкладывали в его рабочую директорию:
-
PRD.md (Product Requirements Document): наш свод законов. Там было черным по белому: controlled-only API, полная навигация с клавиатуры, корректная aria-разметка. Это незыблемые принципы.
-
tasks.json: детальный таск-трекер для агента. Мы декомпозировали всю работу на атомарные шаги: «создай структуру каталогов», «опиши типы для дат», «напиши чистую функцию addMonths», «собери UI-компонент Button».
-
Использованные субагенты:
-
Специалист по ПРД — https://subagents.cc/agents/prd-specialist
-
Архитектор кода — https://subagents.cc/agents/code-architect
-
Фронтендер — https://subagents.cc/agents/frontend-developer
-
Сам подход был похож на конвейер:
-
На каждой итерации агент выбирает задачу из tasks.json
-
Пишет или меняет код.
-
Мы запускаем внешний контур проверки (The Verifier). Это не часть агента, а наш собственный скрипт, который прогонял unit- и a11y-тесты (Vitest + Playwright), сборку проекта (Vite build) и проверку типов (tsc —noEmit).
-
Результаты работы агент записывает в progress.md
Если хоть одна проверка падала — агент получал лог ошибки и команду «переделывай». Он не мог перейти к следующему таску, пока текущий не был идеален. Именно такая система вынудила агента проактивно выстроить ту самую трехслойную архитектуру:
-
Ядро (lib/date/, lib/input/): чистая логика.
-
Представление (ui/): «глупые» stateless-компоненты.
-
Связующий слой (model/): логика, которая всем этим управляет.
Этот подход переносит фокус с «напиши мне DatePicker» на проектирование системы, которая этот DatePicker производит и проверяет, а это и есть проактивная разработка в действии.
Результаты работы агента:
Сравниваем в лоб: цена, качество, риски
Давайте сведем все в таблицу и разберем детально.
1. Экономика и стоимость изменения (Cost of Change)
-
AI-драфтинг: низкий порог входа, но стоимость изменений — лотерея. С хорошим промптом AI может выдать отличное, структурированное решение. Но без жестких архитектурных рамок он часто генерирует монолитный код, где любая фича превращается в болезненный рефакторинг. Ключевой риск — непредсказуемость. Техдолг начинает копиться сразу.
-
Системный инжиниринг: высокая стоимость входа (время на проектирование и большой расход токенов). Нужно добавить поддержку выбора времени? Мы просто расширяем ядро, добавляем новый UI-компонент и обновляем связующий слой. Остальные части системы остаются нетронутыми. Это инвестиция, которая окупается на дистанции.
2. Архитектура и управление сложностью
-
AI-драфтинг: архитектура сгенерированного кода — это по сути черный ящик. Она неявная и хрупкая. Разделение ответственности отсутствует, что делает код трудным для понимания и отладки. Чтобы починить «моргающий диалог», нужно держать в голове всю картину целиком.
-
Системный инжиниринг: думаете, хорошая архитектура в большом проекте спасет от всех проблем? Как бы не так. Мы тоже так думали. Разложили все на три слоя, чтобы спокойно вносить правки. А потом небольшое изменение в логике расчета недель привело к каскадному сбою в датапикере. Прилетело оттуда, откуда не ждали. Это не значит, что подход плохой. Это значит, что для больших систем его недостаточно. Теперь мы всегда добавляем четкие «контракты» между слоями и автоматическую валидацию. Это как отбойники на трассе — не дают случиться аварии.
3. Типология и локализация ошибок
Это самый показательный пункт.
-
Самая частая ошибка при работе с AI-драфтингом — верить, что он сам все сделает правильно. Не сделает. Его главная слабость — интеграция. Он может идеально написать два модуля по отдельности, но на их стыке начнется хаос: ошибки состояния, рендера, событий. А все потому, что у AI нет понимания «правильно/неправильно», он просто выполняет задачу. Наш подход — не исправлять баги, а не давать им появиться. Мы внедряем «гардрейлы» (guard rails) — это набор жестких требований и инструкций, которые AI обязан соблюдать. По сути, мы заставляем его думать об архитектуре. В этом датапикере https://github.com/Codesrc-public-ru/datepicker модули как раз явные. И такой подход снижает риск скрытых дефектов в разы.
-
Системный инжиниринг смещает ошибки на уровень юнитов. Если календарь неправильно показывает февраль в високосный год, мы знаем, что проблема находится в одной конкретной чистой функции в слое Core. Эта ошибка легко покрывается юнит-тестом и исправляется изолированно. Мы не чиним «компонент», мы чиним «алгоритм».
Итог: это не битва, а выбор стратегии управления рисками
Становится очевидно, что это не спор о том, «что лучше». Это стратегический выбор, основанный на контексте.
AI-драфтинг — это стратегия для задач с низкой ценой ошибки:
-
Прототипы и MVP: когда нужно быстро проверить гипотезу и выкинуть.
-
R&D и хакатоны: когда скорость исследования важнее долгосрочной поддержки.
-
Изолированные, некритичные утилиты.
Системный инжиниринг — это стратегия для задач с высокой ценой ошибки:
-
Разработка дизайн-систем: где каждый компонент — это продукт для десятков других команд.
-
Создание ядра приложения: где надежность и предсказуемость — не пустые слова.
-
Долгосрочные проекты: где вы знаете, что компонент будет жить, развиваться и рефакториться годами.
Познакомиться с нашим интерактивным проектом можно по ссылке: https://ralf-datapicker.netlify.app/
Наш следующий шаг — гибридный подход. Мы продолжим использовать системный инжиниринг для проектирования, но будем делегировать AI рутинные, хорошо формализованные задачи. Например: «Вот спецификация нашего математического ядра и тесты. Напиши Storybook-истории для вот этого ‘глупого’ UI-компонента сетки календаря».
AI — это мощнейший ускоритель, но он не заменяет инженера. Он заменяет рутину. А задача инженера — как раз и состоит в том, чтобы спроектировать систему, в которой рутинных, предсказуемых задач будет как можно больше.
Автор статьи: Ищенко Тимофей @Is_Tim, senior frontend-разработчик в “Исходном Коде”.
А какой стратегии придерживаетесь вы? Где для вас проходит граница, за которой скорость перестает оправдывать риски?
ссылка на оригинал статьи https://habr.com/ru/articles/1028440/