← Усі статті

Refactoring: змінювати структуру, не поведінку

Вижимка Fowler: дві шапки, запахи коду, маленькі кроки й тести — з кейсами, контекстом ШІ та діями на сьогодні. Не заміна книги.

Refactoring: змінювати структуру, не поведінку
Зміст

У запиті на злиття «заодно причесали» три модулі. Рев’юер не розуміє, де зміна поведінки, а де перейменування. Тести зелені на щасливому шляху. У проді падає крайній випадок, який жив у «очищеній» гілці. Знайомо?

Рефакторинг Мартіна Фаулера (оригінал Refactoring) — не про «зробити гарно, доки я тут». Книга про зміну структури без зміни спостережуваної поведінки, малими кроками й з тестами. Нижче — розбір своїми словами: як це виглядає в живих системах, де порада ламається і що змінюється з ШІ-асистентами. Вижимка не замінює оригінал.

Теза книги

Рефакторинг — це дисципліна безпечних перетворень: ви покращуєте форму коду так, щоб зовні система поводилась так само. Фаулер відокремлює цей режим від додавання можливостей. Змішувати обидва в одному коміті — шлях до «зелених» тестів і червоного проду.

Каталог прийомів і «запахи коду» — не естетика заради естетики. Це словник, щоб команда могла назвати рух («витягнути функцію», «ввести об’єкт параметрів») і повторити його передбачувано. Друге видання (2018) ближче до сучасного JavaScript і типізації, але метод універсальний: запах → іменований крок → перевірка → наступний крок.

Ключові ідеї

Дві шапки: можливість і рефакторинг

Що каже автор. В один момент часу ви або змінюєте поведінку (нова можливість, виправлення помилки), або змінюєте структуру за незмінної поведінки. Перемикайтесь свідомо. «Заодно приберу» — не рефакторинг, а ризик під маскою турботи про код.

Як це виглядає на промисловому проєкті. У моноліті облікової системи метод проведення рахунку на чотириста рядків. Потрібно додати податкові правила. Розробник у тому ж запиті «розносить» метод, перейменовує поля і трохи змінює порядок перевірок. Через тиждень бухгалтерія ловить розбіжність на нульових сумах — а в дифі вже не відділити структурний шум від змістової правки.

Як це змінюється з ШІ. Асистент охоче змішує шапки: «спрощу і додам поле». Диф виглядає охайно, рев’ю ковзає по перейменуваннях і пропускає зсув семантики. Правило те саме: спочатку структурні коміти (або хоча б окремі коміти в одному запиті), потім поведінка — і явна просьба до моделі: «не змінюй спостережувану поведінку».

Де порада може не спрацювати. Крихітна правка в уже ізольованому шматку іноді дешевша за два проходи. Але щойно зона спільна або без тестів — дві шапки окупаються. Не плутайте «маленький диф» із «одним сенсом».

Що зробити вже сьогодні. У наступному запиті розділіть коміти: спочатку лише структура, потім лише поведінка. В описі напишіть одним рядком, яка зараз шапка.

Мій досвід. Я вимагаю розділення не з педантизму, а тому що інакше рев’ю перетворюється на вгадайку. Особливо коли править агент: без двох шапок ви рев’юєте розповідь моделі про себе, а не зміну системи.

Якщо запам’ятати одну думку — рефакторинг і нова можливість в одному «заодно» майже завжди вороги ясності.

Запахи коду — сигнал, не вирок

Що каже автор. Довгий метод, дублювання, заздрісна функція, довгий список параметрів, умовна логіка, розмазана по файлах — це сигнали, що структура заважає змінам. Запах не дорівнює «поганій людині» і не вимагає негайного героїзму. Він підказує, який прийом із каталогу доречний.

Як це виглядає на промисловому проєкті. «Божественний» метод проведення знає про податки, знижки, журнал і звіт. Кожен новий податок — ще одна гілка if. Команда лається на «поганий код», але править усередині тієї ж каші. Запах уже кричить: витягни кроки, збери параметри в об’єкт, заміни розгалуження поліморфізмом — після тестів.

Як це змінюється з ШІ. Модель «лікує» запах косметикою: дробить на десятки однорядкових або вигадує абстракцію з гарним іменем. Запах зникає з радара метрик, зв’язність падає. Корисніше назвати запах і прийом: «тут довгий список параметрів — запропонуй увести об’єкт параметрів, не чіпаючи поведінку».

Де порада може не спрацювати. Полювання на запахи як метрика команди («нуль довгих методів») плодить обгортки без сенсу. Іноді запах — чесна складність домену на межі. Спочатку запитайте: чи заважає це наступній правці?

Що зробити вже сьогодні. У файлі поточної задачі назвіть один запах вголос (або в коментарі до запиту). Не обов’язково чинити все — зафіксуйте сигнал.

