Що таке рефакторинг, а що лише модифікація коду?


81

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

Я вважаю рефакторинг такими речами, як вилучення методів та перейменування класів. Вони також пропонували такі речі, як зміна структур даних (наприклад, Java LinkedListна an ArrayList), зміна алгоритмів (із використанням сортування злиття замість сортування за допомогою міхура) і навіть переписування великих шматків коду як рефакторинг.

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

Відповіді:


77

Мартін Фаулер "Рефакторинг: вдосконалення дизайну існуючого коду" , мабуть, є посиланням:

Рефакторинг - це контрольована техніка для вдосконалення дизайну існуючої кодової бази. Його суть полягає у застосуванні низки невеликих трансформацій, що зберігають поведінку, кожна з яких "занадто мала, щоб її було варто робити". Однак кумулятивний ефект кожної з цих трансформацій є досить значним. Роблячи їх невеликими кроками, ви зменшуєте ризик помилок. Ви також уникаєте поломки системи під час проведення реструктуризації, що дозволяє поступово реформувати систему протягом тривалого періоду часу.

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

Хорошим посиланням є: Інформація про рефакторинг


16
Цитата Фаулера, звичайно, актуальна, і так, вона поєднується з модульними тестами ... Але, чи справді це відповідає на запитання: чи згадуються в прикладах рефакторинг чи просто модифікація коду? Хто має рацію, ОП чи його колеги, і чому?
Jonik

36

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

Якщо ми робимо рефакторинг або модифікацію коду, що зберігає поведінку:

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

Якщо ми робимо модифікацію коду, що змінює поведінку:

  • ми очікуємо нової поведінки
  • нам слід писати нові тести
  • ми можемо отримати більш брудний код, коли закінчимо (і тоді повинні його рефакторувати)

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


3
+1, точно. Особливо обґрунтування, яке ви даєте; заплутані очікування. Пишучи власну відповідь, я мав це на увазі, навіть якщо мені не вдалося записати її так акуратно :)
Jonik

18

Щоб висловити свою думку:

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

Безумовно, так: "Косметичні" зміни, які не пов'язані безпосередньо з функціями (тобто це не підлягає оплаті як запит на зміну).

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

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


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

Переписування означало б викидання Модуля від будівлі, яка є кращою та швидшою, з нуля, просто вибравши деякі частини зі старої. Або написання нового ядра, а потім введення його в існуюче діалогове вікно.

Рефакторинг означав би зробити невеликі кроки, щоб видалити арифметику покажчика, так що перемикач. Можливо, ви навіть створюєте службову функцію, яка обгортає арифметику вказівника, замінюючи пряму маніпуляцію вказівником викликами до цієї функції, потім перемикаєтесь на ітератор, щоб компілятор скаржився на місця, де арифметика вказівника все ще використовується, потім перемикаєтесь на a list, а потім видаляєте функція утильності.


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

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

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


12

Маючи на увазі визначення Мартіна Фаулера,

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

... Я думаю, ви явно праві.

Вони також запропонували такі речі, як зміна структур даних (наприклад, Java LinkedList на ArrayList), зміна алгоритмів (із використанням сортування злиття замість сортування за допомогою міхура) і навіть переписування великих шматків коду як рефакторинг.

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

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


3
Я не впевнений, що швидше створення коду кваліфікується як зміна зовнішньої поведінки ...
GalacticCowboy

2
Так, я бачу вашу думку, я думаю, це залежить від того, з якого боку ви на це дивитесь. :) У будь-якому випадку, ІМО, при програмуванні слід звертати увагу на те, яку "шапку" ти одягаєш щомиті, тобто чого саме ти хочеш досягти. Іншими словами, слід свідомо відокремлювати при додаванні / виправленні функції, при рефакторингу та оптимізації (покращення продуктивності). IIRC, Фаулер також говорить про це у своїй остаточній книзі про рефакторинг.
Джонік

1
Що стосується зовнішньої зміни, ми могли б змінити формулювання, щоб сказати: [...], не змінюючи своєї зовнішньої поведінки, якщо поведінка є важливою. Якщо продуктивність важлива в будь-якому випадку (швидше чи повільніше), тоді не виконуйте змін, які можуть вплинути на неї як частину фази "рефакторингу".
Локі

11

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

Типовим випадком рефакторингу є

  • "О, всі мої модульні тести працюють, але я думаю, що мій код можна зробити чистішим"
  • Змініть код, щоб він був читабельнішим / чіткішим / ефективнішим
  • Повторно запустіть модульні тести (без зміни тестів) і переконайтеся, що вони все ще працюють

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


7

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


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

4

http://en.wikipedia.org/wiki/Code_refactoring

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

Я погоджуюсь, що код рефакторингу включає порушення існуючого коду. Просто переконайтеся, що у вас є модульні тести, щоб не видавати помилок, а решта коду компілюється. Використання таких інструментів рефакторингу, як Resharper для C #, робить це настільки простим!

  • Робимо код більш зрозумілим
  • Очищення коду та приведення його в порядок
  • Видалення коду! Надлишковий, невикористаний код та коментарі слід видалити
  • Підвищення продуктивності
  • Створення чогось більш загального. Почніть з найпростішої речі, а потім переробіть її, щоб полегшити тестування / ізоляцію або загальний засіб, щоб він міг працювати по-різному завдяки поліморфізму
  • Зберігання коду СУХИМ - не повторюйтесь, тому сеанс рефакторингу може передбачати взяття повторного коду та рефакторинг його в один компонент / клас / модуль.

3

Я не згоден :

У програмній інженерії "рефакторинг" вихідного коду означає вдосконалення його без зміни загальних результатів [...]

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


1

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

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

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

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


0

Рефакторинг = поліпшення нефункціональних вимог при збереженні незмінних функціональних вимог.

Нефункціональні вимоги = модульність, тестованість, ремонтопридатність, читабельність, поділ проблем, принципи Ліскова тощо ...

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.