Есть ли какие-либо научно-строгие исследования принципов стиля кодирования? [закрыто]

25

Является ли принцип стиля кодирования - например, принцип единого выхода - действительно хорошей вещью? Всегда или просто иногда? Насколько это действительно важно?

Каковы бы ни были ваши мнения, это, очевидно, субъективные вопросы. Или они?

Кто-нибудь пытался провести объективное, с научной точки зрения тщательное изучение принципов стиля кодирования?

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

Steve314
источник
5
Вы можете быть заинтересованы в чтении кода завершено. Все не поддается измерению, но многое есть, и в этой книге вы найдете хороший обзор с необработанными данными или источниками.
Deadalnix
Это также сильно зависит от языка, некоторые принципы применяются к конкретным языкам, а не к другим. Например, single-exit principleэто не относится к C ++ из-за RAII
Мартин Йорк,
@ Локи - я должен был подумать об этом, и я не уверен, что согласен. Это правда, что RAII в значительной степени предназначен для работы с исключениями, которые являются альтернативными точками выхода, но (по крайней мере, для некоторых людей) они считаются альтернативными альтернативными точками выхода - на самом деле не учитываются принцип единого выхода break, gotoили returnделать. Единственный выход IOW не является абсолютным в C ++, но в любом случае это мой взгляд на C и большинство других языков. Но это все еще актуально в нестрогом смысле.
Steve314
1
@ Steve314, статья по крайней мере отдаленно актуальна - в ней изложен план методологии такого эксперимента, что весьма важно из-за очевидного отсутствия должным образом зарегистрированных экспериментальных данных в этой области.
SK-logic

Ответы:

11

Я повторяю комментарий Deadalnix: прочитайте Code Complete 2 . Автор (Стив Макконнелл) подробно обсуждает стиль кодирования и часто ссылается на статьи и данные.

М. Дадли
источник
Фундаментальный и хорошо представленный обзор профессиональной разработки программного обеспечения, надеюсь, однажды я найду аналогичный для обеспечения качества. Главы о защитном программировании и программировании псевдокодов были особенно полезны для меня. Глава о методах совместной разработки кажется наиболее убедительной из всех, что я до сих пор читал по этим вопросам.
комнат
Я не читал эту книгу, и, возможно, мне следовало бы, но - основываясь на комментариях в ответе комаров - действительно ли эти статьи, на которые ссылаются, действительно научно точны и объективны? Если ответ «как можно больше», какие компромиссы были необходимы? Как я предположил в вопросе, нужно ли было заменять двойной слепой на более слабый стандарт?
Steve314
@ Steve314: я не знаю, я не проверял источники! Но вам не всегда нужна научная строгость, чтобы установить лучшие практики. Обсуждение плюсов и минусов иногда достаточно.
М. Дадли
@emddudley - абсолютно верно, но не совсем то, о чем этот вопрос.
Steve314
@ Steve314: Code Complete будет для вас отличной отправной точкой, и я уверен, что некоторые из его ссылок посвящены проблеме научного анализа стиля кодирования.
М. Дадли
12

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

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

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

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

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

Конрад Моравский
источник
1
Круто, я никогда не слышал о Колемаке раньше
CaffGeek
1
@ Чед еще менее известен, это Carpal X, с которым я играл некоторое время. Я нашел это лучше, чем Colemak (я достиг 90-100 оборотов в минуту с карпалксом). Даже если вы не собираетесь переключаться на какие-либо экзотические раскладки, веб-сайт carpalx чрезвычайно интересен для оценки и оптимизации раскладок клавиатуры и использования генетических алгоритмов для этой категории проблем. См. Mkweb.bcgsc.ca/carpalx
Конрад Моравский
1
Иногда предельные выгоды альтернативного подхода будут достаточно велики, чтобы оправдать затраты на его принятие; в противном случае мы все еще будем программировать на ассемблере и фортране. Этот ответ на самом деле не отвечает на первоначальный вопрос о том, есть ли на самом деле предельные выгоды. В примере Дворжака, безусловно, есть и это было доказано, но они не являются достаточно большими преимуществами, чтобы оправдать изучение Дворжака.
Джереми
@ Джереми «этот ответ на самом деле не отвечает на первоначальный вопрос о том, есть ли на самом деле предельные выгоды» - ФП прямо не спрашивал о результатах таких исследований, он спрашивал, пытался ли кто-либо проводить такие исследования, который является более открытым вопросом. Я ответил, указав несколько логических причин того, почему это будет технически сложно, и почему любые результаты такого исследования, вероятно, будут значительно загрязнены статистическим шумом. Поэтому, если мой ответ был сочтен бесполезным по тем причинам, которые вы дали, я думаю, что меня осудили несправедливо.
Конрад Моравский
1
@ Джереми, суть этих затрат на усыновление заключается в том, что люди работают лучше с плохим инструментом, если у них было больше практики с ним. И это именно то, что обнаружилось бы в любом исследовании, пытающемся исследовать, насколько хорошо его предметы справляются с различными стилями кодирования. Шум, вызванный их предыдущим знакомством / незнакомостью со стилями кодирования, которые вы могли бы использовать, уменьшит влияние любых врожденных качеств этих стилей. Если вы не выровняли игровую площадку, взяв на себя полных начинающих. Но это создает практическую трудность, как я указывал в последнем абзаце моего ответа.
Конрад Моравский
4

