Как я могу определить и измерить простоту в коде?

13

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

Как я могу определить простоту в коде? Какие программные измерения и метрики доступны для измерения простоты кода?

Ричард
источник
2
@MarkTrapp Существуют и другие способы обсуждения простоты кода без тем эмпирической разработки программного обеспечения, с которыми я гораздо менее знаком. Например, обсуждаем простоту с точки зрения способности писать автоматизированные тесты. Мои навыки и знания позволяют мне ответить на этот вопрос с точки зрения опытного инженера-программиста, в то время как другие могут ответить с альтернативной точки зрения. Добавление этого утверждения к вопросу значительно ограничивает число полезных ответов, делая его (IMO) слишком локализованным. Если вы хотите добавить его, вы можете, но это хороший вопрос, как он есть.
Томас Оуэнс
2
@ThomasOwens У реальных вопросов есть ответы , а не идеи или мнения. Stack Exchange - это сужение области видимости, так что все понимают, как ответить на вопрос одинаково. Может быть больше чем один подход к решению проблемы, но есть только одна недвусмысленно заявленная проблема.
В его нынешнем состоянии очень мало ответов на этот вопрос (мой ответ касается точки зрения эмпирической разработки программного обеспечения, с общими метриками - возможно, есть и другие). Нет смысла исключать ответы, дающие обоснованные альтернативы из других точек зрения, что и делает формулировка этого вопроса. Я полностью не согласен с этими правками, и вопрос должен быть возвращен в исходную форму.
Томас Оуэнс
@MarkTrapp Проблема однозначна: как определить простоту кода? Есть несколько хороших ответов. Моя задача - использовать эмпирические методы разработки программного обеспечения для измерения сложности. Другим может быть написание автоматических тестов, и если сложно написать хорошие тесты, код сложен - совершенно правильный ответ. Могут быть и другие, о которых я не знаю. Если вам необходимо измерить сложность / простоту кодовой базы, вопрос должен быть сформулирован таким образом, чтобы можно было представить все альтернативы, чтобы просящий мог выбрать лучшее решение для своего конкретного случая.
Томас Оуэнс

Ответы:

16

Наиболее распространенными метриками для измерения сложности (или простоты, если принять простоту за противоположность сложности) являются цикломатическая сложность МакКейба и метрики сложности Холстеда .

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

Меры сложности Холстеда используют входные данные от общих и различных операторов и операндов для вычисления объема, сложности и усилия фрагмента кода. Сложность, которая представляет собой (количество уникальных операторов / 2) * (общее количество операндов / количество уникальных операндов), связана со способностью читать и понимать код для таких задач, как изучение системы или выполнение обзора кода. Опять же, вы можете посчитать это на системном уровне, уровне класса или уровне метода / функции. Есть несколько сообщений о том, как вычислить эти измерения здесь и здесь .

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

Разветвление и разветвление - это две другие метрики, связанные с потоком данных. Как определено здесь , fan in - это сумма вызванных процедур, считывание параметров, а считывание глобальных переменных и разветвление - это сумма процедур, вызывающих данную процедуру, записанных параметров (представленных внешним пользователям, переданных по ссылке), и глобальные переменные, записанные в. Опять же, высокий уровень разветвления и разветвления может указывать на модуль, который может быть трудным для понимания.

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

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

Томас Оуэнс
источник
5
Я знаю, что вы упомянули об этом, но важно подчеркнуть, что цикломатическая сложность действительно полезна только на уровне функций / методов и становится значительно более субъективной / бесполезной на более высоких уровнях.
Ryathal
Беда в том, что пока эти меры хороши, это общее руководство. Есть несколько случаев, когда «плохие» программы получают хорошие результаты, например, с дюжиной функций, когда достаточно одной функции с еще двумя параметрами, и, наоборот, многие «хорошие» программы, которые хорошо написаны для решения сложной проблемы, могут получить оценку. плохо.
Джеймс Андерсон
@ Джеймс Я прямо указал на это. Любое измерение или метрика должны рассматриваться в контексте как показатель того, что на что-то нужно смотреть. Требуется решение инженера, чтобы определить, необходимы ли корректирующие действия и что это за действие. Однако, если вы не собираете данные активно, нет эмпирического способа узнать о потенциальных проблемах.
Томас Оуэнс
7

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

Я не ставлю некоторую меру простоты, но когда вы называете что-то простое или нет.

1. Обход кода:
насколько легко перемещаться по коду? Легко ли определить, где написаны функции API? Легко ли понять потоки вызовов, например, какие методы вызывают другие (и почему) - реализованы ли хорошие конечные автоматы или четко определены алгоритмы?

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

2. Присвоение имен
В то время как другие стандарты кодирования помогают сделать код более понятным, наиболее важным является присвоение имен классам / объектам-экземплярам / переменным / методам. Использование четкие и однозначные имена явно имеет большое влияние на простоте коды. Когда трудно определить простое имя, это признак того, что вы можете переосмыслить идею, являющуюся этой переменной / методом.

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

4. Зависимость или взаимосвязь.
Об этом сложно судить, просто взглянув на код, но становится очень очевидным, если кто-то пытается исправить ваши ошибки. Когда некоторые другие вещи изменяются в каком-то другом объекте, изменяется ли операция здесь? Эти изменения очевидны? Вам нужно менять API так часто, чтобы приспособить вещи? Это говорит о том, что межмодульные отношения не просты

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

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

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

