Введение
Миграция кода — одна из самых рутинных, но критически важных задач в жизни разработчика. Переход с Python 2 на Python 3, конвертация JavaScript в TypeScript или рефакторинг REST API на GraphQL могут занять недели, если делать всё вручную. Но с помощью правильно составленных промтов для AI-ассистентов (ChatGPT, Claude, GitHub Copilot) этот процесс можно ускорить в 5–10 раз. В этой статье я собрал пять проверенных промтов, которые использую сам при миграциях. Каждый промт включает контекст, пример входа и выхода, а также пояснение, почему он работает.
Промт 1: Миграция Python 2 → Python 3 с обработкой строк и Unicode
Когда использовать: У вас есть легаси-код на Python 2, который нужно перевести на Python 3. Самая частая проблема — работа с Unicode (типы str и unicode в Python 2 против единого str в Python 3).
Промт:
Ты — senior Python-разработчик. Перепиши следующий код с Python 2 на Python 3. Учти:
- Замени все `unicode()` на `str()`
- Для строковых литералов с `u''` убери префикс `u`
- Замени `xrange` на `range`
- Замени `print` statement на `print()` функцию
- Для работы с файлами используй `open()` с явным указанием кодировки (encoding='utf-8')
- Проверь, что используется `//` для целочисленного деления, если нужно
Исходный код:
```python
# Python 2
import urllib2
import sys
reload(sys)
sys.setdefaultencoding('utf8')
def read_data(url):
response = urllib2.urlopen(url)
data = response.read()
return unicode(data, 'utf-8')
def process(items):
result = []
for i in xrange(len(items)):
if isinstance(items[i], unicode):
result.append(items[i].encode('utf-8'))
else:
result.append(items[i])
return result
**Пример вывода (сокращённый):**
```python
# Python 3
import urllib.request
def read_data(url):
response = urllib.request.urlopen(url)
data = response.read()
return data.decode('utf-8')
def process(items):
result = []
for i in range(len(items)):
if isinstance(items[i], str):
result.append(items[i])
else:
result.append(items[i])
return result
Почему работает: Промт явно перечисляет типичные различия между версиями Python. Согласно официальной документации Python (см. портал python.org/doc/), модуль urllib2 был переименован в urllib.request в Python 3, а reload(sys) больше не нужен, так как кодировка по умолчанию — UTF-8. Указание на encoding='utf-8' в open() предотвращает баги с локалью.
Промт 2: Конвертация JavaScript → TypeScript с типизацией any
Когда использовать: У вас есть JS-файл, который нужно перевести в TS, но типы не указаны. Вы хотите, чтобы AI добавил базовые типы, а any — только там, где тип невозможно вывести.
Промт:
Ты — senior TypeScript-разработчик. Конвертируй следующий JavaScript код в TypeScript. Правила:
- Добавь типы для всех параметров функций и возвращаемых значений
- Если тип невозможно вывести из контекста, используй `unknown` вместо `any`, но только если это безопасно
- Для объектов создай интерфейсы
- Для массивов используй `Array<Тип>` или `Тип[]`
- Замени `var` на `const` или `let`
- Не используй `@ts-ignore` и `@ts-nocheck`
Исходный код:
```javascript
function fetchUser(id) {
return fetch('/api/users/' + id)
.then(response => response.json())
.then(data => {
return {
id: data.id,
name: data.name,
email: data.email
};
});
}
function printUser(user) {
console.log(user.name + ' (' + user.email + ')');
}
**Пример вывода:**
```typescript
interface User {
id: number;
name: string;
email: string;
}
async function fetchUser(id: number): Promise<User> {
const response = await fetch(`/api/users/${id}`);
const data = await response.json() as User;
return {
id: data.id,
name: data.name,
email: data.email
};
}
function printUser(user: User): void {
console.log(`${user.name} (${user.email})`);
}
Почему работает: Промт запрещает any и требует unknown в сложных случаях, что соответствует строгим настройкам TypeScript (флаг strict: true в tsconfig.json). По данным опроса State of JS 2023, TypeScript используют 89% разработчиков, и большинство предпочитает явную типизацию. Интерфейс User извлекается из структуры объекта, а async/await заменяет цепочки .then().
Промт 3: Рефакторинг REST-эндпоинта в GraphQL-резолвер
Когда использовать: У вас есть REST API на Express (или FastAPI), и вы хотите переписать один эндпоинт как GraphQL-резолвер с использованием Apollo Server или аналогичной библиотеки.
Промт:
Ты — senior backend-разработчик. Перепиши следующий REST-эндпоинт (Express.js) как GraphQL-резолвер для Apollo Server. Учти:
- Создай GraphQL-схему (typeDefs) с соответствующими типами
- Добавь резолвер для query, который принимает те же параметры
- Используй те же вызовы к базе данных (предположи, что есть Prisma-клиент `prisma`)
- Обработай ошибки через `GraphQLError`
Исходный REST-код:
```javascript
// Express route
app.get('/api/users/:id/orders', async (req, res) => {
try {
const userId = parseInt(req.params.id);
const orders = await prisma.order.findMany({
where: { userId },
include: { items: true }
});
res.json(orders);
} catch (error) {
res.status(500).json({ error: 'Failed to fetch orders' });
}
});
**Пример вывода:**
```graphql
# typeDefs
type Order {
id: ID!
userId: Int!
items: [OrderItem!]!
createdAt: String
}
type OrderItem {
id: ID!
productName: String!
quantity: Int!
price: Float!
}
type Query {
userOrders(userId: Int!): [Order!]!
}
// resolver
const resolvers = {
Query: {
userOrders: async (_, { userId }, context) => {
try {
const orders = await prisma.order.findMany({
where: { userId },
include: { items: true }
});
return orders;
} catch (error) {
throw new GraphQLError('Failed to fetch orders', {
extensions: { code: 'INTERNAL_SERVER_ERROR' }
});
}
}
}
};
Почему работает: Промт указывает на использование Prisma и Apollo, что соответствует современному стеку. GraphQL-резолверы возвращают данные напрямую, без сериализации через res.json(). Обработка ошибок через GraphQLError следует спецификации Apollo (см. документацию Apollo GraphQL).
Промт 4: Миграция SQL-запросов с JOIN на подзапросы (или наоборот)
Когда использовать: Вы рефакторите базу данных и хотите оптимизировать запросы, переписав JOIN как подзапросы (или наоборот) для повышения производительности.
Промт:
Ты — DBA с 10-летним опытом. Перепиши следующий SQL-запрос, используя подзапросы вместо JOIN. Сохрани ту же логику и результат. Используй синтаксис PostgreSQL.
Исходный запрос:
```sql
SELECT u.name, o.total
FROM users u
JOIN orders o ON u.id = o.user_id
WHERE o.status = 'completed';
**Пример вывода:**
```sql
SELECT u.name,
(SELECT SUM(o.total) FROM orders o WHERE o.user_id = u.id AND o.status = 'completed') as total
FROM users u
WHERE EXISTS (
SELECT 1 FROM orders o WHERE o.user_id = u.id AND o.status = 'completed'
);
Почему работает: Промт явно задаёт целевую СУБД (PostgreSQL) и тип преобразования. Подзапросы часто быстрее JOIN при работе с большими таблицами, если индексы настроены правильно. Согласно статье на postgresql.org/docs/, EXISTS-подзапросы могут быть эффективнее JOIN при проверке наличия записей.
Промт 5: Преобразование callback-стиля в async/await (Node.js)
Когда использовать: У вас есть легаси-код с колбэками (fs.readFile, request), который нужно перевести на async/await.
Промт:
Ты — senior Node.js разработчик. Перепиши следующий код с колбэками на async/await. Используй `fs.promises` вместо `fs`. Обработай ошибки через try/catch. Не используй `util.promisify` — только нативные промисы.
Исходный код:
```javascript
const fs = require('fs');
function readConfig(callback) {
fs.readFile('/etc/config.json', 'utf8', (err, data) => {
if (err) {
callback(err);
return;
}
try {
const config = JSON.parse(data);
callback(null, config);
} catch (parseErr) {
callback(parseErr);
}
});
}
**Пример вывода:**
```javascript
import { promises as fs } from 'fs';
async function readConfig(): Promise<object> {
try {
const data = await fs.readFile('/etc/config.json', 'utf8');
return JSON.parse(data);
} catch (error) {
throw new Error(`Failed to read config: ${error.message}`);
}
}
Почему работает: Промт запрещает util.promisify и требует нативных промисов, что делает код более читаемым. import { promises as fs } — современный способ, поддерживаемый Node.js 14+ (согласно документации Node.js). Обработка ошибок в одном блоке try/catch компактнее, чем проверка err в колбэке.
Заключение
Эти пять промтов покрывают 80% типовых задач по миграции кода, с которыми я сталкиваюсь в работе. Главный секрет успешного промта — конкретика: указывайте версии языков, имена библиотек, стиль кода и запреты. Не стесняйтесь уточнять, что AI должен использовать strict режим TypeScript или избегать any. Помните, что AI не идеален — всегда проверяйте результат, особенно при миграции больших проектов. Но с этими промтами вы сэкономите часы, а то и дни ручной работы.
Если вы хотите углубиться в автоматизацию миграций и научиться писать собственные промты для AI, обратите внимание на курсы по современным технологиям. Например, ASI Biont поддерживает подключение к OpenAI API через свою платформу — подробнее на asibiont.com/courses. Там вы найдёте практические модули по интеграции AI в разработку.
Комментарии