Ответ окончательный НЕТ! Являются ли `break` и` continue` методами программирования? это подмножество этого вопроса, поэтому я собираюсь начать с едва измененного ответа на этот вопрос ...

Вы можете [пере] писать программы без операторов прерывания (или возврата из середины циклов, которые делают то же самое). Но при этом вам, возможно, придется ввести дополнительные переменные и / или дублирование кода, которые обычно затрудняют понимание программы. По этой причине Pascal (язык программирования конца 1960-х) был очень плох, особенно для начинающих программистов.

Есть результат в области компьютерных наук, который называется иерархией управляющих структур Косараю, которая восходит к 1973 году и упоминается в (более) известной статье Кнута « Структурированное программирование с утверждениями 1974 года». То, что С. Рао Косараю доказал в 1973 году, - это то, что это не так. можно переписать все программы, имеющие многоуровневые разрывы глубины n, в программы с глубиной разрывов меньше n без введения дополнительных переменных. Но допустим, что это чисто теоретический результат. (Просто добавьте несколько дополнительных переменных ?! Конечно, вы можете сделать это, чтобы чувствовать себя внутри группы с пользователями 3K + на stackexchange ...)

Что гораздо более важно с точки зрения разработки программного обеспечения, это более поздняя статья Эрика С. Робертса 1995 года под названием « Выход из цикла и структурированное программирование: возобновление дебатов» (doi: 10.1145 / 199688.199815). Робертс суммирует несколько эмпирических исследований, проведенных другими до него. Например, когда группу студентов типа CS101 попросили написать код для функции, реализующей последовательный поиск в массиве, автор исследования сказал следующее о тех студентах, которые использовали разрыв / возврат для выхода из последовательного поиска. цикл поиска сразу, когда элемент был найден:

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

Робертс также говорит, что:

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

Да, вы можете быть более опытным, чем учащиеся CS101, но без использования оператора break (или, что эквивалентно, возврата / перехода из середины цикла), в конце концов вы напишите код, который, хотя номинально хорошо структурирован, достаточно сложен с точки зрения дополнительной логики Переменные и дублирование кода, что кто-то, вероятно, вы сами, добавите в него логические ошибки, пытаясь следовать некоторой устаревшей идее «правильного» стиля кодирования.

И здесь есть еще одна большая проблема, кроме операторов типа return / break-type, так что этот вопрос немного шире, чем вопрос о разрывах. Механизмы обработки исключений также нарушают парадигму единой точки выхода согласно некоторым

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

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