Мій досвід. Запахи корисні як спільна мова на рев’ю. «Тут довгий метод» краще, ніж «мені не подобається». Але я не відкриваю каталог на кожен рядок: чинню те, що стоїть на шляху поточної історії.

Якщо запам’ятати одну думку — запах вказує напрям, а не вимагає суду.

Маленькі кроки і перевірка після кожного

Що каже автор. Рефакторинг іде крихітними перетвореннями. Після кроку — компіляція / типи / тести. Великий «покращувальний» стрибок без проміжних зелених станів — це вже переписування під іншою назвою.

Як це виглядає на промисловому проєкті. Команда вирішує «рознести» модуль оплати за спринт. Три дні червоних гілок, потім один величезний запит. Відкотити неможливо, пошук коміта-винуватця марний. Альтернатива за Фаулером: витягнути одну функцію, зелений прогін, закомітити; зсунути дані в об’єкт параметрів, знову зелений; і лише потім чіпати податкову гілку.

Як це змінюється з ШІ. Агент любить «зробити добре за один прохід»: переписати файл цілком. Ви отримуєте гарний текст і втрачений інваріант. Обмежуйте область: «зроби лише витягування функції X, решту не чіпай»; ганяйте тести на кожну відповідь моделі, не на «коли закінчить».

Де порада може не спрацювати. Якщо немає жодної автоматичної перевірки, «маленький крок» усе одно може мовчки зламати прод. Тоді спочатку шов і характеризація (див. нижче), а не каталог заради каталогу. У прототипі на викид іноді раціональний великий стрибок — якщо ви чесно не обіцяєте сумісність.

Що зробити вже сьогодні. Візьміть один очевидний шматок і зробіть один іменований крок. Запустіть тести. Закомітьте. Зупиніться — навіть якщо хочеться «раз уже відкрив».

Мій досвід. Маленькі кроки — найкраща страховка від власного героїзму. Я ламав прод не на «складному алгоритмі», а на «заодно навів лад» без зеленої точки між правками.

Якщо запам’ятати одну думку — між двома зеленими станами має вміщатися одна думка.

Тести як страховка, не як ритуал

Що каже автор. Без швидкого зворотного зв’язку рефакторинг стає азартом. Тести фіксують спостережувану поведінку. В успадкованому коді часто потрібні характеризаційні тести: спочатку зафіксувати «як є», потім змінювати форму.

Як це виглядає на промисловому проєкті. Модуль розрахунку без юнітів; усі бояться чіпати. Замість великого переписування — один тест на поточний вивід для типового рахунку й одного крайового випадку. Лише після цього — витягування функцій. Порівняння: «великий вибух» нового сервісу vs поступове покращення на місці зі страховкою.

Як це змінюється з ШІ. Модель пише тести до нового коду, який сама ж запропонувала — зелені й безглузді. Або «спрощує» і викидає перевірку на null, якої не бачила в сценаріях. Вимагайте: спочатку тест, що закріплює поточний вивід; потім рефакторинг; диф тесту зі зміною очікувань — червоний прапорець.

Де порада може не спрацювати. Повне покриття перед першою правкою — фантазія у величезному моноліті. Беріть вузький пояс навколо зони зміни. UI і деякі інтеграції потребують іншого контуру — але принцип «є оракул поведінки» той самий.

Що зробити вже сьогодні. Перед правкою страшного методу додайте один характеризаційний тест на фактичний результат (навіть знімок виводу), без переписування дизайну.

Мій досвід. Фаулер тут стикується з книгою Фезерса про успадкований код: шви й характеризація — вхідний квиток. Із «Чистим кодом» навпаки: «красу» без тестів — косметика, яку соромно відкочувати, коли прод уже горить.

Якщо запам’ятати одну думку — тест купує право змінювати форму.

Каталог прийомів — словник команди

Що каже автор. Іменовані рухи (Extract Function, Move Function, Replace Conditional with Polymorphism, Introduce Parameter Object і десятки інших) дають спільну мову. Не потрібно зубрити весь каталог. Потрібно вміти впізнати ситуацію й обрати хід, як шахіст упізнає типову позицію.

Як це виглядає на промисловому проєкті. Перед додаванням податкових правил у проведення: витягнути кроки розрахунку, зібрати розрізнені аргументи в об’єкт параметрів, винести варіації податку в окремі стратегії — кожен крок із каталогу, кожен із зеленими тестами. Рев’юер читає не «магічний диф», а послідовність відомих ходів.

Як це змінюється з ШІ. Просіть модель не «порефактор гарно», а «застосуй витягування функції до блоку рядків 80–120». Каталог звужує простір помилок. Без імені прийому ШІ вигадує свій діалект «чистоти» — і ви знову в двох шапках одразу.

Де порада може не спрацювати. Карго-культ: витягування функції до однорядкових, «поліморфізм» на три гілки, що змінюються раз на рік. Каталог — набір інструментів, не квести на 100%. Застарілі приклади першого видання на Java не скасовують прийоми — змінюйте синтаксис, лишайте сенс.

