Я только что написал функцию, которая занимает примерно 100 строк. Услышав это, вы, вероятно, испытываете желание рассказать мне об отдельных обязанностях и призвать меня провести рефакторинг. Это тоже мой инстинктивный инстинкт, но вот в чем проблема: функция делает одно. Он выполняет сложные манипуляции со строками, а тело функции состоит в основном из одного подробного регулярного выражения, разбитого на множество документированных строк. Если бы я разбил регулярное выражение на несколько функций, я чувствовал бы, что на самом деле потерял бы удобочитаемость, поскольку я эффективно переключаю языки и не смогу воспользоваться некоторыми функциями, предлагаемыми регулярными выражениями. Вот мой вопрос:
Когда дело доходит до манипулирования строками с помощью регулярных выражений, большие тела функций все еще являются анти-паттерном? Кажется, что именованные группы захвата служат очень похожим целям для функций. Кстати, у меня есть тесты для каждого потока через регулярное выражение.
Ответы:
То, с чем вы сталкиваетесь, - это когнитивный диссонанс, возникающий из-за того, что вы слушаете людей, которые предпочитают рабское следование руководящим принципам под видом «лучших практик», а не обоснованных решений.
Вы четко сделали свою домашнюю работу:
Если какой-либо из этих пунктов не соответствует действительности, я бы первым сказал, что ваша функция нуждается в работе. Таким образом, есть один голос за оставление кода как есть.
Второе голосование происходит от просмотра ваших вариантов и того, что вы получаете (и теряете) от каждого:
Это решение сводится к тому, что вы цените больше: удобочитаемость или длина. Я попадаю в лагерь, который считает, что длина хорошая, но удобочитаемость важна, и в любой день перенесу последнюю на первую.
Итог: если он не сломан, не чините его.
источник
Честно говоря, ваша функция может «делать одно», но, как вы сами заявили
Это означает, что ваш код reg ex делает много вещей. И я думаю, что это может быть разбито на более мелкие, индивидуально проверяемые единицы. Однако, если это хорошая идея, на нее нелегко ответить (особенно, не видя реального кода). И правильный ответ может быть ни «да», ни «нет», но «пока нет, но в следующий раз вам придется что-то изменить в этом регистре».
И это ключевой момент - у вас есть кусок кода, написанный на языке reg ex . Этот язык не предоставляет каких-либо хороших средств абстракции сам по себе (и я не считаю «именованные группы захвата» заменой функций). Таким образом, рефакторинг «на языке reg ex» на самом деле невозможен, и переплетение небольших записей reg с языком хоста может на самом деле не улучшить читаемость (по крайней мере, вы чувствуете это, но у вас есть сомнения, иначе ваш вопрос не был бы опубликован) , Так вот мой совет
покажите свой код другому продвинутому разработчику (может быть, на /codereview// ), чтобы другие думали о читабельности так же, как вы. Будьте открыты к мысли, что другие могут не найти 100-строчный регистр, такой же читаемый, как вы. Иногда понятие «его нелегко разбить на мелкие кусочки» можно преодолеть с помощью второй пары глаз.
наблюдайте за фактической эволюционностью - ваш блестящий reg exp все еще выглядит так хорошо, когда появляются новые требования, и вам нужно их реализовать и протестировать? Пока ваш reg exp работает, я бы не стал его трогать, но всякий раз, когда что-то нужно менять, я бы пересматривал, было бы действительно хорошей идеей вкладывать все в этот один большой блок - и (серьезно!) Переосмысливать, если разбить на меньшие части не были бы лучшим выбором.
соблюдайте ремонтопригодность - можете ли вы эффективно отлаживать reg exp в текущей форме? Особенно после того, как вам нужно что-то изменить, и теперь ваши тесты показывают, что что-то не так, у вас есть отладчик reg exp, помогающий вам найти основную причину? Если отладка становится трудной, это также будет поводом пересмотреть ваш дизайн.
источник
Иногда более длинная функция, выполняющая одну вещь, является наиболее подходящим способом обработки единицы работы. Вы можете легко получить очень длинные функции, когда начнете обращаться к базе данных (используя ваш любимый язык запросов). Сделать функцию (или метод) более читабельной, ограничивая ее заявленной целью, - это то, что я считаю наиболее желательным результатом функции.
Длина - это произвольный «стандарт» в отношении размера кода. Если функция на 100 строк в C # может считаться длинной, в некоторых версиях сборки она будет крошечной. Я видел несколько запросов SQL, которые были в пределах 200 строк кода, которые возвращали один очень сложный набор данных для отчета.
Полностью рабочий код , который так просто , как вы можете разумно сделать это цель.
Не меняйте его только потому, что оно длинное.
источник
Вы всегда можете разбить регулярное выражение на под-регулярные выражения и постепенно составить окончательное выражение. Это может помочь в понимании очень большого шаблона, особенно если один и тот же суб-шаблон повторяется много раз. Например, в Perl;
источник
Я бы сказал, сломай его, если он ломкий. с точки зрения ремонтопригодности и, возможно, повторяемости имеет смысл нарушать ее, но, конечно, вы должны учитывать естественность своей функции и то, как вы получаете ввод и что он собирается возвращать.
Я помню, что работал над анализом потоковых данных в виде объектов, поэтому я разделил их на две основные части: одну составляла единое целое из строки String из кодированного текста, а во второй - разбирал эти единицы в словарь данных и организовывал их (может быть случайное свойство для другого объекта), а затем обновление или создание объектов.
Также я мог разбить каждую основную часть на несколько более мелких и более специфических функций, так что в конце у меня было 5 различных функций, чтобы выполнить все это, и я мог повторно использовать некоторые функции в другом месте.
источник
Одна вещь, которую вы могли или не могли рассмотреть, это написать небольшой синтаксический анализатор на языке, который вы используете, вместо использования регулярного выражения в этом языке. Это может быть легче читать, тестировать и поддерживать.
источник
Гигантские регулярные выражения - плохой выбор в большинстве случаев. По моему опыту, они часто используются, потому что разработчик не знаком с анализом (см . Ответ Томаса Эдинга ).
В любом случае, давайте предположим, что вы хотите придерживаться решения на основе регулярных выражений.
Поскольку я не знаю реального кода, я рассмотрю два возможных сценария:
Регулярное выражение простое (много буквального соответствия и мало альтернатив)
В этом случае расширенные функции, предлагаемые одним регулярным выражением, не являются обязательными. Это означает, что вы, вероятно, выиграете от его разделения.
Регулярное выражение сложное (много альтернатив)
В этом случае вы не можете реально иметь полное покрытие тестами, потому что у вас, вероятно, есть миллионы возможных потоков. Итак, чтобы проверить это, вам нужно разделить его.
Мне может не хватать воображения, но я не могу вспомнить ни одной реальной ситуации, когда регулярное выражение из 100 строк является хорошим решением.
источник