Зміст
Уявіть, що ви працюєте над сайтом, і ваші користувачі постійно повідомляють, що мають проблеми з навігацією. Швидше за все, вам потрібно буде реорганізувати код, щоб виправити цю помилку.
Інший приклад: ви працюєте над грою, яка постійно дає збій та вилітає. У цьому випадку рефакторинг коду теж усуне помилки, підвищить продуктивність і запобіжить подальшим збоям.
Рефакторинг — це метод розробки програмного забезпечення, який включає покращення дизайну, структури та якості існуючого коду без зміни його зовнішньої поведінки.
Рефакторинг — це дуже важлива практика в процесі розробки програмного забезпечення, тому що вона гарантує, що код залишиться зручним для супроводу, масштабованим і гнучким навіть із плином часу.
Ця практика стосується практично всіх мов програмування та середовищ розробки, включаючи Java, Python і Ruby on Rails.
Мета рефакторингу — зробити код зрозумілішим, модифікувати та підтримувати його з плином часу.
Ця мета досягається за рахунок усунення надскладності коду, поліпшення його загального дизайну, підвищення зручності читання та виразності. Рефакторинг також допомагає виявити надлишковий або повторюваний код. Видалення такого коду підвищує продуктивність та зручність супроводу програмного забезпечення.
Рефакторинг можна робити різними способами. Ось кілька базових прикладів:
Також можна оптимізувати код із використанням сучасних парадигм програмування та шаблонів проєктування, щоб покращити його загальну структуру.
Рефакторинг може займати багато часу, але це того вартує. У майбутньому ви, навпаки, зменшите витрати на обслуговування. Також ця практика підвищить продуктивність праці розробників: оптимізований код набагато простіше оновлювати і розвивати.
В цілому рефакторинг дає гарантію, що код залишиться підтримуваним, масштабованим та гнучким. Це істотно спрощує його адаптацію до потреб бізнесу і технічних вимог, які змінюються.
Так як рефакторинг — це дуже важливий процес у розробці програмного забезпечення, потрібно суворо дотримуватися правил його проведення. Якщо цього не зробити, можуть з’явитися серйозні помилки, які не лише завадять масштабованості та гнучкості коду, але й викличуть критичні баги після його виконання.
Основні правила рефакторингу перераховані нижче:
Тільки дотримуючись цих правил, рефакторинг можна проводити безпечно та ефективно. Якщо правило з якихось причин доводиться порушити, краще не проводити рефакторинг і залишити код, як є.
Щоб краще зрозуміти, як застосовувати вищеописані правила, розглянемо їх на прикладах.
Припустимо, у вашому коді є функція, яка обчислює суму двох чисел. Після її рефакторингу результат обчислення (тобто те, що код виведе користувачеві) повинен залишитися тим самим:
// до рефакторингу function sum(a, b) { return a + b; } // після рефакторингу function sum(a, b) { const result = a + b; return result; }
Тестування допомагає перевірити, що код, як і раніше, працює так, як замислено, навіть після внесення змін. Але найголовніше, що тестування має бути ретельним та широким.
Наприклад, у вас є функція, яка сортує масив чисел. Після рефакторингу недостатньо перевірити її роботу лише на одному наборі даних. Натомість ви повинні будете протестувати різні масиви (включаючи позитивні та негативні числа, нулі тощо), як до, так і після рефакторингу.
// до рефакторингу function sortArray(array) { return array.sort(); } // після рефакторингу function sortArray(array) { const sortedArray = [...array].sort((a, b) => a - b); return sortedArray; }
Припустимо, вам потрібно реорганізувати складну функцію, яка виконує кілька операцій. Ви можете розбити її на дрібніші і керованіші функції. При цьому створення кожної нової функції вважатеметься новим кроком рефакторингу.
// до рефакторингу function complexFunction(a, b, c, d) { // perform operation 1 // perform operation 2 // perform operation 3 // ... return result; } // після рефакторингу function operation1(a, b) { // perform operation 1 return result1; } function operation2(c, d) { // perform operation 2 return result2; } function operation3(result1, result2) { // perform operation 3 return result3; } function complexFunction(a, b, c, d) { const result1 = operation1(a, b); const result2 = operation2(c, d); const result3 = operation3(result1, result2); return result3; }
Наприклад, у вас є функція, яка обчислює площу прямокутника. Вона включає:
calculateRectangleArea
.width
, height
і area
.// до рефакторингу function calculateArea(x, y) { return x * y; } // після рефакторингу function calculateRectangleArea(width, height) { const area = width * height; return area; }
Дублі коду зазвичай з’являються, якщо одна й та ж дія виконується кілька разів. Іноді можна переписати код так, щоб дія виконувалася лише один раз. Але не завжди.
У всіх інших випадках ви можете просто винести код, який повторюється, в окрему функцію:
// до рефакторингу function calculateTotalPrice(quantity, price) { const totalPrice = quantity * price; const discount = 0.1; const discountedPrice = (totalPrice * discount) + totalPrice; console.log(discountedPrice); } // після рефакторингу function calculateDiscountedPrice(totalPrice, discount) { return totalPrice * (1 - discount); }
Зазвичай рефакторинг проводять по одній (або кількох одразу) з наступних причин:
Перераховані вище причини важливі, але не завжди можна зрозуміти, чи актуальні вони для вашого проєкту тут і зараз. Тому, якщо сумніваєтеся, чи потрібен вам рефакторинг коду, краще пройтися цим чек-листом.
Ознаки, що рефакторинг потрібен:
Рефакторинг приносить результати, тому що покращує якість, зручність супроводу та продуктивність вашого коду без зміни його зовнішньої поведінки.
Це як редагування готового тексту: ви не пишете нічого з нуля, а думаєте, як покращити матеріал.
Чим більше ви дивитеся на вже написану функцію та шукаєте можливості її спростити, тим краще ви самі розумієте, як працює код. В результаті ви отримуєте не тільки фактично працюючу програму, але й чітку програмну структуру.
Це своєрідна самоперевірка — чи зможете ви коротко в коментарях пояснити, чому потрібен саме цей шматок коду?
Припустимо, ви працюєте над вебзастосунком з формою авторизації. Форма має одну-єдину функцію перевірки. Функція стежить за тим, щоб поля імені користувача та пароля не були порожніми.
def validate_login(username, password): if not username: return "Username is required" if not password: return "Password is required" return None
Але застосунок розвивається, і вимог до нього стає дедалі більше. Так, тепер ім’я користувача має містити лише дійсну адресу електронної пошти, а пароль містити рівно вісім символів.
Кожну з нових вимог ви записуєте все в тій самій одній-єдиній функції, через що вона розростається і стає все більш складною.
У якийсь момент ви розумієте, що не тільки не можете пояснити колезі, що саме робить ця функція, але й самі губитеся, де закінчується одна перевірка та починається інша. Час робити рефакторинг.
Логічне рішення — винести кожну з перевірок в окрему функцію з відповідною назвою та метою:
def validate_username(username): if not username: return "Username is required" if not re.match(r"[^@]+@[^@]+\.[^@]+", username): return "Username must be a valid email address" return None def validate_password(password): if not password: return "Password is required" if len(password) < 8: return "Password must be at least 8 characters long" if not any(c.isupper() for c in password): return "Password must contain at least one uppercase letter" if not any(c.isdigit() for c in password): return "Password must contain at least one digit" return None def validate_login(username, password): errors = [] username_error = validate_username(username) if username_error: errors.append(username_error) password_error = validate_password(password) if password_error: errors.append(password_error) return errors or None
Тепер у кожного правила перевірки є своя функція: читати такий код набагато зручніше. Крім того, ми додали функцію validate_login
, яка викликає кожну функцію перевірки та повертає список помилок.
Якщо подивитися на ситуацію з боку користувача, нічого не змінилося. Як би не було записано функцію перевірки, на виході вона дасть помилку, якщо ви як користувач введете недійсну адресу електронної пошти або пароль у чотири символи. Але ви як програміст (і ваші колеги) більше не плутатиметеся в тому, де яка перевірка.
Більше того, якщо в майбутньому вам потрібно буде додати нові правила перевірки, ви зможете створити нову функцію і додати її до функції validate_login
.
За всіх переваг рефакторингу бувають ситуації, коли трудовитрати на нього не мають сенсу. Ось кілька прикладів, коли рефакторинг не потрібний:
Найгірше, що ви можете зробити — це почати робити рефакторинг, не розуміючи навіщо. Так ви просто витратите гроші та час дарма.
Рефакторинг та проєктування (дизайн-код) — тісно пов’язані поняття у розробці програмного забезпечення, але з деякими ключовими відмінностями.
Рефакторинг — це процес покращення дизайну існуючого коду без зміни його зовнішньої поведінки .
Проєктування — це процес створення структури та організації коду з нуля.
Через цю основну відмінність, рефакторинг проводять після проєктування. Іншими словами, результат проєктування — це код, який використовується для подальшого рефакторингу. Але це не означає, що на цьому все закінчується.
Рефакторинг — це безперервний процес, який має виконуватися постійно протягом усього циклу розробки, а не лише як разовий захід.
Повертаючись до порівняння, проєктування виконується лише на початку циклу розробки. Воно включає створення плану програмної системи, структуру, функціональність та поведінку. Якщо проєктування зроблено добре, у процесі рефакторингу не буде багато змін.
Але навіть при хорошому дизайн-коді можуть виникати моменти, коли необхідний рефакторинг. Зазвичай це відбувається в міру того, як код розвивається та змінюється, а дизайн перестає бути оптимальним. Все тому, що на початку циклу розробки неможливо передбачити все. А рефакторинг може допомогти привести код відповідно до вихідного бачення.
Таким чином проєктування та рефакторинг — два найважливіші аспекти розробки ПЗ. Дизайн закладає основу програмної системи, а рефакторинг допомагає покращити її код.
При правильному виконанні рефакторинг може підвищити продуктивність з допомогою видалення непотрібного коду, спрощення та оптимізації алгоритмів. Але якщо рефакторинг виконаний неправильно, це може зашкодити продуктивності.
Тим не менш, бувають випадки, коли рефакторинг взагалі не впливає на продуктивність. Давайте розберемося, як це працює:
АЛЕ:
Рефакторинг має проводитися з акцентом на поліпшення якості коду. І хоча продуктивність має значення, вона не має бути основною метою рефакторинга.
Ми вже часто згадували це у матеріалі, щоб зробити однозначний висновок: тестування — невід’ємна частина процесу рефакторингу. Це гарантія того, що рефакторинг не внесе до коду нових помилок і що після цього процесу код, як і раніше, буде працювати так, як потрібно.
Розберемо докладніше, коли та як проводять тести.
Тестування перед початком рефакторингу допомагає встановити базовий рівень того, як на даний момент працює код. Крім того, так можна виявити помилки чи проблеми, які потрібно вирішити перед стартом рефакторингу.
Приклад:
Припустимо, у вас є функція на Python, яка змінює розмір зображення за допомогою бібліотеки Pillow
:
from PIL import Image def resize_image(input_path, output_path, max_size): with Image.open(input_path) as img: width, height = img.size if width > max_size or height > max_size: ratio = min(max_size / width, max_size / height) new_size = (int(width * ratio), int(height * ratio)) img = img.resize(new_size) img.save(output_path)
Щоб протестувати цю функцію, ви можете написати простий скрипт, який (1) створює файл зображення потрібного розміру, (2) викликає функцію resize_image
для зменшення розміру зображення, а потім (3) перевіряє правильність розмірів вихідного файла:
import os import tempfile def test_resize_image(): input_file = tempfile.NamedTemporaryFile(suffix='.jpg') output_file = tempfile.NamedTemporaryFile(suffix='.jpg') img = Image.new('RGB', (1000, 1000)) img.save(input_file.name) resize_image(input_file.name, output_file.name, 500) assert os.path.exists(output_file.name) with Image.open(output_file.name) as img: width, height = img.size assert width <= 500 and height <= 500
У цьому прикладі функція test_resize_image
створює тимчасовий вхідний файл з використанням модуля tempfile
розміром 1000×1000 пікселів. Потім він викликає функцію resize_image
, щоб змінити розмір зображення до максимального розміру 500 пікселів, і перевіряє, що вихідний файл існує і має розміри менші або рівні 500×500 пікселів.
Протестувавши функцію resize_image
перед рефакторингом, ви можете встановити базові показники того, як вона на даний момент працює, і переконатися, що будь-які зміни, які ви вносите в процесі рефакторингу, не призводять до нових помилок або регресій.
Регулярні перевірки в процесі рефакторингу допомагають виявити будь-які проблеми та помилки на ранній стадії та усунути їх.
Після завершення процесу рефакторингу код необхідно знову протестувати, щоб переконатися, що він, як і раніше, працює належним чином.
Якщо регулярне тестування проводилося досить ретельно, перевірка після рефакторингу не повинна виявити серйозних проблем.
Автоматизоване тестування може бути особливо корисним під час рефакторингу, тому що воно допомагає проводити часте та всебічне тестування з мінімальними зусиллями. Його включають на всіх етапах перевірок: до, після та в процесі рефакторингу.
Хоча рефакторинг має багато переваг, він також може призвести до виникнення певних проблем:
Щоб проблем не було, потрібно підходити до рефакторингу обережно та методично, маючи чіткий план та цілі.
Тестування та документування мають бути головним пріоритетом протягом усього процесу, а зміни потрібно вносити поступово і з прицілом на зручність супроводу та зручність читання.
Насамкінець поділимося з вами деякими ефективними методами рефакторингу:
Це лише деякі з багатьох методів, які можна використовувати для рефакторингу коду. Конкретні методи будуть залежати від конкретних цілей процесу рефакторингу і характеристик коду.
Швейцарська компанія з кібербезпеки Prodaft запустила ініціативу під назвою «Продай своє джерело», в рамках якої…
Презентовано JRuby 10 — останню версію реалізації мови програмування Ruby на основі JVM. Вона має…
Компанія Ілона Маска xAI презентувала новий онлайн-інструмент під назвою Grok Studio. Він призначений для редагування…
В освітній платформі «Мрія» планують впровадити генератор тестів на основі штучного інтелекту. Про це в…
OpenAI працює над власною X-подібною соціальною мережею, згідно з кількома джерелами, знайомими з цим питанням,…
Команда Unit 42 з Palo Alto Networks помітила чергову активність хакерської групи з КНДР, яка…