Говоря о цикломатической сложности во внешнем интерфейсе

внешний интерфейс
Говоря о цикломатической сложности во внешнем интерфейсе

DevUI – это команда, которая занимается как проектированием, так и проектированием, обслуживая HUAWEI CLOUD.DevCloudПлатформа и несколько промежуточных и серверных систем в Huawei предназначены для дизайнеров и проектировщиков.
Официальный сайт:devui.design
Библиотека компонентов Ng:ng-devui(Добро пожаловать в Звезду)

введение

Рефакторинг — неизбежная часть нашего процесса разработки. Рефакторинг кода для адаптации к разнообразным сценариям, которые не рассматривались в начале разработки текущего модуля, и повышение удобства сопровождения, надежности и тестируемости модуля. Итак, как уточнить направление реконструкции и количественно оценить результаты реконструкции?

Цикломатическая сложность (CC) может быть альтернативной метрикой.

Что такое цикломатическая сложность

Цикломатическая сложность (CC), также известная как условная сложность или циклическая сложность, представляет собой программную метрику, предложенную Томасом Дж. Маккейбом-старшим в 1976 году. Она используется для представления сложности программы и имеет символ VG или М. Цикломатическая сложность — это количество линейно независимых путей в исходном коде программы.

Зачем уменьшать цикломатическую сложность модулей (функций)

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

Цикломатическая сложность

статус кода

Тестируемость

стоимость технического обслуживания

1 - 10

ясно и структурировано

высоко

Низкий

10 - 20

сложный

середина

середина

20 - 30

очень сложно

Низкий

высоко

>30

нечитаемый

Непредсказуемый

очень высоко

Уменьшить сложность программного обеспечения

Когда Маккейб предложил цикломатическую сложность, одной из его первоначальных целей было ограничение ее сложности при разработке программного обеспечения. Он предложил программистам рассчитать сложность своих модулей разработки: если цикломатическая сложность модуля превышает 10, его нужно разделить на более мелкие модули. Методология структурированного тестирования NIST (Национальный институт стандартов и технологий) несколько скорректировала этот подход: в некоторых конкретных случаях целесообразнее ослабить верхний предел цикломатической сложности модуля до 15. Эта методология также допускает, что в некоторых особых случаях сложность модуля должна превышать верхний предел. Верхний предел».

Увеличьте связность модулей

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

Уменьшить количество возможных программных ошибок

Во многих исследованиях отмечается, что цикломатическая сложность модуля (функции) связана с количеством дефектов в нем, число дефектов также является наибольшим.

Улучшенная тестируемость модуля

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

Повышение читаемости кода

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

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

метод расчета

Цикломатическая сложность программы — это количество ее линейно независимых путей. Если в программе нет потока управления, такого как инструкция IF или цикл FOR, потому что в программе только один путь, ее цикломатическая сложность равна 1. Если в программе есть инструкция IF, будет два разных пути , соответствующий тому, выполняется ли условие ЕСЛИ или нет, поэтому цикломатическая сложность равна 2.

Математически цикломатическая сложность структурированной программы определяется графом потока управления программы. Граф потока управления является ориентированным графом, а узлы в графе являются базовыми модулями программы. Если один модуль заканчивается, другой может Для модуля используйте стрелки, чтобы связать два модуля и указать возможный порядок выполнения. Цикломатическая сложность M может быть определена как:

M = E − N + 2P

в

E - количество ребер в графе

N - количество узлов в графе

P - количество подключенных компонентов

Метрики

CodeMetrics

Плагин VSCODE для метрик TS, сложность кода JS CODE.

ESLint

eslintТакже можно настроить правила цикломатической сложности, такие как:

rules: { 
  complexity: [ 
    'error', 
    { 
      max: 15 
    } 
  ] 
}

представляет текущий函数из最高圈复杂度равно 15, иначеeslintдам错误提示.

conard cc

Инструмент определения цикломатической сложности с открытым исходным кодом (github:GitHub.com/con AR DL i/Арвен…) для создания отчета о цикломатической сложности кода в рамках текущего проекта.

Как уменьшить цикломатическую сложность модуля (функции)

Цикломатическая сложность общих структур

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

последовательная структура

Последовательная структура имеет сложность 1.

пример:

function func() {
  let a = 1, b = 1, c;
  c = a * b;
}

