Чи повинен я рефактор великих функцій, які в основному складаються з одного регулярного вираження? [зачинено]


15

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

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


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

2
Ви впевнені, що гігантський регулярний вираз - найкраще рішення вашої проблеми? Чи розглядали ви простіші альтернативи, як, наприклад, бібліотека аналізатора або заміна користувальницького формату файлу на стандартний (XML, JSON тощо)?
lortabac

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

8
Як 100-рядовий регулярний вираз може зробити лише 1 річ?
Пітер Б

@lortabac: Вхід - це текст, створений користувачем (проза.)
DudeOnRock

Відповіді:


36

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

Ви чітко зробили домашнє завдання:

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

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

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

  • Рефактор. Це дає вам відповідність чиєсь уявленню про те, як довго повинна бути функція, і приносить в жертву читабельність.
  • Нічого не робити. Це підтримує наявну читабельність і жертвує дотриманням чиєїсь ідеї про те, якою тривалістю повинна бути функція.

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

Підсумок: якщо він не порушений, не виправляйте його.


10
+1 для "Якщо це не зламано, не виправляйте".
Джорджіо

Справді. Правила Сенді Мец ( gist.github.com/henrik/4509394 ) приємні і всі, але на youtube.com/watch?v=VO-NvnZfMA4#t=1379 вона розповідає про те, як вони стали і чому люди приймають вони занадто серйозно.
Амадан

@Amdan: З додатковим контекстом відео, те, що зробив Мец, має сенс. Її рекомендація до того, що один замовник навмисно був крайнім на одному кінці, щоб протидіяти поведінці, що було крайнім на іншому, як спосіб перетягнути його в більш розумну середину. Решта цього обговорення зводиться до основної моєї відповіді: міркування, а не віра - це спосіб визначити найкращий хід дій.
Blrfl

19

Чесно кажучи, ваша функція може "зробити одне", але, як ви самі заявили

Я міг би почати розбивати регулярний вираз на кілька функцій,

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

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

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

  • покажіть свій код іншому просунутому розробнику (можливо, на /codereview// ), щоб переконатися, що інші думають про читабельність так, як ви. Будьте відкриті до думки, що інші, можливо, не знайдуть 100-лінійний рег-реп настільки читабельним, як ви. Іноді поняття "його не легко зламати на більш дрібні шматки" можна подолати лише другою парою очей.

  • дотримуйтесь фактичної еволюційності - чи виглядає ваш блискучий регп досі так добре, коли надходять нові вимоги, і вам доведеться їх впровадити та протестувати? Поки ваш reg exp працює, я б його не торкався, але щоразу, коли щось потрібно міняти, я б переглядав, якби це справді гарна ідея вкласти все в цей великий блок - і (серйозно!) Переосмислити, якщо розколотись на менші шматки не були б кращим варіантом.

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


Я б сказав, що названі групи захоплення (групи захоплення взагалі, справді) найбільш схожі на змінні final / write-Once або, можливо, макроси. Вони дозволяють посилатись на певні частини матчу, або з об'єкта відповідності, повернутого з процесором регулярних виразів, або пізніше в самому регулярному виразі.
JAB

4

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

Довжина - це довільний "стандарт", коли мова йде про розмір коду. Якщо функція 100 ліній в C # може вважатися довгостроковою, це було б крихітно в деяких версіях складання. Я бачив деякі запити SQL, які добре входили до 200 рядків кодового діапазону, які повертали один дуже складний набір даних для звіту.

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

Не змінюйте це лише тому, що він довгий.


3

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

my $start_re = qr/(?:\w+\.\w+)/;
my $middle_re = qr/(?:DOG)|(?:CAT)/;
my $end_re = qr/ => \d+/;

my $final_re = $start_re . $middle_re . $end_re;
# or: 
# my $final_re = qr/${start_re}${middle_re}${end_re}/

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

1

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

Я пам’ятаю, я працював над аналізом потокового відбиття даних до об’єктів, тому в основному я це розділив на дві основні частини, одна створила повну одиницю String з закодованого тексту, а в другій частині проаналізувала ці одиниці у словнику даних та організувала їх (може бути випадковою властивістю для різних об'єктів), а не оновлення або створення об'єктів.

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


1

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


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

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

Я хотів би навчитися новій майстерності. Якісь хороші ресурси, які ви можете запропонувати? Мене цікавить і теорія, що стоїть за нею.
DudeOnRock

1

Гігантські реджекси - це поганий вибір у більшості випадків. На мій досвід, вони часто використовуються, оскільки розробник не знайомий з розбором (див. Відповідь Томаса Едінга ).

У будь-якому випадку, припустимо, ви хочете дотримуватися рішення на основі регулярних виразів.

Оскільки я не знаю фактичного коду, я вивчу два можливі сценарії:

  • Зворотний вираз простий (багато буквального узгодження та мало альтернатив)

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

  • Регекс складний (багато альтернатив)

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

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

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