шипение
источник
Я не отрицал это, но на ваше «Но при этом вам, возможно, придется вводить дополнительные переменные и / или дублирование кода, которые обычно затрудняют понимание программы». точка, это субъективное утверждение. Я согласен, что добавление переменной или дублирование кода затрудняет понимание, но, возможно, добавление goto также усложняет понимание, плюс, возможно, ущерб, нанесенный дублированием, может быть уменьшен путем выделения дублированного кода в функцию (хотя IMO перемещается сложность в графе вызовов не устраняет ее автоматически).
Steve314
Я понял вашу точку зрения о газете 1995 года только после этого последнего комментария и решил высказаться - интересный момент. Я думаю, что ваш отрицательный голос может быть больше, потому что ваш пост длинный и начинается с субъективной точки зрения, так что, вероятно, нижний голос не прочитал все (так же, как я, на первых порах). По сути, это хорошая идея, чтобы представить вашу реальную точку зрения рано.
Steve314
В любом случае, я думаю, что многие люди думают об исключениях как об альтернативных альтернативных точках выхода - потому что они предназначены для случаев ошибок (вроде), которые они на самом деле не учитываются. Я понимаю, что это немного чувствительно к языковой культуре. В некоторых языках «исключение» - это больше, чем название - исключительный случай успеха действителен (и IIRC Страуструп сказал нечто подобное о C ++, поднимая философский вопрос о том, является ли ошибка ошибкой, если она обрабатывается). Некоторые даже говорят, что исключения - это просто еще один поток управления, который можно использовать всякий раз, когда он дает необходимый поток управления.
Steve314
1
@ Steve314 " плюс, возможно, ущерб, нанесенный дублированием, можно смягчить, выделив дублирующийся код в функцию " Вынесение из строки и из непосредственного обзора части логики функции, части, которая не имеет смысла изолированной. Это усложняет понимание логики функции.
любопытный парень
1
@curiousguy - да, это правда, и, вероятно, это часть моего намерения «переместить сложность в граф вызовов». Моя религия заключается в том, что каждый ваш выбор - это компромисс, поэтому знайте обо всех вероятных вариантах, их преимуществах и недостатках, и важно знать общие меры по снижению риска, но будьте осторожны, если лекарство хуже болезни. За исключением, конечно, этой части компромисса является то, сколько времени вы тратите (или тратите) на суету о вещах.
Steve314
1

http://dl.acm.org/citation.cfm?id=1241526

http://www.springerlink.com/content/n82qpt83n8735l7t/

http://ieeexplore.ieee.org/xpl/freeabs_all.jsp?arnumber=661092

[На ваши вопросы, кажется, отвечает одно слово «да». Мне, однако, сказали, что предоставление коротких ответов является «пренебрежительным» вопросом. Если вы считаете, что я отказался от ответа, пометьте ответ, чтобы модератор мог его удалить.]

С. Лотт
источник
1
@ luis.espinal: к какому концу? Какую информацию будет содержать текст? Вопрос немного бродит вокруг. Какая часть вопроса должна быть решена с помощью какого-либо текста?
S.Lott
1
В качестве стиля и, возможно, для предоставления дополнительной информации, которую могут предоставить рефераты ссылок (учитывая, что мы не знаем, является ли OP платным членом ACM / IEEE / Springer Verlag с доступом к полным статьям и найти ответы на них). его вопросы.) Например, реферат статьи ACM не упоминает о стиле кодирования. В большинстве случаев речь идет о подтверждении теоремы о структурированной программе (которая сама по себе не говорит о проблеме единичного или множественного возврата). Таким образом, вы могли бы объяснить, почему эта ссылка актуальна.
luis.espinal
1
Третья статья (к счастью, у меня есть доступ к IEEE Xplore), насколько я могу судить, не связана с тем, что спрашивает ОП. Заметьте, это замечательная статья, которую я печатаю для более подробного чтения позже. Поэтому, возможно, вы могли бы также объяснить, как эта статья помогает ОП ответить на его вопрос. В целом, кажется, вы просто бросили кучу ссылок вместе. Это не манера быть пренебрежительным (если только это не было вашим намерением), но, опять же, я не понимаю, как это помогло ФП. И именно поэтому плакат должен добавить текст по его ссылкам. Итак, теперь вы знаете, почему я это сказал;)
luis.espinal
1
из уст ОП Is a coding style principle - e.g. the single-exit principle - really a good thing?- это дает контекст его вопросу о стилях кодирования. Кроме того, стиль кодирования не совпадает с методологией программирования, в частности, методы проектирования высокого уровня, которые находятся в центре внимания статьи IEEE (ясно заявленной авторами.) Вот почему я говорю «нет» - области видимости совершенно разные.
luis.espinal
1
Я подозреваю, откуда приходит ОП. Он четко указывает на стили кодирования (а не методологии) и, в частности, один или несколько возвратов. Я должен был справиться с этим пару раз с хорошо написанным, по сути самоочевидным кодом, использующим несколько операторов return, переписываемых в более замысловатые версии с использованием single-return (в частности, в больших организациях с большим количеством бюрократизма) * в виде за «процесс». И возникает вопрос (и проблемы с доказательствами) обоснованности, удобства использования и экономической эффективности таких произвольных мандатов. Люди, которые навязывают такие мандаты, все еще живут в 60-х годах: /
luis.espinal
1