Как показано в приведенном выше коде, функция func представляет собой последовательную структуру, и ее схема потока управления выглядит следующим образом:

ребро: 1, точка: 2, соединенная ветвь: 1,

Цикломатическая сложность:

M = 1 - 2 + 2 * 1 = 1

if-else-else, переключатель регистра

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

пример:

function func() {
  let a = 1, b = 1, c;
  if (a = 1) {
    c = a + b;
  } else {
    c = a - b;
  }
}

Ребра: 4, Точки: 4, Соединённые ответвления: 1,

Цикломатическая сложность:

M = 4 - 4 + 2 * 1 = 2

петлевая структура

Добавление структуры цикла увеличивает сложность на 1. ,

пример:

function func() {
  let a = 1, b = 1, c = 2;
  for (let i = 1; i < 10; i++) {
    b += a;
  }
  c = a + b;
}

Ребра: 4, Точки: 4, Соединённые ответвления: 1,

Цикломатическая сложность:

M = 4 - 4 + 2 * 1 = 2

return

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

Метод сложности общий модуль уменьшения (функция)

1. Извлечение и разделение функций, единая ответственность (рекомендуется)

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

пример:

function add(a, b) {
  let tempA;
  if (a === 10) {
    tempA = 11;
  } else if (a === 12) {
    tempA = 12;
  }
  let tempB;
  if (b === 10) {
    tempB = 13;
  } else if (b === 12) {
    tempB = 12;
  }
  return tempB + tempA;
}

Рефакторинг:

function add(a, b) {
  return calcA(a) + calcB(b);
}

function calcA(a) {
  if (a === 10) {
    return 11;
  } else if (a === 12) {
    return 12;
  }
}

function calcB(b) {
  if (b === 10) {
    return 13;
  } else if (b === 12) {
    return 12;
  }
}

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

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

2. Алгоритм оптимизации (уменьшение ненужных условий, ответвлений цикла)

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

пример:

let a = 'a', c;
if (a === 'a') {
  c = a + 1;
} else if (a === 'b') {
  c = a + 2;
} else if (a === 'c') {
  c = a + 3;
} else if (a === 'd') {
  c = a + 4;
}
return c;

Рефакторинг:

let a = 'a', c;
let conditionMap = {
  a: 1,
  b: 2,
  c: 3,
  d: 4
}
c = a + conditionMap[a];
return c;

Устраняет все условные переходы, что значительно снижает цикломатическую сложность текущей функции.

3. Оптимизация логики выражений

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

пример:

a && b || a && c

Простую оптимизацию можно сделать так:

a && (b || c)

Это уменьшает цикломатическую сложность выражения на 1.

5. Уменьшить ранний возврат (этот метод нужно рассматривать диалектически)

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

пример:

let a = 1, b = 1;
if (a = 1) {
  return a + b;
} else {
  return a - b;
}

Рефакторинг:

let a = 1, b = 1, c;
if (a = 1) {
  c = a + b;
} else {
  c = a - b;
}
return c;

Цикломатическая сложность будет уменьшена на 1.

Суммировать

Код с высокой цикломатической сложностью (CC) не должен быть хорошим кодом.Для измерения качества нашего кода цикломатическая сложность может быть использована в качестве эталонного показателя;цикломатическая сложность может быть рассчитана по графу потока управления;для сокращения модулей (функций) Цикломатическая сложность, функции уточнения и разделения, оптимизация алгоритмов и оптимизация логических выражений — все это методы, которые можно попробовать.

Ссылаться на

Циклическая сложность:This.Wikipedia.org/wiki/%E5%be…

Подробная цикломатическая сложность:Кэ Лю Чанг 81.GitHub.IO/2017/06/18/…

Качество внешнего кода - принцип цикломатической сложности и практика:nuggets.capable/post/684490…

Присоединяйтесь к нам

МыКоманда DevUIДобро пожаловать и присоединяйтесь к нам, чтобы создать элегантную и эффективную систему человеко-машинного проектирования/исследований и разработок. Электронная почта для приема на работу:muyang2@huawei.com.

Текст/DevUI бах-бах-бах

Рекомендуемые статьи в прошлом

"Научит вас создавать собственную библиотеку компонентов Angular.

«Научить вас разрабатывать компоненты разбивки на страницы с использованием трех фреймворков Vue/React/Angular»

"Научить вас, как создать среду публикации в оттенках серого"