PHP Manual
/
Безпека

Рефакторинг застарілого PHP-проекту - як надолужити технологічний борг

11. 05. 2021

Obsah článku

Консультуючись зі знаючими та досвідченими власниками проектів, я часто стикаюся з питанням довгострокової стійкості цифрового проекту. Багато великих проектів, які виходять за рамки 3 років розробки, починають внутрішньо застарівати і перестають бути життєздатними - тепер уявіть собі команду розробників з різним рівнем знань, досвіду і найголовніше - працьовитості.

Для того, щоб тримати свій цифровий проект на ТОПовому рівні технічно, потрібно:

  • Компетентні розробники та проектний менеджер, які мають чудову комунікацію і кожен знає, що він робить і як це впливає на інших,
  • Функціональні інструменти та робочий процес, які знає вся команда і відповідно адаптує свою роботу до інших,
  • Автоматизовані завдання, які забезпечують щоденну рутину, про яку так легко забути, є надзвичайно важливими.

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

Що таке рефакторинг і навіщо він потрібен

Поняття рефакторингу охоплює комплекс заходів, які змінюють зовнішній вигляд і внутрішню логіку коду програми, не впливаючи на навколишнє середовище. Процес рефакторингу можна порівняти з різдвяним прибиранням - все залишається таким же, але набагато більш організованим, а непотрібні речі викидаються. З рефакторингом також важливо пам'ятати, що це не одноразова подія, а довготривалий процес, який потрібно повторювати в регулярних циклах. Якщо ви цього не зробите, на вас чекають всілякі дивні помилки, фінансові втрати, проблеми з адаптацією і крики про допомогу.

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

  • Проект буде безпечнішим. Виправлення помилок і вразливостей безпеки регулярно випускаються в бібліотеках, які ви використовуєте. Ви повинні займатися безпекою, це одна з основних життєвих функцій здорового проекту.
  • Код та внутрішня архітектура стануть простішими та більш продуманими. Ви зможете краще знаходити помилки, а багато помилок можна навіть запобігти.
  • За допомогою спрощеного коду ви також можете залучити молодших розробників, щоб значно скоротити ваш загальний бюджет.
  • Ви можете виявити, що ви робите деякі речі занадто складними та надмірно заплутаними - проект буде спрощено в цілому.

Для того, щоб встигати за великим цифровим проектом, потрібно бігти. Але хочеться розвиватися.

Як безпечно рефакторити

Кожен рефакторинг - це велика ставка, яка може не окупитися.

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

Для стабільності особливо потрібне функціональне протоколювання помилок. Для простих проектів достатньо Tracy, який записує помилки в HTML-файл. Для більш складних проектів використовуються такі інструменти, як Sentry або Rollbar. Особисто я на всіх проектах використовую Tracy, інші інструменти в залежності від типу проекту.

Приблизно за місяць до рефакторингу я починаю відстежувати баги і створюю таблицю відомих багів, щоб потім зосередитися на них. Завжди важливо знати, які помилки були внесені рефакторингом, а які проект вже містив раніше. Це потім допоможе краще відстоювати результати роботи перед клієнтом.

Коли я знаю, завдяки журналу, що працюю у відносно стабільному середовищі, ми можемо приступити до важкої роботи. Інші рубрики включають опис методів відповідно до того, наскільки вони пов'язані з ризиком.

Закріплення стилю кодування та стандарту кодування

Більшість проектів не мають єдиного стилю форматування коду. Це велика помилка. Добре написаний проект виглядає як проект однієї людини, де всі речі написані однаково.

Базові помилки форматування добре виправляються інструментом Nette Code Checker, який я регулярно проганяю по всьому проекту.

Стиль кодування, з іншого боку, охоплює спосіб форматування коду та відступи окремих мовних виразів. Стандарт PSR-12 дуже широко використовується в світі PHP, і дуже багато інших стандартів базуються на ньому. Рекомендую використовувати.