Дипан Мехта
источник
1
Он попросил измерения и метрики. Это субъективно, поэтому я не думаю, что они очень точны.
PSR
@psr Я согласен с тобой. Это было также очень очевидно из ответа из ответа Фомы. Однако он упомянул простоту, связанную с удобочитаемостью . Ответ Томаса имеет дело с цикломатической сложностью - это говорит о том, насколько сложно проверить код, а не о том, насколько сложен код с точки зрения читабельности и может расширить возможности сопровождения . Это две совершенно разные концепции. Именно поэтому я написал этот ответ, чтобы поставить резкое противоречие. К сожалению, насколько мне известно, нет метрик, которые относятся к простоте кода с точки зрения читабельности.
Дипан Мехта
«использовать имена, которые невозможно понять неправильно» - ИМХО, это слишком высокая цель, к нереальной и невозможной цели. Я бы предпочел не пытаться быть настолько определенным и просто сказать «используйте ясные и недвусмысленные имена».
Петер Тёрёк
@ PéterTörök Я согласен. Я думаю , как правило, во многих организациях, очень четко определенных правил именования и еще некоторая путаница о интенции от конкретных переменных сохраняется. Поэтому акцент был сделан на том, что ясность цели означает простоту, а не формальное правило. Может быть, я пошел за борт в том, как я описал. Благодарю.
Дипан Мехта
@Dipan Цикломатическая сложность связана с удобочитаемостью кода через рабочую память. Код с высокой цикломатической сложностью (или даже просто с большой глубиной блока) трудно хранить в рабочей памяти, поэтому его сложнее читать.
Томас Оуэнс
0

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

  • Простота используемых языковых функций: если в языке есть функции, которые можно считать «продвинутыми» и «простыми», вы можете подсчитать количество появлений расширенных функций. То, как вы определяете «продвинутый», может быть немного более субъективным. Я предполагаю, что некоторые могут сказать, что это также похоже на измерение «умности» программы. Типичный пример: некоторые могут сказать, что ?:оператор должен быть «продвинутой» функцией, другие могут не согласиться. Я не знаю, насколько легко было бы написать инструмент, который может проверить это.

  • Простота конструкций внутри программы: вы можете измерить количество параметров, которые примет функция. Если у вас есть> п % всех функций с> м параметров, вы можете выбрать , чтобы считать это не просто, в зависимости от того, как вы определяете н и м (может быть , п = 3 и т = 6?). Я думаю, что есть некоторые инструменты статического анализа, которые могут это измерить - я думаю, что JTest просто измеряет функции с> m параметрами.

  • Вы можете попытаться посчитать количество вложенных циклов или управляющих структур. Это, я думаю, на самом деле не плохой показатель, и я думаю, что есть имя для него (не могу вспомнить с верху моей головы). Опять же, я думаю, что есть инструменты (опять же, как JTest), которые могут в определенной степени измерить это.

  • Вы можете попытаться измерить «рефакторируемость». Если ваш код содержит много фрагментов кода, которые могут быть реорганизованы, но это не так , возможно, это было бы не так просто. Я также вспоминаю со времени, когда я работал с JTest, он тоже пытался измерить это, но я помню, что не часто соглашался с этим в этом случае, поэтому YMMV.

  • Вы можете попытаться измерить количество слоев между различными частями вашей системы. Например: сколько различных частей кода будет касаться данных, которые поступают из веб-формы, прежде чем они будут сохранены в базе данных? Это может быть сложно измерить правильно ...

FrustratedWithFormsDesigner
источник
2
Я считаю, что № 3 называется глубиной блока. Это также связано с цикломатической сложностью, если задействованы структуры контроля принятия решений.
Томас Оуэнс
Нет объяснения понижения?
FrustratedWithFormsDesigner
Не могу согласиться с «простотой языковых возможностей». Расширенные возможности существуют для упрощения кода. Использование только простых, базовых функций затруднит понимание того, что на самом деле делает код, это неизбежно приведет к утечке уровней абстракции. Расширенные возможности языка позволяют выразить более высокие уровни абстракции, делая ваш код намного более плотным и читаемым. Чем более продвинутые функции вы используете (разумно, конечно), тем лучше для простоты. Просто сравните код, скажем, в Matlab (который действительно «продвинутый») с аналогичным кодом на Fortran, сделанном только из базовых функций.
SK-logic
И я не буду согласен с метрикой ряда слоев. Если вы можете сделать что-то за дюжину простых и чистых шагов или за одно скрученное преобразование, лучше сделать это за несколько шагов. Многие простые и четко разделенные слои намного лучше (и проще), чем один скрученный слой.
SK-logic
@ SK-logic: я думаю, мне следовало бы назвать это «умом», это ближе к тому, что я имел в виду. Я бы сказал, что такие вещи ?:являются проблемой, когда они вложены в 5 глубин. Что касается слоев, то четко разделенные слои лучше, чем один извилистый слой. Но 7 в основном избыточных слоев, когда нужны были только 2 или 3, - это плохо.
FrustratedWithFormsDesigner