Каково увлечение метриками кода?
================================

В последнее время я видел ряд связанных с "кодовыми метриками" вопросов о SO, и вам интересно, что это за увлечение? Вот несколько недавних примеров:

* [какие показатели кода убедят вас в том, что предоставленный код дерьмовый](/questions/70171/what-code-metrics-convince-you-that-provided-code-is-crappy)
* [если когда-либо количество строк кода полезной метрики](/questions/70173/when-if-ever-is-number-of-lines-of-code-a-useful-metric)
* [написание тестов качества](/questions/70174/writing-quality-tests)

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

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

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

Есть ли какое-то волшебное понимание, которое можно получить из кодовых показателей, которые я забыл? Ленькие программисты/менеджеры ищут оправдания, чтобы не читать код? Люди представлены гигантскими устаревшими кодами и ищут место для начала? Что происходит?

>  Примечание. Я задал некоторые из этих вопросов по конкретным темам как в ответах, так и в комментариях, и не получил ответов, поэтому я подумал, что я должен просить сообщество вообще, возможно, что я что-то упускаю. Было бы неплохо запустить пакетное задание метрики, и на самом деле мне не нужно снова читать код других людей (или мой собственный), я просто не думаю, что это практично!

EDIT: Я знаком с большинством, если не во всех обсуждаемых метриках, я просто не вижу смысла в них отдельно или как произвольные стандарты качества.

 

Ответы в этой теме немного странные, о чем они говорят:

* "команда", как "единственный и единственный бенефициарий" этих указанных показателей;
* "метрики", как будто они означают что-то само по себе.

1/Метрики не для одной совокупности, а для трех:

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

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

2/Метрики сами по себе представляют  **снимок** кода, а это значит... ничего!

Это комбинация этих показателей и комбинации этих разных уровней анализа, которые могут указывать на "хороший" или "плохой" код, но что более важно, это  **тренд этих показателей** Это важно.

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

---

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

* "красивый" код (хотя это всегда в глазу наблюдателя-кодера)
* "хороший" код (который работает и может доказать, что он работает)

 .i1a { width: 336px; height: 280px; }
 @media(min-width: 768px) { .i1a { width: 728px; height: 90px; } }
 @media(min-width: 992px) { .i1a { width: 360px; height: 300px; } }
 @media(min-width: 1083px) { .i1a { width: 728px; height: 90px; } }

 (adsbygoogle = window.adsbygoogle || []).push({});

Так, например, функцию с циклической сложностью 9 можно было бы определить как "красивую", а не одну длинную запутанную функцию цикломатической сложности 42.

НО, если:

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

можно утверждать:

* последний представляет собой "хороший" код (он работает, он стабилен, и если его нужно изменить, можно проверить, продолжает ли он после модификаций),
* первый - это "плохой" код (ему все равно нужно добавить некоторые случаи и условия, чтобы охватить все, что он должен делать, и нет простого способа сделать некоторый регрессионный тест)

---

Итак, суммируем:

>  единственная метрика, которая сама по себе всегда указывает [...]
> 
> 
> 

: не так много, за исключением того, что код может быть более "красивым", что само по себе не означает многого...

>  Есть ли какое-то волшебное понимание, которое можно получить из кодовых показателей, которые я забыл?
> 
> 
> 

Только комбинация и тренд метрик дают реальную "магическую проницательность", которую вы после.

 

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

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

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

 .i2a { width: 336px; height: 280px; }
 @media(min-width: 768px) { .i2a { width: 728px; height: 90px; } }
 @media(min-width: 992px) { .i2a { width: 360px; height: 300px; } }
 @media(min-width: 1083px) { .i2a { width: 728px; height: 90px; } }

 (adsbygoogle = window.adsbygoogle || []).push({});

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

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

Метрики - это путеводители и помогают, а не сами по себе.

 

Лучшей метрикой, которую я когда-либо использовал, является C.R.A.P. Гол.
<http://www.artima.com/weblogs/viewpost.jsp?thread=215899>

