Рефакторинг — сила прихована в якісному коді

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

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

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

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

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

Кілька принципів, які точно потрібно знати при проектуванні класів вашої «Feature»:

1. SOLID (single responsibility, open-closed, Liskov substitution, interface segregation і dependency inversion)

Це основа основ у проектуванні класів. Якщо ви ще не знайомі з SOLID, тут можна ознайомитися.

2. DRY (do not repeat yourself)

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

Наприклад:

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

— Замість використання функції progress50(), краще застосувати більш абстрактну progress($percent).

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

3. KISS (keep it simple, stup...)

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

Наприклад:

Вам потрібно написати клас для генерації Excel звіту з вашої БД. Потрібно весь звіт розділити на частини: установка заголовків таблиці, висновок статистичних даних у документ, висновок підвалу документа, створення діаграми. Деякі частини функціоналу можна винести в окремі класи, що дасть можливість використовувати їх повторно.

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

Стандарт стилю коду (і не тільки) PSR (PHP Standards Recommendations), тут можна ознайомитися. Вміст англійською мовою, так як англійський більш ясно дає зрозуміти ступінь застосування одного чи іншого правила («MUST», «MUST NOT», «REQUIRED», «SHALL», «SHALL NOT», «SHOULD», «SHOULD NOT», «RECOMMENDED», «MAY», and «OPTIONAL»).

Кілька зауважень, які автор вважав важливими:

1. Ознайомтеся з PHPDOC для написання коментарів до вашого коду.

2. Кращий коментар — це правильно названий клас, метод, або параметр-змінна.

3. Використовуйте утиліти PHPMD, PHPCS, їх застосування ширше, ніж тільки для визначення невідповідностей в стилі коду. Ось документація: PHPMD, PHPCS.

4. Використовуйте просунуте IDE.

Рефакторинг в чистому вигляді
Дуже проста аксіома — на продакшн повинен потрапляти тільки код, що пройшов рефакторинг. Іноді після розробки ви самі робите рефакторинг, що дуже навіть не погано (наприклад, розробка через тестування взагалі включає рефакторинг, як обов'язковий крок, так як спочатку пишеться «працюючий код», а потім вже «чистий»), але для того, щоб код був по-справжньому якісним, він повинен пройти перевірку коду (code review) іншим програмістом. Якщо проект дозволяє виділити час на перевірку коду, то на такому проекті ти будеш вчитися писати код чистіше і чистіше, що надалі приведе до автоматичного написання якісного коду.

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

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

1. Довгі методи (краще розділити функціонал на кілька методів).

2. Громіздкі класи (ваш клас повинен виконувати одну функціональну задачу у вашій системі).

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

4. Занадто багато параметрів у методі (деякі розрахунки можна зробити всередині методу, використовуючи внутрішні константи, значення отримані з атрибутів і геттеров).

5. Класи, що містять однакові змінні і методи. Проблему можна вирішити через створення додаткового класу).

6. Важко читається IF (вираз можна винести в окрему змінну і розділити на логічні частини, які також винести в змінні, якщо багато перевірок null, то краще всього використовувати NullObject — кількість перевірок значно зменшиться).

7. Громіздкий SWITH (виносимо в окремий метод).

8. Використання спадкування за однакових методів і властивостей, різних за своєю суттю сутності (кішка і стілець мають ноги, але їх не можна групувати в категорію «тварини»).

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

10. Занадто складний функціонал в одному класі, який можна розділити на кілька класів.

11. Клас робить дуже мало, щоб його залишати в системі.

12. «Мертвий код» — його слід видалити.

13. Не використані структури класів, які ви проектували на майбутнє, але вони так і не стали в нагоді — такі краще видалити.

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

15. Занадто довга ланцюжок викликів ($a>b()->c()->d()->e()), в цьому випадку варто створити додаткові методи.

16. Клас, що містить тільки один метод, який створює інший клас. (Такий клас потрібно використовувати з розумом, наприклад, для патерну «Проксі», в іншому випадку цей клас лише збільшує час і ресурс на підтримку проекту).

17. Дуже багато дій в конструкторі. (Конструктор повинен тільки встановлювати властивості класу, якщо ж у конструкторі створюються інші класи, відбуваються якісь розрахунки, то це робить його складним для розуміння, доводиться вникати в суть реалізації. Щоб створити об'єкт і виконати якісь дії, додайте статичний метод create($param1, ...), який створює екземпляр класу з додатковими дії над ним, цей метод можна назвати більш підходящим до того, що він буде все робити).

Список літератури
» Source Making
» PSR
» UML
Джерело: Хабрахабр

0 коментарів

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