Чи зменшують ітеративні методи цикломатичну складність та покращують сприятливість?


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 Це краще?
C. Ross

Я б асоціював ітераційні методи з ітераційними методологіями розвитку. Я думаю, що кращим терміном були б функції вищого порядку. (І як осторонь, методи не мають типу return / void, тоді як функції щось повертають).
Йоханнес Рудольф

@JohannesRudolph "Методи не мають типу повернення / недійсні, тоді як функції щось повертають" - на якій мові це правда? Я ніколи цього не чув; насправді єдине справжнє відмінність, про яке я чув, - це методи, пов'язані з класом, функції - ні.
кинув

Відповіді:


14

Я здогадуюсь, що ви просто розділили / перенесли складність. Він зменшився, оскільки ви не враховуєте реалізацію .where()свого CC.

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

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


11

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


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

6

Для того щоб відповісти на питання об’єктивно, нам знадобиться якась метрика для ремонту. Цикломатична складність сама по собі не є показником ремонтопридатності, але вона є складовою деяких показників, які спрямовані на вимірювання ремонтопридатності. Наприклад, формула індексу ремонтопридатності :

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

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

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


Попередження: Чарівні числа! (>_<)
Ізката

Є лише ця маленька проблема з індексом ремонтопридатності. Три її складові - об'єм Холстеда, цикломатична складність та лінії коду. Як показано, що об'єм Галстеда і цикломатична складність дуже сильно співвідносяться з кодовими лініями. Це означає, що альтернативне приблизне рівняння для індексу ремонтопридатності, яке залежало ТІЛЬКИ від рядків коду, може бути отримане таким же точним, як оригінал, із значно меншими труднощами в обчисленні.
Джон Р. Стром

@ JohnR.Strohm Я думаю, ви отримаєте подібний результат, навіть якщо ви просто використовуєте LOC як метрику ремонту. Зміна ОП знижує рівень LOC до 1 з 4, а інші зміни, що знижують цикломатичну складність, також можуть знизити LOC. У будь-якому випадку, це дійсно зводиться до того, як ви визначаєте та вимірюєте ремонтопридатність.
Калеб

1
@Caleb: Погоджено. Я намагаюся зробити те, що люди занадто часто звертаються за цими дійсно складними показниками та комбінаціями метрик, не усвідомлюючи, що майже всі вони виявляються сильно співвіднесеними реальним кодом із звичайними старими Lines Of Code (LOC) , а значить, не мають більш прогнозного або описового значення, ніж LOC.
Джон Р. Стром

3

Оскільки було показано, що цикломатична складність (CC) дуже сильно корелює з розміром коду, "настільки, що можна сказати, що CC абсолютно не має власної пояснювальної сили". що ви насправді запитуєте, чи "ітеративні методи, такі, як часто зустрічаються в сучасних мовах, таких як C #, JavaScript та (сподіваємось) в Java 8, зменшують вплив розміру коду на зрозумілість та підтримку коду".

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


2

Якщо ви говорите про сирий стан цикломатичної складності, то обов'язково. Ви просто запустили його від 2 до 0. Якщо ви їдете за номерами, чистий виграш, до кінця.

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

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

Цей випадок із застосуванням 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
Привіт Ейс. Це приклад, навмисно позбавлений смислового змісту для висвітлення структури.
C. Ross
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.