Який найкращий спосіб впоратися з рефакторингом великого файлу?


41

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

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

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

То чи існує спосіб рефакторингу, не вимагаючи від кого-небудь іншого припиняти роботу (надовго) або об'єднувати назад свої функції, щоб розвиватися?


6
Я думаю, це також залежить від використовуваної мови програмування.
Роберт Анджежук

8
Мені подобаються «маленькі додаткові» чеки. Якщо хтось не збереже копію репо-свіжої, ця практика зведе до мінімуму конфлікти злиття для всіх.
Метт Раффель

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

1
Існує чимало підходів, з якими ви можете скористатися, і найкращий підхід залежатиме від вашої ситуації.
Стефан

3
Я приєднався до проекту, де найбільший файл довжиною 10 тис. Рядків, що містить серед інших клас, який має 6-літровий рядок, і всі бояться його торкнутися. Я маю на увазі те, що ваше запитання чудове. Ми навіть придумали жарт, що цей єдиний клас - це вагомий привід розблокувати колесо прокрутки у наших мишах.
ElmoVanKielmo

Відповіді:


41

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

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

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

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

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

  1. Витягніть функціональність в окремий модуль.
  2. Змініть старі функції, щоб переадресувати свої дзвінки до нового API.
  3. З часом код порту залежить від нового API.
  4. Нарешті, ви можете видалити старі функції.
  5. (Повторіть наступну купу функціональності)

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

Зрештою, будь-яке рішення вимагатиме від вас координації зі своєю командою.


1
@Laiv На жаль, це все надзвичайно загальна порада, але деякі ідеї із спритного простору, як-от Безперервна інтеграція, явно мають свої переваги. Командам, які працюють разом (і часто інтегрують свою роботу), буде легше проводити великі наскрізні зміни, ніж команди, які працюють лише поряд. Це не обов'язково стосується SDLC загалом, а більше про співпрацю в команді. Деякі підходи роблять роботу поруч з більш здійсненною (думаю, відкритий / закритий принцип, мікросервіси), але команда ОП ще не існує.
амон

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

1
@Laiv На мій досвід, має сенс заздалегідь обговорити проект з рефакторингом заздалегідь, але зазвичай найпростіше, якщо зміни в код внесе одна людина. В іншому випадку ви повернетесь до проблеми, що вам доведеться об'єднати речі. 4k рядки звучать як багато, але насправді це не для націлених рефакторинга, як екстра-клас . (Я б так сильно шипшив книгу "Рефакторинг" Мартіна Фоулера, якби я прочитав її.) Але 4-рядкові рядки - це багато лише для ненавмисних переробників на зразок "давайте подивимось, як я можу вдосконалити це".
амон

1
@DanLyons В принципі ви праві: це може поширити частину зусиль, що об'єднуються. На практиці злиття Гіта багато в чому залежить від останньої спільної комісії предків гілок, що об'єднуються. Об'єднання майстра → функція не дає нам нового спільного предка на господаря, але функція злиття → master робить. При повторному злитті майстра → функції може траплятися, що нам доведеться вирішувати одні і ті ж конфлікти знову і знову (але див. Git rerere для автоматизації цього). Звільнення тут суворо вище, тому що чайовий майстер стає новим загальним предком, але переписування історії має інші проблеми.
амон

1
Відповідь для мене нормальна, за винятком того, що гнів про git робить його занадто легким для розгалуження, і, отже, розгалужує диски занадто часто. Я добре пам’ятаю часи SVN і навіть CVS, коли розгалуження було досить важким (або принаймні громіздким), що люди взагалі уникали цього, якщо можливо, з усіма пов'язаними з цим проблемами. У git, будучи розподіленою системою, мати багато гілок насправді нічим не відрізняється від того, що взагалі існує багато відокремлених сховищ (тобто, на кожному розробнику). Рішення лежить в іншому місці, простота гілки - це не проблема. (І так, я бачу, що це лише бік ... але все ж).
AnoE

30

Робіть рефакторинг меншими кроками. Скажімо, ваш великий файл має назву Foo:

  1. Додайте новий порожній файл, Barі закріпіть його на "trunk".

  2. Знайдіть невелику частину коду, до Fooякої можна перейти Bar. Застосуйте хід, оновіть з магістралі, складіть і протестуйте код, і виконайте зобов’язання "trunk".

  3. Повторіть крок 2 до Fooі Barмають однаковий розмір (або будь-який інший розмір ви віддаєте перевагу)

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

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

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


2
Це особливо корисно з rerereувімкненою опцією
gits

@ D.BenKnoble: дякую за це доповнення. Треба визнати, я не фахівець з git (але описана проблема не є специфічно для git, вона стосується будь-якого VCS, який дозволяє розгалуження, і моя відповідь повинна відповідати більшості цих систем).
Doc Brown

Я розібрався на основі термінології; насправді, з git, цей вид злиття все ще робиться лише один раз (якщо один просто тягне і зливається). Але завжди можна витягнути і вишневий вибір, або об'єднати окремі зобов’язання, або перезавантажити залежно від уподобань розробника. Це займає більше часу, але це, безумовно, можливо, якщо автоматичне об'єднання, здається, може вийти з ладу.
D. Ben Knoble

18

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

Виберіть частину, яку не довелося довго змінювати ( git blameможе допомогти в цьому), і розділіть її спочатку. Об’єднайте цю зміну у відділення кожного, а потім виберіть наступну найпростішу частину для поділу. Можливо, навіть розділення однієї частини є занадто великим кроком, і ви повинні спершу зробити деяку перестановку у великому файлі.

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

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


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

9

Я збираюся запропонувати інше, ніж звичайне, рішення цієї проблеми.

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

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

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

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

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

Щоб допомогти продати цю ідею своєму менеджеру, згадайте біт перегляду коду, а також усіх, хто знає, де справа з самого початку. Не можна втратити час на те, щоб розробники втрачали час на пошук безлічі нових файлів. Крім того, запобігання розгортанню роз'яснювачів про те, де все закінчилося або «повністю пропало», як правило, це добре. (Чим менше втрат, тим краще, ІМО.)

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

Однак ви вирішили зробити свій рефактор, удачі!


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

+1 за пропозицію кодового мобу
Джон Рейнор

1
Це саме стосується соціального аспекту проблеми.
ChuckCottrill

4

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

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

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

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

Гак фіксації може перевірити наявність нових класів або зробити інший статичний аналіз (ad hoc чи ні). Ви також можете просто вибрати рядок або кількість символів, що на 10% більше, ніж файл, який є на даний момент, і сказати, що великий файл не може перевищувати нову межу. Ви також можете відхилити окремі комітети, які збільшують великий файл на занадто багато рядків або занадто багато символів або w / e.

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

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


-3

Зачекайте, поки не настане час. Розділіть файл, скопіюйте і об'єднайте в master.

Іншим людям доведеться вранці вносити зміни до своїх функціональних гілок, як і всі інші зміни.


3
І все-таки це означатиме, що їм доведеться об'єднати мої реконструкції зі своїми змінами ...
Хофф,


1
Ну, вони насправді мають справу з об'єднаннями, якщо всі вони змінюють ці файли.
Лаїв

9
У цьому проблема "Здивуй, я зламав усі твої речі". Перш ніж це зробити, ОП потребує придбання та затвердження, і це робити в запланований час, коли ніхто інший не має файлу "в процесі роботи".
computercarguy

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