Головна / Статті / Коли ШІ пише ваш React-додаток, але ігнорує принципи чистого коду

Коли ШІ пише ваш React-додаток, але ігнорує принципи чистого коду

Дізнайтеся про сім звичок чистого коду — DRY, принцип єдиної відповідальності, клозули-захисники та інші — які часто порушуються у React-коді, створеному штучним інтелектом, та як їх виправити.

2427 слів

Нещодавно клієнт передав проект зі створення веб-сайту для замовлення піци.

Спочатку обсяг роботи здавався контрольованим.

Сторінка приземлення.

Розділ з меню.

Різні категорії піци.

Окремі сторінки продуктів.

Кошик покупок.

Процес оформлення замовлення.

А також панель адміністратора для керування всім на задньому плані.

Природним припущенням було:

"Це має зайняти небагато часу."

Потім було прийнято рішення скористатися допомогою AI-асистента для програмування.

Саме тоді справи стали цікавими.

Доручення AI більшої частини роботи з кодування

Проект було створено за допомогою React.

Замість того, щоб вручну писати кожен рядок, до AI надсилали запити для створення кожної частини.

Запит на кшталт:

"Створіть компонент картки піци."

негайно генерував цей компонент.

Далі:

«Створіть кошик для покупок».

Виконано.

Далі:

«Створіть екран оформлення замовлення».

Також виконано.

Далі:

«Створіть панель керування для адміністратора зі статистикою, замовленнями та інформацією про клієнтів».

Готово.

Швидкість була справді вражаючою.

Робота, яка зазвичай займає години, виконувалась протягом кількох хвилин.

Результат включав:

  • Компоненти React
  • Форми
  • Таблиці даних
  • Віджети панелі керування
  • Інтеграція з API
  • Індикатори завантаження
  • Обробка помилок
  • Макети, які адаптуються до розміру екрана

І додаток справді працював.

Усе виглядало перспективно.

Здавалося, що знайдений ідеальний процес роботи:

Ідея → Запит → Код → Реліз

Але бракувало одного важливого кроку.

Перевірка того, що було створено.

Клієнт так і не побачив сам код

З точки зору клієнта все виглядало чудово.

Сайт працював без проблем.

Панель керування функціонувала належним чином.

Меню відображалося правильно.

Замовлення з’являлися так, як і очікувалося.

Візуально все було досконале.

То в чому ж була проблема?

Проблему не можна було побачити ззовні.

Під спудом база коду поступово перетворювалася на джерело проблем під час технічного обслуговування.

Спочатку це не було очевидно.

Але коли додавалося все більше функцій, почала проявлятися певна закономірність.

Постійно з’являлася одна думка:

"Чекайте... хіба щось майже ідентичне цьому вже не було створено?"

Саме тоді виникло важливе усвідомлення:

Штучний інтелект справді добре вміє створювати функціональний код.

Але чистий код — це не те, що він генерує автоматично.

Проблема №1: Повторювана логіка скрізь

Майже ідентична логіка виявилася розкиданою по всьому додатку.

Наприклад, кілька окремих функцій обчислювали суми незалежно одна від одної.

const total = price * quantity;

В інших місцях з’являлася майже ідентична версія:

const orderTotal = price * quantity;

А ще в одному файлі:

const cartAmount = price * quantity;

Усі три функції по суті виконували однакові обчислення.

З технічної точки зору нічого не було не так.

Але як тільки з’являлася потреба змінити правила формування цін, доводилося знаходити та оновлювати кожну окрему копію коду.

Саме тоді став зрозумілим перший принцип чистого коду.

1. DRY — Не повторюйте себе

Кожного разу, коли одна й та сама логіка з’являється багато разів, варто поставити таке запитання:

Чи можна об’єднати це в один джерело?

Наприклад:

const calculateItemTotal = (price, quantity) => {
  return price * quantity;
};

З того моменту кожна частина додатку може викликати ту саму спільну функцію.

Мета не в тому, щоб примушувати до повторного використання скрізь.

Це просто спосіб усунути дублювання, яке не має жодної мети.

Проблема №2: Один компонент робив усе

У певний момент один із створених файлів React було відкрито для детального розгляду.

Він продовжував зростати.

Рядок за рядком.

Він просто продовжував розширюватися.