В основном это алгоритм, который сравнивает взвешенную циклическую сложность с автоматизированным тестированием. Алгоритм выглядит так: `CRAP(m) = comp(m)^2 * (1 – cov(m)/100)^3 + comp(m)`
где comp (m) - цикломатическая сложность метода m, а cov (m) - покрытие тестового кода, предоставляемое автоматическими тестами.

Авторы вышеупомянутой статьи (пожалуйста, пойдите, прочитайте это... это стоит вашего времени) предложить максимум C.R.A.P. оценка 30, которая разбивается следующим образом:

```
Method’s Cyclomatic Complexity        % of coverage required to be
                                      below CRAPpy threshold
------------------------------        --------------------------------
0 – 5                                   0%
10                                     42%
15                                     57%
20                                     71%
25                                     80%
30                                    100%
31+                                   No amount of testing will keep methods
                                      this complex out of CRAP territory.

```

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

Для большинства моих разработчиков я очень старался получить C.R.A.P. оценка ниже 8, но если у них были веские причины, чтобы оправдать добавленную сложность, которая была приемлемой, если они покрывали сложность достаточными испытаниями. (Написание сложного кода всегда очень сложно проверить... вид скрытой выгоды для этой метрики).

Большинство людей сначала пытались написать код, который передал бы C.R.A.P. Гол. Но со временем они написали лучший код, код, в котором было меньше проблем, и код, который было намного легче отлаживать. Из любой метрики это тот, который имеет наименьшее количество проблем и большую пользу.

 

Для меня самой важной метрикой, которая идентифицирует плохой код, является циклическая сложность. Почти все методы в моих проектах ниже CC 10, и ошибки неизменно обнаруживаются в унаследованных методах с CC более 30.
High CC обычно указывает:

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

 

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

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

 

Есть одна метрика кода, в которую я верю.

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

  **Чем меньше это число, тем лучше.**

 

Мое очень субъективное мнение состоит в том, что метрики кода выражают неудержимое институциональное увлечение тем, что они способны количественно определить что-то неотъемлемо не поддающееся количественной оценке.

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

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

Не говоря, я считаю, что это хорошая мера, только я вижу, что внутризаконная непреодолимость. И, как вы указали, есть, вероятно, несколько разумных показателей (много 500 линейных методов, высокая сложность - возможно, плохая). Я никогда не был в месте, которое купило это, хотя.

 

Люди обращаются к идее механистических способов понять и описать код. Если это правда, подумайте о последствиях для эффективности и производительности!

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

Например, экстремальные значения для некоторых показателей указывают путь к возможным проблемам. Метод длиной 1000 строк, вероятно, недостижим. Код с нулевым охватом кода unit test, вероятно, имеет больше ошибок, чем аналогичный код с большим количеством тестов. Большой прыжок в коде, добавленный в проект непосредственно перед выпуском, который не является сторонней библиотекой, вероятно, вызывает дополнительное внимание.

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

 

Метрики и автоматические тесты не предназначены для полной проверки кода.

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

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

Измерения полезны, если:

* Команда разработала их.
* Команда согласилась с ними.
* Они используются для идентификации определенной области.

В общем, любая метрика, которая не вписывается в это, будет страдать от команды, оптимизирующей ее. Вы хотите измерить строки кода? Честно говоря, сколько можно писать! Вы хотите измерить охват кода, golly, наблюдайте, как я покрываю этот код!

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

 

