Имеет ли когда-нибудь смысл для рефактора получить более высокий LOC? [закрыто]

25

Существуют ли случаи, когда более подробный код (как в более логичных выражениях) является более чистым, чем более сжатый код?

неправильное имя пользователя
источник
18
Конечно, это так. Даже при устранении дублирования код для определения новой извлеченной функции занимает свое собственное пространство. Написание новой функции может занять четыре строки и сохранить только две, и все же это стоит сделать.
Килиан Фот
5
"более краткий код"? Я действительно ненавижу ошибочное мнение, что меньшее число строк означает «лучший» код. Это не так. На самом деле, обычно все наоборот. Наступает момент - и он достигается очень быстро - когда втискивание все большего и большего значения в все меньше и меньше пространства делает код труднее для понимания. Фактически, существует целый конкурс - Международный конкурс кодов с запутанным кодом - где многие победители полагаются на эти пределы человеческого понимания при написании непроницаемого кода.
Эндрю Хенле
1
Название вашего вопроса и сам ваш вопрос задают разные вопросы. Например, оператор if может быть преобразован в троичное выражение, которое логически совпадает, но содержит только одну строку.
Капитан Мэн
1
-1 *** больше многословного кода (как в более логических утверждениях) *** многословие и количество логических утверждений - две несвязанные вещи. Это плохая форма, чтобы изменить определения.
Питер Б,

Ответы:

70

Чтобы ответить на этот вопрос, давайте рассмотрим пример из реальной жизни, который произошел со мной. В C # библиотеке, которую я поддерживаю, у меня был следующий код:

TResult IConsFuncMatcher<T, TResult>.Result() =>
    TryCons(_enumerator) is var simpleMatchData && !simpleMatchData.head.HasValue
        ? _emptyValue.supplied
            ? _emptyValue.value
            : throw new NoMatchException("No empty clause supplied");
        : _recursiveConsTests.Any() 
            ? CalculateRecursiveResult() 
            : CalculateSimpleResult(simpleMatchData);

Обсуждая это с коллегами, единодушным вердиктом было то, что вложенные троичные выражения в сочетании с «умным» использованием is varпривели к краткому, но трудному для чтения коду.

Так что я рефакторинг это:

TResult IConsFuncMatcher<T, TResult>.Result()
{
    var simpleMatchData = TryCons(_enumerator);

    if (!simpleMatchData.head.HasValue)
    {
        return _emptyValue.supplied
            ? _emptyValue.value
            : throw new NoMatchException("No empty clause supplied");
    }

    return _recursiveConsTests.Any() 
        ? CalculateRecursiveResult() 
        : CalculateSimpleResult(simpleMatchData);
}

Оригинальная версия содержала только одно составное выражение с неявным return. Новая версия теперь содержит явное объявление переменной, ifоператор и два явных returns. Он содержит больше операторов и больше строк кода. Тем не менее все, с кем я консультировался, считали, что легче читать и рассуждать, что является ключевыми аспектами «чистого кода».

Таким образом, ответ на ваш вопрос - решительное «да», более подробный может быть чище, чем сжатый код, и, следовательно, является действительным рефакторингом.

Дэвид Арно
источник
34
В наши дни мозги разработчика являются более редким ресурсом, чем диск, процессор, оперативная память или пропускная способность сети. Эти другие вещи важны, и в некоторых приложениях они могут быть вашим ограничивающим фактором, но в большинстве случаев вы хотите оптимизировать способность разработчиков сначала понимать код , а затем и другие вещи.
Анаксимандр
2
@anaximander, абсолютно согласен. Напишите код, чтобы другие читали его первым, а компилятор - вторым. Вот почему я считаю полезным, чтобы другие коллеги просматривали мой код, даже если я один разрабатываю его.
Дэвид Арно
4
Если бы я проверял это, я бы предложил поменять порядок операторов возврата и убрать !условие из условия. Я также предложил бы поместить второе возвращение в else. Но даже в том виде, в каком оно есть, это значительное улучшение.
Мартин Боннер поддерживает Монику
2
@DavidArno Я вижу эту логику, и если if (!foo.HasValue)это идиома в вашем коде, то еще сильнее. Однако ifэто не на самом деле выход быстротвердеющий - это «делать это или что в зависимости.»
Мартин Боннер поддерживает Монику
2
@fabric Сравнение логических значений опасно. Я избегаю этого столько, сколько могу.
Мартин Боннер поддерживает Монику
30

1. Отсутствие корреляции между LOC и качеством кода.

Целью рефакторинга является улучшение качества фрагмента кода.

LOC - это очень базовая метрика, которая иногда коррелирует с качеством фрагмента кода: например, метод с несколькими тысячами LOC может иметь проблемы с качеством. Следует отметить, однако, что LOC не является единственным показателем, и во многих случаях отсутствует корреляция с качеством. Например, метод 4 LOC не обязательно является более читабельным или более поддерживаемым, чем метод 6 LOC.