Цей єдиний компонент був відповідальний за:

  • Запити до API
  • Керування станом форми
  • Логіку перевірки
  • Видимість модалу
  • Відображення таблиці
  • Фільтрація результатів
  • Сторінкування
  • Повідомлення
  • Коротко кажучи, один файл фактично сам по собі виконував майже половину роботи програми.

    Очевидним висновком було:

    "Підтримка цього буде складною."

    Тож компонент було розділено на менші частини.

    Замість того, щоб зберегти цю структуру:

    Orders.jsx
       ↓
    800+ lines
    

    її було реструктуровано приблизно так:

    Orders
     ├── OrderFilters
     ├── OrderTable
     ├── OrderRow
     ├── OrderModal
     └── useOrders
    

    Ця зміна безпосередньо призвела до наступного принципу.

    2. Єдина відповідальність

    Компонент або функція повинні виконувати одну чітку задачу.

    Якщо ви не можете описати, що робить компонент, за одне речення, існує велика ймовірність того, що він несе занадто багато обов’язків.

    Наприклад:

    OrderTable відображає список замовлень.

    Це чіткий та зосереджений опис.

    Порівняйте його з цим:

    OrderTable отримує замовлення, перевіряє права користувача, обчислює суми, відправляє сповіщення та відображає все у вигляді таблиці.

    Такий тип опису є попереджувальним сигналом.

    Проблема №3: Вкладені оператори if захопили код

    У певний момент частина логіки проекту виглядала так:

    if (user) {
      if (user.isActive) {
        if (user.isVerified) {
          // create order
        }
      }
    }
    

    Він працював коректно.

    Але його аналіз був виснажливим.

    Тож його було переписано як:

    if (!user) return;
    if (!user.isActive) return;
    if (!user.isVerified) return;
    
    // create order
    

    Ця версія була набагато зрозумілішою при першому погляді.

    Саме тут вступає в игру наступна звичка:

    3. Ранні повернення/клозули захисту

    Замість того, щоб ховати основну логіку під кількома рівнями вкладених умов, корисно одразу обробляти недійсні випадки та рано завершувати виконання.

    Invalid?
       ↓
    Return
    
    Invalid?
       ↓
    ReturnEverything okay?
       ↓
    Do the actual work
    

    У результаті основна логіка залишається простою, зрозумілою та без зайвого відступування.

    Проблема №4: Штучний інтелект запропонував нові компоненти для того, що вже існувало

    Ця помилка була дещо ніяковою.

    Запит, який було надано ШІ, звучав так:

    "Створіть модальне вікно підтвердження для видалення замовлення."

    ШІ відповів, створивши абсолютно новий компонент.

    Його майже без запитань прийняли.

    Потім швидкий пошук у проекті виявив щось важливе.

    Компонент модального вікна вже існував.

    Його можна було просто використати знову.

    Цей момент усвідомив одну річ:

    Штучний інтелект не знає автоматично, що вже існує у даній базі коду.

    І навіть коли система справді знає, вона все одно може вирішити створити щось нове замість того, щоб використати наявне.

    Кращим підходом є нагадування щось на кшталт:

    "Перед створенням нового компонента перевірте існуючу базу коду на наявність елементів, які можна використати знову."

    Цей досвід вказує на ще одне правило:

    4. Використовуйте наявне перед створенням

    Перед тим, як додати:

    • новий компонент
    • нову функцію-допоміжник
    • новий користувацький хук
    • нового допоміжника API

    запитайте себе:

    "Чи вже існує це у проекті?"

    Чиста база коду визначається не наявністю десятків елементів, які можна використати знову.

    Вона визначається розробниками, які використовують те, що вже є, замість того, щоб мовчки копіювати його.

    Проблема №5: Імена змінних іноді були жахливими

    Код, створений штучним інтелектом, готовий дуже швидко.

    І легко погодитися з іменами змінних на кшталт:

    const data = ...
    const result = ...
    const x = ...
    const temp = ...
    

    Ці імена компілюються без проблем та не спричиняють помилок.

    Але через кілька місяців до чого насправді відноситься data?

    Це дані про піцу?

    Інформація про замовлення?

    Дані клієнтів?

    Щось, пов’язане з панеллю керування?

    Тож іменування має ставати більш усвідомленим у міру розвитку проекту.

    Замість того, щоб писати:

    const data = await getOrders();
    

    краще використовувати більш зрозумілу версію:

    const orders = await getOrders();
    

    А замість того, щоб:

    const x = users.filter(...);
    

    так буде набагато зрозуміліше:

    const activeUsers = users.filter(...);
    

    Це призводить до ще одного простого правила:

    5. Використовуйте імена, які пояснюють код

    Описове іменування часто дозволяє повністю усунути потребу в коментарях.

    Читаючи щось на кшталт:

    const activeUsers = users.filter(
      (user) => user.isActive
    );
    

    Це вже точно пояснює, що відбувається.

    Немає потреби додавати:

    // Filter users who are currently active
    

    Код говорить сам за себе.

    Проблема №6: Оптимізація того, що не потребує оптимізації

    На певному етапі такого проекту легко почати думати:

    "Цей код потрібно більше оптимізувати."

    Це часто призводить до розгляду таких речей, як:

    useMemo()
    useCallback()
    

    та кількох інших трюків для покращення продуктивності.

    Але варто зупинитися тут.

    Оптимізація не завжди є чимось хорошим.

    Візьмемо простий розрахунок, наприклад:

    const total = price * quantity;
    

    Немає жодних причин обгортати його у складну схему оптимізації лише через наявність інструментів.

    Це лише ускладнить розуміння коду.

    Що веде до ще одного уроку:

    6. Оптимізуйте лише тоді, коли є справжня проблема

    Не поспішайте з оптимізацією через:

    "Хтось в Інтернеті сказав, що цей метод швидший."

    Натомість спочатку знайдіть справжню причину уповільнення.

    Чи компонент переробляється занадто часто?

    Чи виклик API є повільним?

    Чи обчислення справді є складними?

    Чи занадто великий розмір пакета?

    Чи запит до бази даних є неефективним?

    Визначте справжню проблему, перш ніж щось змінювати.

    Лише тоді слід проводити оптимізацію.

    Чистий код плюс зайва оптимізація призводять до зайвої складності.

    Проблема №7: Більше не просити ШІ "виправити все"

    Це, можливо, найважливіший урок від такого проекту.

    Іноді виникає спокуса просто сказати:

    «Просто впорядкуйте для мене весь проект».

    Але краще утриматися від цього.

    Що взагалі означає «впорядкувати» у цьому контексті?

    Штучний інтелект може відповісти так:

    • зміна назв змінних та файлів
    • переорганізація структури папок
    • введення нових абстракцій
    • об’єднання функцій
    • видалення коду, який він вважає зайвим
    • реструктуризація архітектури

    Деякі з цих змін справді можуть допомогти.

    Інші можуть бути марними.

    А деякі можуть тихо внести баги.

    Краще діяти повільно та поетапно.

    Почніть з запитання:

    «Подивіться на цей проект, але поки що нічого не змінюйте».

    Потім:

    «Вкажіть на будь-яку дубльовану логіку».

    Потім:

    «Скажіть мені, які з цих дублікатів справді варто виправляти».

    Лише після цього слід розглянути пропозиції.

    Потім вноситься одна зміна.

    Потім її тестують.

    Це стає сьомим правилом:

    7. Зрозумійте перед тим, як рефакторити

    Ніколи не дозволяйте ШІ працювати з кодом, який спочатку не було повністю зрозуміло.

    Почніть з аналізу.

    Потім переконайтеся, що логіка зрозуміла.

    Потім вирішіть, що робити.

    Потім внесіть зміни.

    Потім перевірте їх за допомогою тесту.

    Що ілюструє веб-сайт з піцою

    Цікаво, але клієнти рідко запитують:

    «Чи чистий ваш код?»

    Зазвичай запитання простіше:

    «Чи працює сайт?»

    І часто він дійсно працює.

    Проте розробники несуть відповідальність, яка виходить за межі першої працездатної версії.

    Програмне забезпечення рідко залишається незмінним після випуску.

    Зрештою клієнт знову звертається з проханням:

    "Чи можемо ми додати відстеження доставки?"

    Потім:

    "Давайте додамо коди знижок."

    Потім:

    "Нам потрібна підтримка кількох філій."

    Потім:

    "Додайте облікові записи для персоналу ресторану."

    Потім:

    "Нам потрібні звіти."

    Незабаром цей невеликий сайт з піцою перетворився на повноцінну систему.

    Саме тоді чистий код починає виправдовувати докладені зусилля.

    Це не вина ШІ

    Тут варто бути справедливими.

    Це не вина ШІ.

    Це справді корисно протягом усього такого процесу створення.

    Це допомагає у:

    • швидшій роботі
    • тестуванні різних підходів
    • виконанні повторюваних завдань з програмування
    • виявленні помилок
    • створенні основи компонентів
    • обґрунтуванні рішень

    Справжня проблема ніколи не полягає у тому, що ШІ генерує код.

    Проблема в тому, що іноді генерований код приймається без належної перевірки.

    Це дві зовсім різні проблеми.

    Оновлений процес роботи з програмуванням за допомогою ШІ

    Після такого проекту доцільно змінити підхід.

    Процес може виглядати приблизно так:

    Understand the requirement
              ↓
    Explore existing code
              ↓
    Plan the solution
              ↓
    Ask AI for implementation
              ↓
    Review the generated code
              ↓
    Simplify
              ↓
    Test
              ↓
    Refactor if necessary
    

    ШІ все ще виконує значну частину фактичного набору коду.

    Але більша частина мислення повертається до розробника.

    Схоже, саме до такого балансу рухається розробка програмного забезпечення в цілому.

    Штучний інтелект пише код, але база коду все одно належить вам

    Це основний висновок з усього цього досвіду.

    Як тільки ШІ починає створювати ваш код, виникає спокуса припустити:

    "Штучний інтелект написав це, отже, він мусить розуміти, що робить."

    Ця припущення не витримує критики.

    Власність на базу коду залишається у вас.

    Саме ви будете її підтримувати у майбутньому.

    Саме ви змушені будете знаходити баги, коли вони з’являються.

    Саме вам доведеться пояснювати, як це працює, іншій людині.

    Саме ви повернетесь до неї через кілька місяців та знову будете намагатися її зрозуміти.

    У певний момент інший розробник може відкрити проект та запитати:

    "Яка була логіка цього підходу?"

    Ідеально, якби сам код чітко ілюстрував цей логічний підхід.

    Сім звичок чистого коду, до яких варто триматися

    Якщо узагальнити весь цей досвід, ось що залишилося у мене в пам’яті:

    1. DRY

    Уникайте дублювання однакової логіки в кількох місцях без вагомої причини.

    2. Одна відповідальність

    Переконайтеся, що кожна функція чи компонент має одну чітко визначену мету.

    3. Ранні повернення

    Зменшуйте кількість вкладень, щоб основний логічний шлях залишався зрозумілим.

    4. Використовуйте вже існуюче перед створенням нового

    Шукайте наявні рішення в кодбазі перед тим, як створювати щось нове.

    5. Хороше найменування

    Обирайте назви, які чітко вказують на те, що представляє змінна чи функція.

    6. Оптимізація з підтвердженнями

    Утримуйтеся від додавання складності, якщо немає вимірюваної проблеми з продуктивністю, яка б це виправдовувала.

    7. Зрозумійте перед тим, як рефакторувати

    Штучний інтелект може пропонувати зміни, але рішення про те, які з них варто впровадити, залишається за вами.

    Заключні думки

    Коли я починав працювати над проектом сайту з піцою, я припускав, що основною перевагою допомоги ШІ буде:

    висока швидкість.

    Озираючись назад, я усвідомив, що існує ще більша перевага.

    Штучний інтелект звільняє розумові ресурси для тих аспектів розробки, які справді вимагають осуду.

    Замість того, щоб витрачати зусилля на стандартні елементи, ми можемо спрямувати цю енергію на кращі запитання:

    Чи справді це правильний підхід?

    Чи можна це спростити?

    Чи вже існує щось подібне у проекті?

    Чи витримає цей дизайн появу наступної функції?

    Чи зможе інший розробник працювати за цим підходом?

    Ось у чому справжня складність роботи з розробкою за допомогою ШІ.

    ШІ здатне майже миттєво створювати сотні рядків коду.

    Підтвердження того, що ці рядки дійсно заслуговують на своє місце у кодбазі, все ще лежить на нас.

    Можливо, ось оновлена версія визначення «чистого коду» тепер, коли ШІ є частиною процесу:

    Те, що код запускається, — це не кінцева мета. Важливо мати можливість пізніше його підтримувати.

    Пов’язані статті

  • Три шаблони TypeScript, які покращують архітектуру React-додатків — Дізнайтеся, як шаблони Repository, Observer та Builder використовують систему типів TypeScript для створення більш чистих та легкозберіганих кодових баз для React та Next.js.