Що зробити вже сьогодні. Оберіть один прийом із каталогу (хоча б витягування функції) і застосуйте його один раз у зоні задачі, із зеленими тестами.

Мій досвід. Словник важливіший за енциклопедію. Junior виграє, коли може сказати «давай уведемо об’єкт параметрів» замість «тут якось забагато всього». Senior виграє, коли знає, який хід не робити.

Якщо запам’ятати одну думку — назвіть хід, перш ніж рухати код.

Коли рефакторити (і коли не чіпати)

Що каже автор. Евристики на кшталт правила трьох: терпіть дублювання до третього разу, потім узагальнюйте. Рефакторіть перед тим, як нарощувати безлад; після того, як зрозуміли код. Не рефакторіть «усе підряд», коли горить строк і немає страховки.

Як це виглядає на промисловому проєкті. Новий податок у тому ж божественному методі — класичний момент «спочатку структура, потім гілка». Навпаки, косметичний прохід по модулю «на майбутнє» без найближчої історії часто вмирає в конфлікті з чужим запитом. Великий вибух «перепишемо білінг» vs покращення на місці: друге частіше переживає квартал.

Як це змінюється з ШІ. Модель завжди готова рефакторити «про всяк випадок». Ваш фільтр: чи є найближча зміна поведінки, яка стане простішою? Чи є тест? Якщо ні — відмова. ШІ добре прискорює усвідомлений хід і погано замінює судження «зараз не час».

Де порада може не спрацювати. Правило трьох — не закон фізики. У безпеці й грошах іноді узагальнюють із другого разу. У викидному прототипі — і з п’ятого не треба. Контекст важливіший за мантри.

Що зробити вже сьогодні. Перед наступною нетривіальною правкою запитайте: «що мені заважає змінити це безпечно?» Якщо відповідь — структура, заплануйте один крок рефакторингу до нової можливості.

Мій досвід. Найкращий рефакторинг — той, що оплачений найближчою історією. Найгірший — «приведи весь сервіс до ідеалу», поки продукт чекає одну галочку.

Якщо запам’ятати одну думку — час рефакторингу прив’язаний до наступної правки, не до абстрактного сорому за код.

На практиці

На перевірці коду

Питайте:

  • Це одна шапка чи дві одразу?
  • Чи є зелена точка між кроками?
  • Який запах і який прийом названі?
  • Чи не зсунуто поведінку під виглядом перейменування?

У запиті з ШІ-агентом

Вимагайте вузький прийом, тест до і після, маленький диф. Рев’юйте змістові рядки окремо від «шуму краси». Якщо агент викинув перевірку на порожнє значення «для простоти» — це не рефакторинг.

З успадкованим кодом

Спочатку шов і характеризація, потім каталог. Інакше ви рефакторите навдачу. Серія і Фезерс про це прямо кажуть — див. добірку.

Кому яка ідея корисніша

Ідея Junior Middle Senior
Дві шапки ★★★★★ ★★★★★ ★★★★
Запахи як сигнал ★★★★ ★★★★★ ★★★★
Маленькі кроки ★★★★★ ★★★★★ ★★★★
Тести / характеризація ★★★★★ ★★★★★ ★★★★★
Каталог прийомів ★★★★ ★★★★★ ★★★★
Коли не чіпати ★★★ ★★★★ ★★★★★

Оцінки — орієнтир для розмови, не таблиця істини.

Обмеження та критика

Каталог величезний: спроба вивчити все підряд рідко приживається. Приклади першого видання старіють; друге ближче до JS, але ваш стек усе одно інший — переносьте метод, не копіюйте синтаксис. Без культури тестів книга легко стає виправданням великих небезпечних дифів («ми ж рефакторили»).

Коротке порівняння. Refactoringяк безпечно змінювати форму. «Чистий код» — яким код виглядає локально (і там більше догм). Фезерс — що робити, коли тестів ще немає. Предметно-орієнтоване проєктування — куди рефакторити смислову модель, а не лише функції. «Програміст-прагматик» — звички навколо змін; Фаулер дає мікро-механіку кроку.

Читайте каталог як словник ходів, не як чекліст «закрити всі запахи за спринт».

Кому читати

Варто, якщо ви чіпаєте промисловий код частіше, ніж пишете з нуля; якщо рев’юєте чужі й агентські запити; якщо команда сперечається про «красу», але ламає поведінку.

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

Обережно, якщо шукаєте виправдання великому переписуванню: книга якраз проти підміни рефакторингу переписуванням.

Що зробити сьогодні

  1. У наступному запиті розділіть коміти: рефакторинг, потім поведінка.
  2. Назвіть один запах у поточному файлі й застосуйте один прийом каталогу за зелених тестів.
  3. Додайте один характеризаційний тест перед правкою страшного методу.
  4. Якщо просите ШІ витягнути функцію — спочатку закріпіть тест на поточний вивід.