2. Некоторые методы рефакторинга состоят из добавления LOC.

Если вы возьмете список методов рефакторинга , вы легко сможете найти те, которые заключаются в намеренном добавлении LOC. Примеры:

Оба являются очень полезными методами рефакторинга, и их влияние на LOC совершенно не имеет значения при рассмотрении, использовать их или нет.

Избегайте использования LOC.

LOC - опасный показатель. Его очень легко измерить и очень трудно правильно интерпретировать.

Пока вы не ознакомитесь с методами измерения качества кода, в первую очередь попробуйте не измерять LOC. В большинстве случаев вы ничего не получите, и в некоторых случаях это может ввести вас в заблуждение и снизить качество вашего кода.

Арсений Мурзенко
источник
Вы реорганизовали свой ответ и улучшили качество, добавив больше ЛОТ (строк текста): p
grinch
12

Если вы хотите увидеть конечный результат, сводя к минимуму количество байтов или количество LoC в вашем исходном коде, посмотрите на материалы, представленные на сайте Stack Exchange Code Golf .

Если ваш исходный код сокращен таким образом, у вас скоро будет неразрешимый беспорядок. Даже если вы тот человек, который написал такой код и в то время полностью его понимал, насколько вы будете эффективны, когда вернетесь к нему через шесть месяцев? Нет никаких доказательств того, что такой минимальный код на самом деле выполняется быстрее.

Код должен быть написан таким образом, чтобы любой член вашей команды мог посмотреть на него и сразу понять, что он делает.

сапсан
источник
Может быть, излишним, но просто разобрать это; если вы реорганизуете гольф-код для удобства чтения, у вас всегда будет больше
LoC
1

Да, рефакторинг определенно может привести к большему количеству строк кода.

Наиболее распространенный случай IMO - когда вы берете код, который не является универсальным, и вы делаете его более универсальным / гибким . Обобщение кода легко приводит к значительному увеличению строк кода (иногда в два или более раз).

Если вы ожидаете, что новый универсальный код будет использоваться другими (а не просто как внутренний программный компонент) в качестве библиотеки, то обычно вы добавляете код проверки кода и разметку документации в коде, что снова увеличивает количество строк кода.

Например, вот очень распространенный сценарий, который происходит для каждого разработчика программного обеспечения:

  • Вашему продукту необходима срочная новая высокоприоритетная новая функция, исправление или исправление ошибки в течение двух недель (или любой другой период времени, который считается срочным для вашего размера проекта / размера компании / и т.д.)
  • Вы усердно работаете и доставляете XYZ вовремя, и это работает. Поздравляем! Отличная работа!
  • Пока вы разрабатывали XYZ, существующий дизайн / реализация кода на самом деле не поддерживала XYZ, но вы смогли внедрить XYZ в базу кода.
  • проблема в том, что шимон уродлив и имеет ужасный запах кода, потому что вы сделали некоторые хитрые / умные / уродливые / плохие практики, но вроде как работают
  • когда вы найдете время спустя, вы реорганизуете код, который может изменить многие классы, или добавить новый слой классов, и ваше новое решение «сделано правильно» и больше не имеет неприятного запаха кода ... однако, делая это, «правильный путь» теперь занимает гораздо больше строк кода.

Некоторые конкретные примеры, которые приходят ко мне из головы:

  • для интерфейса командной строки у вас может быть 5000 строк кода if / else-if или вы можете использовать обратные вызовы ... каждый обратный вызов будет намного меньше и проще для чтения / тестирования / проверки / отладки / и т. д., но если вы посчитаете строки закодировать уродливые 5000 строк кода if / else-if, вероятно, будет меньше
  • для обработки кода, который поддерживает N методов обработки , вы могли бы снова использовать операторы if / else, которые выглядели бы наиболее уродливо ...
    • или вы могли бы переключиться на обратные вызовы, которые были бы лучше / лучше, но обратные вызовы занимают больше строк кода (хотя все равно время компиляции)
    • или вы можете абстрагироваться дальше и создать плагины, которые можно изменить во время выполнения. Плагины хороши тем, что вам не нужно перекомпилировать основной продукт для каждого нового плагина или модификации существующего плагина. и вы можете опубликовать API, чтобы другие могли расширить продукт. НО снова плагин-подход использует больше строк кода.
  • для GUI вы создаете отличный новый виджет
    • Вы или коллега замечаете, что новый виджет будет полезен для XYZ и ABC, но сейчас виджет тесно интегрирован только для работы на XYZ
    • вы реорганизуете виджет для работы с обоими, но теперь общее количество строк кода увеличивается
Тревор Бойд Смит
источник