Каждый Android-разработчик знает это чувство: Compose-экран готов на 80%, а оставшиеся 20% — это состояния, рекомпозиции и «почему не обновляется». Или корутина, которая в проде падает с CancellationException, хотя в тестах всё зелёное. LLM не заменит вас, но снимет рутину, если задавать правильные вопросы.
Ниже — 13 промтов, которые я гоняю в работе над Kotlin-проектами: от Compose UI до Room и Flow. Каждый — с реальным примером, который можно скопировать и адаптировать. Важно: модель не знает вашего проекта, поэтому в промт всегда вкладывайте версию Kotlin, AGP, Compose BOM и фрагмент кода — иначе получите советы из 2022 года.
collectAsState() там, где проект уже на collectAsStateWithLifecycle().
Compose UI: от макета до превью
1. «Разложи экран на stateless-компоненты»
Промт: «Вот @Composable-функция на 120 строк. Разбей её на stateless-компоненты по принципу single responsibility, вынеси состояние в hoisted-параметры и покажи, какие превью (@Preview) добавить для каждого состояния: loading, empty, error, data».
Зачем: Compose любит маленькие функции. Модель хорошо справляется с механической декомпозицией, а вы проверяете, что state hoisting не сломал порядок аргументов.
2. «Почему это рекомпозируется лишний раз»
Промт: «Проанализируй код: какие значения читаются внутри composable и вызывают рекомпозицию? Предложи варианты: derivedStateOf, remember(key), key() в списке, стабильные data-классы. Покажи diff».
Реальный кейс: список с items(list) { LazyRowItem(it) } дёргался на каждое изменение счётчика в родителе. Причина — нестабильный лямбда-колбэк, создаваемый в композиции. Фикс: remember(list) { ... } и вынос колбэка.
3. «Сгенерируй @Preview для всех состояний»
Промт: «Для этого экрана создай набор @Preview: тёмная/светлая тема, шрифт 1.0 и 1.3, состояния loading/error/empty. Используй @PreviewParameter с провайдером. Не дублируй логику — только UI-состояния».
./gradlew :app:compileDebugKotlin — LLM часто забывает импорты androidx.compose.ui.tooling.preview.Preview и путает пакеты material3.
Корутины и Flow: где LLM реально помогает
4. «Объясни scope и найди утечку»
Промт: «Вот ViewModel и repository. Найди места, где корутина запускается в неправильном scope, где GlobalScope, где нет withContext(Dispatchers.IO) вокруг блокирующего вызова. Предложи исправленный вариант с viewModelScope и supervisorScope».
Корутины — самая частая тема ошибок: launch в viewModelScope с try/catch, который глотает CancellationException, ломает отмену. Модель хорошо ловит такие паттерны, если дать ей полный контекст класса.
5. «Преврати callback-API в Flow»
Промт: «У меня есть listener-based API (например, LocationManager или Bluetooth). Оберни его в callbackFlow с awaitClose, добавь buffer и обработку trySend. Покажи, как подписаться во ViewModel через stateIn с SharingStarted.WhileSubscribed(5000)».
Этот промт закрывает классическую проблему: слушатель не отписывается при уходе с экрана. awaitClose — обязательный элемент, и LLM о нём помнит, если явно попросить.
6. «Тест на корутины без flaky»
Промт: «Напиши unit-тест для suspend-функции с задержкой. Используй runTest, StandardTestDispatcher, advanceUntilIdle. Не используй Thread.sleep. Покажи, как подменить Dispatchers.Main через Dispatchers.setMain».
Без Dispatchers.setMain тесты ViewModel падают с Module with the Main dispatcher had failed to initialize. Это неочевидно для новичков, и промт сразу закрывает грабли.
runTest управляет виртуальным временем, а Thread.sleep — реальным. Смешивание даёт тесты, которые проходят локально и падают в CI. Всегда просите LLM использовать advanceUntilIdle и StandardTestDispatcher.
Room и данные
7. «Сгенерируй Entity, DAO и миграцию»
Промт: «Создай Room Entity для таблицы orders (id, userId, amount, status, createdAt). Добавь DAO с Flow-запросом и пагинацией. Напиши миграцию с версии 2 на 3: добавь колонку status с дефолтом. Покажи Migration-класс и тест миграции через MigrationTestHelper».
Версия Room важна: в новых версиях KSP заменил kapt, и синтаксис @Database отличается. Указывайте версию явно.
8. «Найди N+1 и предложи @Relation»
Промт: «Вот два Entity и запрос, который в цикле достаёт связанные данные. Перепиши через @Relation или @Transaction, покажи, как изменится DAO и модель. Объясни trade-off: eager-загрузка против отдельных запросов».
Типичная ошибка: Flow<List<Order>> + внутри маппинг с отдельными запросами. Модель предложит @Transaction и @Relation, но проверьте, что не появилось лишних JOIN.
9. «Тест миграции, который ловит потерю данных»
Промт: «Напиши инструментальный тест миграции Room с версии 2 на 3: создай БД версии 2, вставь строки, примени миграцию, проверь, что данные на месте и схема совпадает. Используй MigrationTestHelper и runMigrationsAndValidate».
fallbackToDestructiveMigration() как «простое решение». В проде это стирает данные пользователей. Просите миграцию явно и тестируйте её.
Сеть, DI и архитектура
10. «Retrofit + сериализация: разбери ошибку»
Промт: «Вот ответ API и data-класс. Ошибка MissingFieldException. Объясни, почему kotlinx.serialization падает, и предложи варианты: @SerialName, ignoreUnknownKeys = true, explicitNulls = false. Покажи настройку Json».
Классика: бэкенд добавляет поле, приложение падает. ignoreUnknownKeys решает, но маскирует контрактные проблемы — trade-off, который стоит обсудить с командой.
11. «Hilt: почему не инжектится»
Промт: «Вот модуль Hilt и класс с @Inject constructor. Приложение падает с MissingBinding. Проверь scope, qualifiers и наличие @InstallIn. Предложи минимальный фикс и объясни, как читать граф зависимостей».
12. «Сгенерируй UseCase и проверь границы слоёв»
Промт: «Раздели эту ViewModel на UseCase-классы. Проверь, что ViewModel не знает про Retrofit/Room, а repository не знает про Android-контекст. Покажи итоговую структуру пакетов».
Рефакторинг и ревью
13. «Переведи Java-код на идиоматичный Kotlin»
Промт: «Перепиши этот Java-класс на Kotlin: используй data class, sealed interface вместо enum с логикой, when вместо switch, by lazy вместо double-checked locking. Покажи diff и объясни каждое изменение».
Этот промт хорошо работает в паре с подходом из материала Go без C-привычек: 12 промтов, которые заставят LLM писать идиоматичный код — там та же логика: просить идиоматику, а не «работающий» код.
Что в итоге
Промты не отменяют ревью и тесты — они снимают механическую часть: декомпозицию, обёртки, миграции, превью. Самые полезные — те, где вы даёте контекст: версии, фрагмент кода, ожидаемое поведение. И всегда проверяйте сгенерированный код компилятором и тестами, особенно вокруг корутин и Room.
Если хотите глубже — посмотрите, как выстраивать ревью и менторство в команде в статье Tech Lead (менторство, code review): как перейти от senior-разработчика к тимлиду. А для тестов на LLM пригодится подход из Юнит-тесты на Python с LLM: 12 промтов от pytest-фикстур до Hypothesis.