В современной разработке искусственный интеллект (ИИ) стал мощным инструментом, но его слепое применение часто приводит к появлению низкокачественного, сложного в поддержке кода. Парадокс, описанный в статье Нолана Лоусона «Using AI to write better code more slowly», заключается в том, что для улучшения качества кода с помощью ИИ разработчику необходимо сознательно замедлиться. Вместо того чтобы использовать ИИ для автоматической генерации больших объемов кода, мы будем применять его как «умного стажера»: для рефакторинга, написания тестов и документирования небольшими итерациями. Этот подход позволяет сохранить контроль над архитектурой, улучшить читаемость и снизить технический долг. В этом туториале вы научитесь использовать ИИ для пошагового улучшения существующего кода на TypeScript, применяя принцип «лучше, но медленнее».
Для начала нам нужно настроить среду, которая будет способствовать осознанной работе с ИИ. Мы будем использовать VS Code с расширением GitHub Copilot (или аналогичным, например, Codeium или Tabnine). Ключевой принцип - не просить ИИ написать весь модуль целиком. Вместо этого мы разобьем задачу на микрошаги.
# Установите расширение GitHub Copilot в VS Code
# Настройте его на работу с вашим проектом TypeScript
# Убедитесь, что у вас установлен Node.js и TypeScript
Создайте простой файл index.ts с типичной «грязной» функцией, которая обрабатывает данные пользователя. Это будет наша стартовая точка.
// index.ts - первая версия
function processUserData(data: any) {
const user = data.user;
const name = user.name;
const age = user.age;
if (age > 18) {
console.log("Adult user: " + name);
return { status: "success", message: "User processed" };
} else {
console.log("Minor user: " + name);
return { status: "skipped", message: "User is minor" };
}
}
Теперь мы начнем применять ИИ для улучшения этого кода, но медленно и вдумчиво. Вместо того чтобы просить «перепиши всю функцию», зададим конкретный, узкий промпт. Откройте палитру команд Copilot (Ctrl+Shift+I) или используйте встроенный чат.
Промпт 1: Улучшить типизацию. Выделите код и напишите: «Улучши типизацию для этого кода, используя TypeScript. Создай интерфейсы для всех объектов. Не меняй логику, только типы.»
// Результат после промпта
interface User {
name: string;
age: number;
}
interface ProcessResult {
status: 'success' | 'skipped';
message: string;
}
function processUserData(data: { user: User }): ProcessResult {
const { user } = data;
const { name, age } = user;
if (age > 18) {
console.log("Adult user: " + name);
return { status: "success", message: "User processed" };
} else {
console.log("Minor user: " + name);
return { status: "skipped", message: "User is minor" };
}
}
Промпт 2: Разделение ответственности. Теперь, когда типы улучшены, попросите ИИ: «Вынеси логику логирования в отдельную функцию. Логика принятия решения о статусе должна остаться в основной функции, но вывод на консоль выдели.»
// Результат после второго промпта
function logUserActivity(name: string, isAdult: boolean): void {
const label = isAdult ? "Adult" : "Minor";
console.log(`${label} user: ${name}`);
}
function processUserData(data: { user: User }): ProcessResult {
const { user } = data;
const { name, age } = user;
const isAdult = age > 18;
logUserActivity(name, isAdult);
return isAdult
? { status: "success", message: "User processed" }
: { status: "skipped", message: "User is minor" };
}
Обратите внимание: мы сделали два маленьких шага, каждый раз проверяя результат. Это «медленное» улучшение, которое гарантирует, что код остается понятным и корректным.
Теперь, когда код стал чище, самое время добавить тесты. Используйте ИИ для генерации тестовых случаев, но снова - итеративно. Попросите: «Напиши тест для функции processUserData, который проверяет случай с совершеннолетним пользователем. Используй Jest.»
// processUserData.test.ts
import { processUserData } from './index';
describe('processUserData', () => {
it('should return success for adult user', () => {
const result = processUserData({
user: { name: 'Alice', age: 25 }
});
expect(result).toEqual({
status: 'success',
message: 'User processed'
});
});
it('should return skipped for minor user', () => {
const result = processUserData({
user: { name: 'Bob', age: 17 }
});
expect(result).toEqual({
status: 'skipped',
message: 'User is minor'
});
});
});
Повторите процесс для граничных случаев (age = 18, пустой объект user). Каждый новый тест - это отдельный запрос к ИИ. Так вы контролируете покрытие и не позволяете ИИ генерировать избыточные или бессмысленные тесты.
Последний шаг - добавление JSDoc и комментариев. Снова используйте ИИ для конкретной задачи: «Добавь JSDoc комментарии для функции processUserData и logUserActivity. Опиши параметры и возвращаемые значения.» ИИ сгенерирует документацию, которую вы должны проверить на точность. Удалите лишнее, оставьте только полезное.
/**
* Обрабатывает данные пользователя и возвращает результат.
* @param data - Объект, содержащий пользователя (user).
* @returns Объект ProcessResult со статусом и сообщением.
*/
function processUserData(data: { user: User }): ProcessResult {
// ... код
}
В этом туториале вы научились применять ИИ для написания лучшего кода, но медленнее. Вместо того чтобы делегировать ИИ всю задачу, мы разбили её на микрошаги: улучшение типов, рефакторинг, написание тестов, документирование. Каждый шаг проверяется и осмысливается разработчиком. Такой подход снижает риск появления «галлюцинаций» ИИ и сложного для понимания кода. Помните: ИИ - это отличный инструмент для рутинных задач, но архитектурные решения и контроль качества остаются за человеком. Используйте этот метод в своих проектах, чтобы писать код, который будет легко поддерживать и развивать.
Комментариев пока нет