Вот некоторые показатели сложности из stan4j (http://stan4j.com/).

Инструмент анализа структуры класса eclipse.

Мне нравится этот инструмент и метрики. Я рассматриваю показатели как статистику, индикаторы, предупреждающие сообщения. Когда-то из-за некоторых методов или некоторых классов действительно была сложная логика, которая делала их сложными, что должно быть сделано, следите за ними,
просмотрите их, чтобы проверить, необходимо ли их реорганизовать или тщательно их просмотреть, поскольку они обычно подвержены ошибкам. Также я использую его как инструмент анализа, чтобы изучить исходный код, из-за того, что мне нравится учиться от сложного до простого. Фактически он включает в себя некоторые другие показатели, такие как метрики Роберта К. Мартина, Chidamber и Kemerer Metrics, Count Metrics
Но мне нравится этот лучший

  **Показатели сложности**

  **Циклические показатели сложности**

  **Цикломатическая сложность (CC)**
Циклическая сложность метода - это количество точек принятия решения в графе потока управления методом, увеличенном на единицу. Точки решения встречаются в случаях, когда /for/while, предложения case/catch и аналогичные элементы исходного кода, где поток управления не только линейный. Количество точек принятия решения (байтового кода), введенных одним (исходным кодом), может варьироваться в зависимости, например, о сложности булевых выражений. Чем выше значение циклометрической сложности метода, тем больше тестовых случаев требуется для проверки всех ветвей графа потока управления методом.

  **Средняя циклическая сложность**
Среднее значение метрики Cyclomatic Complexity по всем методам приложения, библиотеки, дерева пакетов или пакета.

  **Жирные показатели**
Матовая метрика артефакта - это количество ребер в соответствующем графике зависимостей артефакта. Тип графа зависимости зависит от варианта метрики и выбранного артефакта:

  **Жир**
Матовая метрика приложения, библиотеки или дерева пакетов - это счетчик границ его графа зависимости поддерева. Этот график содержит все дочерние артефакты в иерархии дерева пакетов, а также включает в себя листовые пакеты. (Чтобы увидеть соответствующий график в представлении компоновки, необходимо отключить переключение "Плоские пакеты" в проводнике структуры. Переключатель "Показать библиотеки" должен быть включен, если выбранный артефакт является библиотекой, в противном случае он должен быть отключен.)

Матовая метрика пакета - это счетчик края его графа зависимости от единицы. Этот график содержит все классы верхнего уровня пакета.

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

  **Жир для зависимостей библиотек (Fat - Libraries)**
Показатель Fat for Library Dependencies представляет собой счетчик границ его графиков зависимости библиотеки. Этот график содержит все библиотеки приложения. (Чтобы увидеть соответствующий график в представлении компоновки, нужно включить переключатель "Показать библиотеки библиотек" ).

  **Жир для плоских зависимостей пакета (Fat - Packages)**
Метрика приложения Fat for Flat Package Dependencies представляет собой счетчик грани его плоского графика зависимости пакета. Этот график содержит все пакеты приложения. (Чтобы увидеть соответствующий график в представлении компоновки, необходимо включить переключатель Flat Packages структуры Explorer, и запрет Показать библиотеки будет отключен.)

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

  **Жир для зависимостей класса верхнего уровня (Fat - Units)**
Показатель Depth Fat для уровня верхнего уровня приложения или библиотеки - это счетчик границ его графа зависимости от единицы. Этот график содержит все классы верхнего уровня приложения или библиотеки. (Для разумных приложений он слишком велик, чтобы быть визуализированным и, следовательно, не может отображаться в представлении композиций. Графы зависимости от единицы могут отображаться только для пакетов.)

 

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

Oh... и это предполагает, что хотя бы один из участников вашего обзора кода имеет ключ.

 

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

 

Метрики не заменяют проверку кода, но они намного дешевле. Это показатель больше всего.

 

Одна часть ответа состоит в том, что некоторые метрики кода могут дать вам очень быстрый первоначальный удар при ответе на вопрос: что это за код?

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

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

 

Метрики сами по себе не особо интересны. Это то, что вы делаете с ними, что считается.

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

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

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

edit: В ответ на комментарии Стивена А. Лоу - это абсолютно правильно. В любом анализе данных необходимо быть осторожным, чтобы различать причинную связь и простое соотношение. Важен выбор метрик на основе пригодности. Нет смысла пытаться измерять потребление кофе и атрибутировать качество кода (хотя я уверен, что некоторые пробовали;-))

Но прежде чем вы сможете найти отношение (причинное или нет), вы должны иметь данные.

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

Итак, прежде чем собирать данные, вам нужно знать, что вы хотите с ними делать. Если метрика - это средство, каков конец?

 

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

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

 

Мы программисты. Нам нравятся номера.

Кроме того, что вы собираетесь делать, НЕ описывайте размер базы кода, потому что "строки метрик кода неактуальны"?

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