Это принцип стиля кодирования - например, принцип единого выхода

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

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

Что касается остальных моих ответов, все относительно (что не в программном обеспечении?):

  • действительно хорошая вещь?

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

Всегда или просто иногда?

Большую часть времени.

Насколько это действительно важно?

Зависит.

Читаемый код против нечитаемого кода. Увеличенная сложность (которую мы должны знать, теперь увеличивает вероятность появления ошибок) по сравнению с более простой сложностью (и, следовательно, меньшей вероятностью ошибок). Языки, компиляторы которых не добавляют неявный возврат (скажем, Pascal, Java или C #) и те, которые по умолчанию int (C и C ++).

В конце концов, это навык, отточенный в человеко-часах за клавиатурой. Иногда нормально иметь несколько операторов return, как здесь (в некотором псевдокоде Pascal'esque):

function foo() : someType
  begin
  if( test1 == true )
  then
    return x;
  end
  doSomethignElseThatShouldnHappenIfTest1IsTrue();
  return somethingElse();
end;

Цель ясна, а алгоритм достаточно мал и не сложен, так что он не гарантирует создание переменной 'flag', которая содержит возможное возвращаемое значение, используемое в одной точке возврата. Алгоритм может быть ошибочным, но его структура достаточно проста, поэтому усилия по обнаружению ошибки (скорее всего) незначительны.

Иногда это не так (здесь используется C-подобный псевдокод):

switch(someVal)
{
case v1 : return x1;
case v2 : return x2:
case v3 : doSomething(); // fall-through
case v4: // fall-through
case v5: // fall-through
case v6: return someXthingie;
...
...
default:
   doSomething(); // no return statement yet
}

Здесь алгоритм не имеет простой структуры, и оператор switch (в стиле C) допускает переходные этапы, которые могут выполняться или не выполняться преднамеренно как часть алгоритма.

Возможно, алгоритм правильный, но плохо написан.

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

Может быть, это неправильно.

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

Предполагая, что фрагмент кода считается правильным:

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

  2. Один оператор возврата повышает удобочитаемость и простоту такого фрагмента кода, если возвращаемое значение вычисляется либо во время выполнения алгоритма, либо если этапы алгоритма, ответственные за его вычисление, могут быть сгруппированы в одном месте в структуре алгоритма. ,

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

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

Это тесно связано со сложностью рассматриваемого фрагмента кода. А это, в свою очередь, связано с мерами цикломатической сложности и сложности Холстеда. Из этого можно наблюдать следующее:

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

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

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

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

luis.espinal
источник
1
Тип возвращаемого значения в C ++ не по умолчанию равен int: тип возвращаемого значения по умолчанию отсутствует, поэтому его необходимо указывать во всех случаях.
Sjoerd
Прежде чем я написал этот вопрос - programmers.stackexchange.com/questions/58237/… . По сути, я защищаю понимание принципа, но не строго следую ему - если все точки выхода очевидны, я счастлив. Моя точка зрения здесь - то, что я упоминаю принцип в качестве примера, не означает, что я защищаю этот принцип и, конечно, не в его строгой форме. Однако мое субъективное мнение таково - может быть, есть более веский аргумент для моей точки зрения, или, может быть, есть веский аргумент, что я ошибаюсь.
Steve314
Что такое «по умолчанию для int» о?
любопытный парень
Я хочу сказать, и я должен был это квалифицировать, что большинство компиляторов просто «запихивают» значение регистра накопителя в качестве возвращаемого значения, если случается, что код имеет ветвь выполнения без явного возвращаемого значения. По сути это означает возвращение результата последней арифметической операции (какой бы мусор это ни был) в виде int. И это, безусловно, будет мусором (и, следовательно, неопределенным поведением) независимо от того, что функция намеревалась делать в первую очередь. C и C ++ могут предупредить вас, но компиляция позволит вам скомпилировать, если вы не используете -Werror или что-то подобное.
luis.espinal