LLM уверенно генерирует код, но как только задача выходит за пределы функции на 20 строк, качество ответа падает. Причина не в модели — в постановке. «Отрефактори этот файл» даёт косметику, а «найди места, где тип any маскирует nullable-поле из API, и предложи discriminated union» — реальные изменения.
Ниже — 12 промтов для веб-разработки, разбитых на три уровня. Базовые снимают рутину, продвинутые заставляют модель думать о типах и границах, экспертные работают с архитектурой и эксплуатацией. Каждый — с задачей, готовым текстом и разбором того, что он реально даёт и где ломается.
Общий принцип: промт для кода — это техническое задание, а не вопрос. Чем точнее в нём границы (версии, ограничения, формат ответа), тем меньше правок после.
Базовый уровень: снять рутину и привести код к стандарту
1. Строгий TypeScript-конфиг без сюрпризов
Задача: включить strict в проекте, где накопились десятки ошибок, и не утонуть в них.
Ты senior TypeScript-инженер. У меня проект на TS 5.x с tsconfig,
где strict выключен. Включи strict по группам и объясни порядок:
1) Какие флаги дают максимум пользы при минимуме правок
(noImplicitAny, strictNullChecks, strictFunctionTypes).
2) Какие ломают больше всего legacy-кода и почему.
3) Дай пошаговый план миграции: какую группу включать первой,
как временно подавлять ошибки точечно (не глобально).
Формат: таблица флаг → эффект → риск → порядок включения.
Код не пиши, только план и примеры tsconfig-фрагментов.
Что получаете: план миграции и таблицу флагов. Полезный неочевидный вывод, который модель обычно выдаёт при таком промте: strictNullChecks почти всегда даёт больше пользы, чем noImplicitAny, потому что ловит реальные падения на undefined, а не косметику аннотаций. Порядок включения важнее самого факта включения — если включить всё сразу, PR на 800 файлов никто не отревьюит.
strictPropertyInitialization — она часть strict, но требует отдельного внимания к классам.
2. Генерация discriminated union для состояний UI
Задача: превратить набор булевых флагов (isLoading, isError, data) в тип, где невозможные состояния не компилируются.
Преобразуй состояние этого React-компонента из набора флагов
в discriminated union. Требования:
- Состояния: idle | loading | success | error.
- У success обязателен data, у error — message, у loading — нет лишних полей.
- Покажи тип, функцию-редьюсер переходов и компонент,
который через switch гарантирует исчерпывающую проверку (exhaustiveness).
- В конце функции-редьюсера — проверка never.
Исходный код: <вставьте состояние компонента>
Пример результата: тип `type State = {status:'idle'}
| {status:'loading'} | {status:'success', data: User} | {status:'error', message: string}, редьюсер наswitch(state.status)иdefault: const _exhaustive: never = state`. Компилятор теперь не даст забыть новое состояние.
3. Быстрый code review по диффу
Задача: получить ревью пул-реквеста до того, как его посмотрит человек.
Ревью diff как тимлид. Проверь по чек-листу:
- обработка ошибок и rejected promises (нет ли незакрытых catch);
- мутации входных параметров;
- утечки: подписки, таймеры, event listeners без cleanup;
- N+1 запросы к БД в цикле;
- отличия от принятого в проекте стиля.
Для каждой проблемы: строка, почему это баг (а не вкусовщина),
как исправить. Если проблем нет — скажи прямо, не выдумывай.
Diff: <вставьте diff>
Ключевая фраза здесь — «если проблем нет — скажи прямо». Без неё модель почти всегда «находит» замечания, чтобы оправдать запрос, и вы тратите время на разбор несуществующих багов.
Продвинутый уровень: типы, рефакторинг, производительность
4. Рефакторинг legacy-кода с сохранением поведения
Задача: разобрать функцию на 200 строк без риска сломать логику.
Разбей эту функцию на чистые подфункции. Жёсткие условия:
- Поведение не меняется: те же побочные эффекты, тот же порядок.
- Сначала перечисли побочные эффекты и внешние зависимости.
- Покажи, какие тесты нужны ДО рефакторинга, чтобы зафиксировать поведение.
- Если функция не чистая — укажи, что мешает, и предложи минимальный шаг.
Код: <вставьте функцию>
Trade-off, который стоит проговорить: разбиение на мелкие функции улучшает читаемость, но добавляет уровни в стек вызовов и усложняет отладку в профайлере. Для горячего пути (обработка каждого запроса) иногда лучше оставить плотную функцию с комментариями, чем дробить ради красоты.
5. Типизация ответа внешнего API без any
Задача: описать контракт чужого API так, чтобы изменения на их стороне ловились в рантайме.
У меня есть пример JSON-ответа от API. Сгенерируй TypeScript-типы
и runtime-валидатор (zod). Требования:
- Опциональные поля — явно, с пояснением, что значит отсутствие.
- Для полей-перечислений — union из литералов, не string.
- Покажи, как валидатор превращает «грязный» ответ в безопасный тип
и что делать при несовпадении (не молча падать).
JSON: <вставьте ответ>
User не защищает от того, что сервер вернёт строку вместо числа. Тип описывает ваши ожидания, а zod-схема проверяет реальность. Для внешних границ нужны оба: тип для разработчика, схема для рантайма.
6. Оптимизация React-рендеров по профайлеру
Задача: убрать лишние перерисовки, не расставляя useMemo вслепую.
Вот дерево компонентов и вывод React Profiler (какие компоненты
рендерятся и сколько мс). Найди причины лишних рендеров:
- нестабильные ссылки в пропсах (объекты/функции в inline);
- контекст, который меняется целиком;
- отсутствие мемоизации там, где она реально нужна.
Предложи минимальный набор изменений. Для каждого — оцени,
что выигрываем и чем платим (память, сложность).
Не предлагай useMemo для примитивов.
Модель при таком промте обычно честно называет цену: мемоизация каждого пропса увеличивает потребление памяти и усложняет код, а выигрыш на компонентах, которые рендерятся редко, стремится к нулю. Правило — оптимизировать только то, что видно в профайлере.
7. Безопасные SQL/ORM-запросы в Node.js
Задача: убрать N+1 и SQL-инъекции до код-ревью.
Проверь этот код доступа к БД (Prisma/TypeORM/Knex) на:
- N+1 запросы (запрос в цикле, ленивые связи);
- конкатенацию пользовательского ввода в запрос;
- отсутствие транзакций там, где несколько записей меняются вместе.
Для каждой находки: почему это проблема, как переписать,
какой индекс может понадобиться. Код: <вставьте репозиторий>
8. Обработка ошибок и ретраи на границе сети
Задача: сделать так, чтобы падение внешнего сервиса не роняло весь запрос.
Спроектируй слой вызовов внешнего HTTP-API. Требования:
- таймауты, ретраи с экспоненциальной задержкой и jitter;
- какие статусы ретраить (5xx, 429), какие нет (4xx кроме 429);
- идемпотентность: как не задвоить операцию при повторе;
- что логировать, чтобы разбирать инциденты.
Покажи код на Node.js без лишних зависимостей.
Неочевидный момент: ретраить 4xx бессмысленно — повтор не исправит неверный запрос, только добавит нагрузку. Jitter в задержке нужен, чтобы при массовом сбое клиенты не били по серверу синхронной волной.
Экспертный уровень: архитектура, эксплуатация, деплой
9. Проектирование модульной архитектуры фронтенда
Задача: нарезать большое приложение на слои без циклических зависимостей.
Спроектируй структуру фронтенд-приложения (React + TypeScript)
по слоям: shared → entities → features → pages → app.
Правила:
- зависимости только в одну сторону, без циклов;
- где живут API-клиенты, типы домена, UI-кит;
- как проверить нарушения автоматически (ESLint-правило границ).
Дай дерево папок и пример конфигурации ограничений импорта.
Это методология Feature-Sliced Design. Модель хорошо воспроизводит её правила, но проверяйте конфиг линтера: конкретный синтаксис плагина границ импорта меняется между версиями.
10. Аудит производительности Node.js-сервиса
Задача: найти узкие места до того, как сервис упадёт под нагрузкой.
Проанализируй Node.js-сервис на предмет блокировки event loop:
- синхронные операции в обработчиках (fs, crypto, тяжёлый JSON);
- неограниченные очереди и отсутствие backpressure;
- утечки памяти (растущие Map/Set, незакрытые соединения).
Для каждой находки: как воспроизвести проблему локально
и как измерить эффект исправления. Код: <вставьте модуль>
11. Промт под CI/CD: пайплайн с проверками
Задача: собрать пайплайн, который ловит ошибки до мержа.
Сгенерируй GitHub Actions workflow для JS/TS-проекта:
- install с кэшем зависимостей;
- typecheck, lint, unit-тесты, сборка;
- запуск только на PR и на основной ветке;
- артефакт сборки.
Объясни, какие шаги можно распараллелить и что даст кэш.
npm ci без кэша и запускать все шаги последовательно. Проверьте, что кэш ключуется по lock-файлу, иначе он бесполезен, а иногда и вреден — восстановит устаревшие зависимости.
12. Стратегия деплоя и отката
Задача: продумать релиз так, чтобы ошибка не стоила часа простоя.
Предложи стратегию деплоя для веб-приложения (frontend + API):
- blue-green или canary, с обоснованием выбора;
- как откатывать миграции БД, которые нельзя откатить;
- что проверять в первые минуты после релиза (метрики, алерты);
- чек-лист «релиз готов / откатываем».
Учти, что миграции схемы — самая частая причина неудачных откатов.
Самый ценный вывод здесь: откат кода — дешёвая операция, откат схемы БД — часто невозможен. Поэтому миграции делают обратно совместимыми (сначала добавить колонку, потом переключить чтение, потом убрать старую), а не пытаются откатить всё разом.
Как выбирать уровень промта
| Уровень | Когда применять | Главный риск |
|---|---|---|
| Базовый | Рутина, стандарты, ревью | Модель «находит» несуществующие баги |
| Продвинутый | Типы, рефакторинг, производительность | Оптимизация без профайлера |
| Экспертный | Архитектура, CI/CD, деплой | Уверенный, но устаревший синтаксис |
Общее правило: чем выше уровень, тем важнее давать модели контекст (версии, код, вывод инструментов) и просить обоснования и trade-off, а не только готовый ответ. Промт без границ даёт красивый код, который ломается на первом же нестандартном случае.
Похожий подход — с явными границами и разбором отказов — мы разбираем в материале про юнит-тесты на Python с LLM: механика постановки задачи там та же, меняется только стек.
Начните с одного промта на реальной задаче из своего проекта. Сравните результат с тем, что вы бы написали сами: разница покажет, где модели не хватает контекста, — именно туда стоит добавлять ограничения в следующий раз. Хороший промт для JavaScript и TypeScript — это не магия формулировки, а честное техническое задание с границами и критериями готовности.