У деяких проектах незграбно поєднуються табуляції та пробіли. Для ефективного запобігання порушенню угоди про пробіли (та інших помилок), створіть в корені проекту файл .editorconfig, який вказує редактору, як форматувати новий написаний код.

Особисто я використовую саме таку конфігурацію:

root = true
[*]
charset = utf-8
end_of_line = lf
insert_final_newline = true
trim_trailing_whitespace = true
[*.{php,phpt}]
indent_style = tab
indent_size = 4

Також виправити всі знаки переносу на апострофи. Це можна робити в автоматичному режимі.

Ви також можете перевірити форматування свого коду автоматично, для цього я підготував повністю функціональну демонстрацію на GitHub. Якщо вам також необхідно провести автокорекцію коду, це можна зробити за допомогою того ж інструменту. PhpStorm також дуже добре справляється з автоматичним виправленням коду безпосередньо, навіть масово по всьому проекту.

Як виправити стиль кодування для великих проектів

Для великих проектів рекомендую робити автоматичне форматування коду по одному модулю, так як це може створити величезну кількість конфліктів в Git'е. Тому найкращою стратегією є виправлення якомога більшої кількості рядків одним великим коммітом, відправка цього комміту безпосередньо до майстра, а потім розповсюдження змін в інші гілки.

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

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

PhpStan - статичний аналіз коду та виправлення типових помилок

Перш ніж приступати до масштабного виправлення логіки, дуже важливо переглянути та виправити основні особливості життєвого циклу проекту. До них відносяться такі очевидні речі, які очікуєш від будь-якого проекту, але все одно іноді не виконуються.

Наприклад:

  • Всі класи, методи та функції повинні існувати
  • Спадковість класів не повинна бути порушена
  • Класи повинні реалізовувати використовуваний інтерфейс або інтерфейс предка. При цьому не можна успадковувати "фінальні" класи
  • Не можна викликати небезпечні функції, такі як eval(), hell_exec(), var_dump() і так далі. А якщо ви їх все одно називаєте, то це має бути чітко зазначено в коментарі
  • Ви завжди повинні ловити винятки і не допускати падіння всього додатка

Вирішенням цієї проблеми є встановлення в проекті PhpStan та виправлення його принаймні до рівня 1. Так, це важко, і так, це багато роботи. Але якщо цього не робити, то кожен рефакторинг перетворюється на російську рулетку, і розробник просто сподівається, що збитки будуть мінімальними.

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

Ректор - безпечний ітеративний ремонт

Відома програмна сентенція говорить, що перед тим, як додати нову помилку в систему (наприклад, згенерувати виключення), слід спочатку додати цю помилку як попередження, а вже потім перетворювати її на фатальну помилку, якщо вона довго не проявляється.

Те ж саме стосується і типів даних. При рефакторингу невідомого коду я дозволяю автоматичним інструментам на кшталт Rector спочатку додати до коду анотації коментарів, що нічого не ламає, але допомагає прояснити, що де буде пізніше. Ці коментарі потім прослуховуються PhpStan, який може бути використаний для безпечної перевірки того, що ми нічого не порушили і це безпечна модифікація.

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

Див. статтю Як ми заповнили тисячі відсутніх @var анотацій за день.

Більше про ректора, дивіться на GitHub.

Оновлення залежностей

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

Якщо тести працюють, ми можемо перейти до інструменту Composer для виконання оновлення. Якщо є можливість, скористайтеся допомогою робота Dependabot, який автоматично оновлює composer.json вашого проекту і може перевірити наявність змін сумісності.

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

Куди рухатися далі

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

Схрестимо пальці! Буде важко, але ви впораєтеся.

Jan Barášek   Více o autorovi

Autor článku pracuje jako seniorní vývojář a software architekt v Praze. Navrhuje a spravuje velké webové aplikace, které znáte a používáte. Od roku 2009 nabral bohaté zkušenosti, které tímto webem předává dál.

Rád vám pomůžu:

Související články

1.
10.
Status:
All systems normal.
2024