Снижают ли итеративные методы цикломатическую сложность и улучшают ли поддерживаемость?


11

Уменьшают ли итерационные методы, такие как обычно встречающиеся в современных языках, таких как C #, JavaScript и (надеюсь) в Java 8, влияние цикломатической сложности на понятность и поддерживаемость кода?

Например, в C # у нас может быть следующий код:

List<String> filteredList = new List<String>();

foreach (String s in originalList){
   if (matches(s)){
      filteredList.add(s);
   }
}

Это имеет простую цикломатическую сложность 2.

Мы могли бы легко переписать это как:

List<String> filteredList = originalList.where(s => matches(s));

Который имеет простую цикломатическую сложность 0.

На самом ли деле это приводит к более поддерживаемому коду? Есть ли какие-либо реальные исследования по этой теме?


2
Ваш заголовок спрашивает о сокращении цикломатической сложности, но ваш текст предполагает сокращение CC и спрашивает о ремонтопригодности. Это может стать ценным вопросом. Можете ли вы отредактировать заголовок, чтобы он был более точным?
Килиан Фот

@KilianFoth Это лучше?
К. Росс

Я бы связывал итеративные методы с итеративными методологиями разработки. Я думаю, что лучшим термином были бы функции высшего порядка. (Кроме того, у методов нет возвращаемого типа / void, тогда как функции возвращают что-то).
Йоханнес Рудольф

@JohannesRudolph "у методов нет возвращаемого типа / void, тогда как функции возвращают что-то" - на каком языке это правда? Я никогда не слышал этого; фактически единственное различие, которое я когда-либо слышал, было то, что методы связаны с классом, а функции - нет.
3

Ответы:


14

Я предполагаю, что вы просто разделили / переместили сложность. Он уменьшился, потому что вы не учитываете реализацию .where()в вашем CC.

Общий CC не изменился, CC вашего кода уменьшился, только потому, что теперь он перемещен в код фреймворка.

Я бы сказал, что это более ремонтопригодно. Когда это особенность языка, используйте его. Это не «о, я вижу, это умный трюк», который вы используете, а простая встроенная функция, похожая на сокращение.


11

Все, что вы делаете, это выделяете недостаток цикломатической сложности как метрику, сложность кода действительно не изменилась. В первом примере у вас есть явная ветвь, и вы должны понимать, что во втором есть подразумеваемая ветвь. Второй - более понятный и понятный, если вы понимаете синтаксис и поскольку он использует менее базовый синтаксис, который может быть проблемой.


1
Можно утверждать, что цикломатическая сложность собственного кода здесь снижена, поскольку whereздесь, скорее всего, из фреймворка. Я думаю, что цикломатическая сложность как метрика полезна даже здесь, потому что, хотя разбивка функции на несколько не уменьшает общую сложность системы (действительно, она часто увеличивает ее, хотя бы немного), она помогает вам определить, когда часть системы становится чрезмерно сложной и требует разрушения.
3

6

Чтобы объективно ответить на вопрос, нам понадобится какой-то показатель для удобства обслуживания. Цикломатическая сложность сама по себе не является показателем ремонтопригодности, но она является компонентом некоторых показателей, предназначенных для измерения ремонтопригодности. Например, формула для индекса ремонтопригодности :

MI = 171 - 5.2 * ln(V) - 0.23 * (G) - 16.2 * ln(LOC)

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

Трудно сказать , делает ли вид изменения вы предлагаете программа кажется более ремонтопригодна для программистов; это, вероятно, зависит от того, насколько они знакомы (в вашем случае) с этим whereметодом.


Предупреждение: волшебные числа! (>_<)
Изката,

Есть только одна маленькая проблема с индексом ремонтопригодности. Три составляющих этого: объем Холстеда, цикломатическая сложность и строки кода. Объем Халстеда и цикломатическая сложность, как было показано, очень сильно коррелируют с линиями кода. Это означает, что может быть получено альтернативное приближенное уравнение для индекса ремонтопригодности, которое зависит ТОЛЬКО от строк кода, которое будет почти таким же точным, как и оригинал, со значительно меньшей вычислительной сложностью.
Джон Р. Штром

@ JohnR.Strohm Я думаю, что вы получите аналогичный результат, даже если вы просто используете LOC в качестве показателя ремонтопригодности. Изменение OP уменьшает LOC до 1 с 4, и другие изменения, которые уменьшают цикломатическую сложность, также могут уменьшить LOC. В любом случае, все сводится к тому, как вы определяете и измеряете ремонтопригодность.
Калеб

1
@ Калеб: Согласен. Я хочу подчеркнуть, что люди слишком часто обращаются к этим действительно сложным метрикам и комбинациям метрик, не осознавая, что почти все из них оказались сильно коррелированными в реальном коде с простыми старыми строками кода (LOC). и, следовательно, имеют не более прогнозирующее или описательное значение, чем LOC.
Джон Р. Штром

3

Поскольку было показано, что цикломатическая сложность (CC) очень сильно коррелирует с размером кода, «настолько, что можно сказать, что CC не имеет абсолютно никакой собственной объяснительной силы». на самом деле вы спрашиваете: «Снижают ли итерационные методы, такие как обычно встречающиеся в современных языках, таких как C #, JavaScript и (надеюсь) в Java 8, влияние размера кода на понятность и поддержку кода».

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


2

Если вы говорите о сырой статистике Cyclomatic Complexity, конечно. Вы просто обнулили его от 2 до 0. Если вы идете по цифрам, то получите чистый выигрыш.

С практической (читай: человеческой) точки зрения, я бы сказал, что вы на самом деле увеличили сложность на 2. Один из моментов этого заключается в том, что теперь какой-то другой программист должен принести или получить знание свободно-синтаксического LINQ, чтобы понять это. код.

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

В этом случае использование a.where(x => matches(x, arg))не является ужасным, и, честно говоря, это отличный способ заставить своего коллегу впервые увидеть и поработать с выражениями LINQ и Lambda (я фактически представил учебник по LINQ / Lambdas для некоторых бывших коллег, использующих этот и другие наборы кода, для большого эффекта.) Однако их использование требует некоторых знаний.

Я рекомендую осторожность, потому что я видел случаи, когда рефактор LINQ на самом деле значительно хуже для чтения, чем foreachстановится этот цикл.


1

Субъективно, от аудитории разработчиков зависит, понимают ли они лямбда-выражения;

List<String> filteredList = originalList.where(s => matches(s));

быстрее понять, и, возможно, немного легче. Я был бы более обеспокоен использованием s и match (). Ни один не является информативным, что-то вроде;

List<String> filteredList = 
    originalList.where(stringToBeTested => matchesNameTest(stringToBeTested));

Или же

List<String> filteredList = 
        originalList.where(originalListString => matchesNameTest(originalListString));

дает разработчику более значимую информацию и ее легче анализировать без необходимости углубляться в функцию match (), чтобы определить, какое сопоставление выполняется.

Поддерживаемость - это не только способность понимать код, но главным образом скорость и точность, с которой можно понять код.


2
Привет Эйс. Это пример, намеренно лишенный семантического контента для выделения структуры.
К. Росс
Используя наш сайт, вы подтверждаете, что прочитали и поняли нашу Политику в отношении файлов cookie и Политику конфиденциальности.
Licensed under cc by-sa 3.0 with attribution required.