Почему цикломатическая сложность так важна для одного метода?


10

Я использую SonarLint для Eclipse с недавнего времени, и это мне очень помогло. Однако, это подняло мне вопрос о цикломатической сложности.

SonarLint считает приемлемым CC 10, и в некоторых случаях я превышаю его, около 5 или 6 единиц. Эти части относятся к картографам, где значения зависят от разных переменных, например:

  • Поле A опирается на строку sA;
  • Поле B опирается на строку sB;
  • Поле C опирается на String sC;
  • так далее ...

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


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

(Извините за мелкие ошибки, если есть).


РЕДАКТИРОВАТЬ

Мой вопрос касается не глобальной цикломатической сложности, а только сложности одного метода и разделения метода (у меня есть трудное время, чтобы объяснить, что именно я имею в виду, извините). Я спрашиваю, почему допустимо разделить ваши условия на более мелкие методы, если они все еще принадлежат «супер-методу», который будет просто выполнять каждый суб-метод, тем самым добавляя сложности алгоритму.

Однако вторая ссылка ( об анти-паттерне ) очень полезна.




^^^ вопрос «стрелка в голову», вероятно, является лучшим дубликатом в том смысле, что он объясняет, как улучшить ваш код, но я выбрал первый из-за подробного объяснения, отвечающего на часть вашего вопроса о цикломатической сложности
комнат

Разделение метода на более мелкие части не сокращает общий объем выполняемого кода, а делает понятными отдельные выполняемые задачи; каждый из них может быть понятен намного легче индивидуально, чем когда они все запутаны в большее целое. По крайней мере, он удаляет много одноразовых промежуточных переменных из более широкой области видимости.
Довал

1
Для вашего конкретного описанного случая я бы сделал что-то в вашем основном методе, например "A = extractAFrom (sA);" для каждого поля. Вы, вероятно, можете придумать лучшие имена, так как вы знаете фактические поля и их использование.
Жестянщик

Ответы:


32

Основная вещь здесь: «емкость мозга».

Видите ли, одна из основных функций кода ... для чтения . И код может быть легко читаемым и понятным; или сложно.

А наличие высокого CC просто подразумевает множество «уровней» в рамках одного метода. И это подразумевает: вам, читателю, будет трудно понять этот метод.

Когда вы читаете исходный код, ваш мозг автоматически пытается представить вещи в перспективе: другими словами - он пытается создать некую форму «контекста».

И когда у вас есть маленький метод (с хорошим именем), который состоит только из нескольких строк и очень низкого CC; тогда ваш мозг может легко принять этот «блок». Вы читаете это, вы понимаете это; СДЕЛАННЫЙ.

С другой стороны, если ваш код имеет высокий уровень CC, ваш мозг будет тратить много «циклов» больше, чтобы вычесть то, что происходит.

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


9
Так что в основном речь идет не о технических вопросах, а о людях ? Это звучит действительно умно, я не знаю, как я не думал об этом раньше. Спасибо !
Яссин Бадач

4
Если это так, я искренне рекомендую вам приобрести «Чистый код» Роберта Мартина (вы можете найти PDF бесплатно в сети). Видите ли, создание читаемого кода является одним из наиболее важных, но очень часто игнорируемых достоинств хорошего программиста.
GhostCat приветствует Монику С.

@YassineBadache CC также затрудняет тестирование каждого закоулка (полное покрытие).
Тулаинс Кордова

Это была также и суть дела Дейкстры .
Сет Бэттин

По моему опыту, ошибки почти всегда есть в методах с высоким CC, а когда ошибки в методе с низким CC, они, как правило, совершенно очевидны, и они не могут спрятаться за первым прогоном кода. Кроме того, я обнаружил, что мне почти никогда не приходится модифицировать метод с низким уровнем СС - большая нагрузка снимается с мозга.
Лорен Печтел

6

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

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


2
Если «FieldA полагается на String sA» в качестве состояния OP, я не уверен, что перемещение этого в CalculateFieldA (String sA) приведет к более запутанному коду.
Taemyr

2

Вкратце: все дело в удобочитаемости и, следовательно, удобстве сопровождения вашего кода.

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


Хотя это хороший ответ, он немного короток. Было бы неплохо, если бы вы могли привести пример того, что вы говорите, и быть более конкретным в отношении вопроса, заданного ОП: «почему так важно не иметь слишком высокий СС в одном методе?».
Мачадо

2

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

Кроме того, я согласен с другими ответами по другим соображениям - умственные способности разработчика или индикатор потенциальных проблем или рефакторинг или мера читаемости и ремонтопригодности кода .


0

CC - это просто эвристика, и от того, насколько «плох» конкретный результат, зависит многое.

Тем не менее, вы всегда должны рассматривать высокий CC как нечто, что выделяет код, который можно / нужно реорганизовать. Вы говорите, что перемещение ifоператора в другой метод скрывает проблему - но есть ли там шаблон, который вы можете абстрагировать вместо вставки копий n раз? Если это длинная if-elseцепочка, можете ли вы превратить ее в оператор switch, или, возможно, использовать полиморфизм или что-то еще? Если есть глубокое вложение, можно ли объединить некоторые из ваших условных предложений, или это указывает на отдельные обязанности, которые следует разделить на разные классы?


0

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

Один из способов уменьшить тип CC, который вы упоминаете, - это использовать полиморфизм, поскольку вы пометили свой вопрос тегом Java. Таким образом, вместо строковых путей кода вы можете использовать хорошо именованные классы. Это может помочь, но иногда излишне и может сделать ваш код еще сложнее для понимания.

Однако это может быть признаком кода, который будет сложно поддерживать. Легко ли увидеть, какой путь кода вы будете использовать при каждом чтении при чтении метода? Сможете ли вы пропустить этот метод, если вы плохо знаете кодовую базу и искали что-то связанное, но дальше в коде? Я знаю, что некоторые люди выступают за разделение методов на множество методов длиной в 1/2 строки с описательными именами, но иногда я думаю, что это даже сложнее читать, чем код, который он должен был заменить.

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


0

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

  • Рассмотрим метод с 10 строками - возможно, потребуется несколько минут, чтобы понять, что он делает.
  • Рассмотрим метод из 100 строк - возможно, потребуется час или больше, чтобы понять, что происходит.
  • Рассмотрим метод из 1000 строк - возможно, потребуется день или больше, чтобы понять, что происходит.

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

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

Еще одна вещь, которую следует учитывать, это обновление сложного кода. При проведении анализа разработчик может сообщить, что изменение кода более или менее рискованно, если посмотреть на его сложность.

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


1
Извините Ghost Cat ответ очень похож, следовало бы обновить страницу.
Джон Рейнор
Используя наш сайт, вы подтверждаете, что прочитали и поняли нашу Политику в отношении файлов cookie и Политику конфиденциальности.
Licensed under cc by-sa 3.0 with attribution required.