Руководство по кодированию: методы не должны содержать более 7 операторов?

78

Я просматривал Рекомендации по кодированию AvSol для C #, и я согласен почти со всем, но мне действительно интересно посмотреть, что другие думают об одном конкретном правиле.

AV1500

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

Следуют ли большинство из вас этому правилу? Даже если мало что можно спасти от создания нового метода (ваш код все еще СУХОЙ ), кроме значительного повышения читабельности? И ваш номер по-прежнему всего 7? Я хотел бы больше к 10.

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

Я действительно просто хочу знать, что все думают о том, что НИКОГДА не нарушать это правило (это «1» в стандарте кодирования, то есть НИКОГДА не делать этого) Но я думаю, что у вас будут проблемы с поиском кодовой базы, которая этого не делает.

Брайан
источник
48
Считают ли они caseзаявления в одном switch? В любом случае, это просто идиотское, бесполезное требование. Те, кто написал это, ничего не знают о программировании.
SK-logic
86
Единственное правило, которое должно быть «1» в стандарте кодирования, должно быть правилом «все правила кодирования возьми с солью».
Майк Накис
6
@ SK-logic 1027 тоже неплохо - должно быть весело писать код, который должен обрабатывать пропущенные данные, если вы должны обрабатывать пустую строку как равную пустой строке.
quant_dev
25
При чтении этого руководства я ожидал увидеть кодовую базу, полную: void DoSomething () {DoSomethingFirstSevenLines (); DoSomethingSecondSevenLines (); DoSomethingThirdSevenLines (); и т.д; }
буксиры
12
Попробуйте отразить большую часть .NET Framework и посмотрите, сколько методов имеют менее 7 операторов ...
Дэвид Бойк

Ответы:

195

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

TMN
источник
25
+1 за «микроуправление по доверенности». Я подозреваю, что кто-то читал о правиле «7 плюс или минус 2» ( en.wikipedia.org/wiki/… ) и путал кратковременное хранение фактов с долгосрочным хранением, как, вы знаете, редактор кода.
пушистый
25
Любой разумно продуманный стандарт запрещает магические числа в коде, верно? Можно подумать, что стандарт кодирования тоже будет соответствовать этому стандарту. Число 7 определенно обладает определенно «волшебным» качеством.
Адам Кроссленд
2
Ваш ответ был бы более разумным, если бы заголовок документа не был «Кодирование Guidlinesдля C # 3.0 и 4.0».
Энди,
+1 По-моему, единственная причина, по которой вы должны следовать стандартам кодирования, - это никогда не следовать догматически произвольному числу, а убедиться, что вы не вызываете ненужных проблем слияния в управлении версиями (то есть проблем, связанных с работой в команде). Обычно более короткие файлы и больше компонентов означают меньшую вероятность возникновения проблем при объединении изменений кода.
Спойк
3
Я скачал этот документ и начал просматривать его. В п. 1.6 говорится: «В документе не указывается, что проекты должны соответствовать этим руководящим принципам, а также не говорится, какие руководящие принципы важнее других. Однако мы призываем проекты самим решать, какие руководящие указания важны, какие отклонения будет иметь проект. Укажите, кто является консультантом в случае возникновения сомнений, и какой макет должен использоваться для исходного кода ». Даже если 1 означает «Рекомендации, которые вы никогда не должны пропускать и которые должны применяться ко всем решениям», вы можете изменить их.
chrish
83

Обычно хорошая идея разбить материал на маленькие методы. Но важно разделить вещи там, где это имеет смысл.

Если нет смысла разделять, то не разделяйте. Это часто имеет место для некоторых процедур или кода GUI.

Стив Макконнелл заявил в Code Complete, что вы не всегда более продуктивны при использовании коротких методов. Если вы разделяете, когда это не имеет смысла, вы добавляете сложность в код без какой-либо выгоды.

Как и в случае с руководящими принципами, полезно помнить, почему существуют ограничения, чтобы вы могли узнать, когда они не применяются. В большинстве кода методы будут короткими, или у вас, вероятно, есть проблема с СУХОЙ или разделением проблем . Но если это не так, тогда хорошо.

deadalnix
источник
1
Отличный ответ. Последние две строчки особенно подчеркивают эту точку зрения.
Ксонатрон
6
Я думаю, что важным практическим правилом является проверка того, являются ли субметоды ортогональными. Если они независимы, могут вызываться в любом порядке и уважать инвариант класса, то лучше хранить их отдельно. Если методы тесно связаны, нарушают инварианты классов и / или должны вызываться в определенном порядке, то, возможно, лучше хранить их вместе.
hugomg
4
Полный код полон хороших вещей. Каждый программист должен есть кусок этого на обед каждый день.
Deadalnix
29

Это следует рассматривать как правило.

Такие вещи, как «Не более 80 (100 120) столбцов текста», «одна точка выхода на метод», «Не более 2 уровней вложенности», - это то, что я бы назвал пороговыми значениями для индикаторов запаха кода. Если вы нарушаете их время от времени, это не обязательно означает, что код плохой. Если вы обнаружите, что нарушаете их последовательно, то в коде что-то пахнет, и вы можете сделать паузу и пересмотреть свой подход.

Для меня наиболее важными критериями являются: «Этот код понятен?», «Повторяется ли он?», «Разбивается ли он в логических местах?», «Является ли он слабосвязанным?» Есть еще несколько, но я думаю, что основную идею можно подытожить, вспомнив совет Дональда Кнута: «Программы предназначены для чтения людьми и только для выполнения компьютерами».

seggy
источник
7
Предел столбцов «80/100/120» позволяет читать код. Большинство терминалов открываются в 80 столбцах, и автору требуется меньше 80 столбцов, чтобы заставить каждого читателя изменять размер своего терминала каждый раз, когда он хочет прочитать код. В отличие от других ограничений, ограничение N-столбцов не влияет на семантику кода, это чисто стилистическое правило; в той же категории, что и «использовать вкладки с 4 пробелами» или «поставить открывающие скобки для функций на их собственной строке».
Дитрих Эпп
4
Конечно, это эстетический аспект, а не семантический. Тем не менее, вот где мое последнее предложение применяется. Нередко встречаются операторы Java, которые превышают правило 80 столбцов без «хорошего» места для разбиения строки. Это влияет на читаемость и понимание кода. Это также может указывать на нарушение закона Деметры
seggy
7
В 21-м веке в моей IDE была эта функция, называемая «динамическая перенос слов».
Дьёрдь Андрасек
9
@ GyörgyAndrasek: Но все не всегда используют вашу IDE: мы смотрим на код в GitHub, в терминалах с less, в vimи emacs; и автоматическая упаковка кажется случайным в лучшем случае. Стандарты кодирования не для вас, а для людей, которые работают в команде.
Дитрих Эпп
2
@DietrichEpp Лично мне трудно читать код, который всегда заключен в столбец 80. Недавно мне пришлось работать над проектом Java, в котором использовался стандартный форматтер Eclipse. И внутри метода было очень трудно отслеживать строки, проходящие через две или даже три строки (хотя я и виню в этом другие настройки форматирования). Суть в том, что я думаю, что 80 немного устарела. Я лично использую ограничение в 120, мои редакторы настроены на это, имеют консоль шириной 120 столбцов, а Github фактически отображает 125 столбцов. И я думаю, что так гораздо удобнее читать.
тыкай
18

Я никогда не тратил время на то, чтобы посчитать количество операторов в моих методах, но я стараюсь писать методы, которые четко выполняют единственную, ясную цель. Пока ваш код чистый, читаемый и соответствует принципам СУХОЙ и Единой ответственности , вы, вероятно, сделали свою работу. Я думаю, что произвольное разделение метода на части только для обеспечения ограничения в семь операторов может сделать ваш код менее читаемым / поддерживаемым.

Джошуа Смит
источник
1
+1 для читабельности. Это не должно иметь значения, если метод имеет длину 20, 30 или даже 50 строк. Если DRY и SRP являются вашими целями, не имеет значения, если методы кажутся немного далекими, хотя чаще всего вы обнаружите, что чем более читабельны вы пытаетесь сделать свой код, тем короче ваши методы естественно станет.
С.Робинс
11

Это приблизительно

Такие правила не следует воспринимать слишком буквально. Они могли бы сказать, что « методы должны быть короткими ». Тем не менее, некоторые люди интерпретировали бы это как «менее 1 страницы», а другие как «максимум 2 строки».

Я предположил бы, что они сказали «7 утверждений», чтобы дать вам грубую идею (хотя я думаю, что они должны были сказать «около 7»). Если вам нужно время от времени 9, не переживайте. Но если вы наберете 20, вы поймете, что не подходите для этого правила.

Натан Лонг
источник
Это делает это довольно явным приближением тогда. Он отмечен в разделе «Правила, которые вы никогда не должны пропускать, и должен применяться ко всем ситуациям».
Брайан
1
@brian - может быть, авторы руководств случайно пропустили слово «грубо», или, может быть, они были сумасшедшими диктаторами. Моя точка зрения заключается в том, что ОП должен принять это как приблизительное число. Любое правило, которое не соблюдает компилятор или интерпретатор, является лишь предложением.
Натан Лонг
«Любое правило, которое не соблюдает компилятор или интерпретатор, - это просто предложение». Не обязательно верно. Я не смотрел на его пользовательские правила reharper или fxcop и действительно ли они применяют это конкретное правило, но есть компании, которые заставляют вас проверять все правила стиля. Я встречал людей, чья компания заставляет их писать код, который может соответствовать строгим требованиям Microsoft по кодированию.
Брайан
Я согласен, что это приблизительно, и это должно быть взято за черту соли, если параграф стандарта кода поднимает произвольное число, неизбежно вызовет путаницу. В большинстве случаев стандарты будут вырываться из контекста, и «люди» будут следовать этому произвольному приближению как догма.
Спойк
10

7 - абсолютно произвольное число, абсолютно не имеющее значения.

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

Хотя это довольно экстремальный случай, дело в том, что вам нужно сохранять код СУХИМЫМ и иметь низкую цикломатическую сложность. Это важнее, чем количество строк в методе.

Возьмите, например, оператор switch / case. Если у вас есть более 7 возможных значений, вам нужно разбить оценку на несколько методов? Конечно нет, это было бы глупо.

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

Принцип должен быть следующим: Каждый метод должен делать одну вещь и держать ваш код СУХИМ.

Джим Маккит
источник
1
+1: произвольные ограничения только произвольно полезны. Метод должен содержать одну согласованную операцию на одном уровне абстракции. Нарушение такого атомарного блока усложняет код, усложняя его понимание.
Аллон Гуралнек
СУХОЙ переоценена. Довольно часто это означает тесную связь двух аспектов чего-то, что не должно быть так тесно связано.
Брэд Томас
4

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

Jaydee
источник
8
Вы не можете абстрагировать шаблон кода в его собственный метод?
erjiang
После публикации я заметил, что это C #, а не Java, но я думаю о подобных вещах. stackoverflow.com/questions/321418/…
Джейди
@erjang: вы можете. Это очень уродливо в Java, так как вы должны обернуть каждый запрос в анонимный класс, но все же стоит это сделать. Не так страшно в C # и определенно стоит делать.
Кевин Клайн
Лично я считаю несколько дополнительных строк кода прямой строки более читабельными. Но, возможно, это только я.
Джейди
@Jaydee Связанный вопрос показывает обычную, но странную практику: перенос исключения и ведение журнала. На следующем уровне вы можете сделать то же самое ... таким образом, одно исключение появляется в журнале несколько раз. Было бы лучше объявить метод throwing, и вы сохранили 3 строки. Написать вспомогательный метод закрытия как psи rsи сохранить еще один. Или напишите метод, List<Row> readDb(String sql, Object... args)который выполняет всю работу (работает только для наборов результатов, умещающихся в памяти, но выборка слишком большого количества данных обычно подразумевает, что работа должна быть выполнена в БД в любом случае).
Маартин
4

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

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

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

asveikau
источник
4

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

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

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

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

Резюме? Если сравнить запах проекта «Использовать менее 7 операторов» с запахом кода «Я использовал более 7 операторов», я бы предпочел устранить запах кода.

Билл К
источник
4

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

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

Я также никогда не претендовал на звание эксперта. Но я в этой профессии уже 15 лет, с 4 годами опыта C ++ и 11 годами опыта C #. Первоначально он был основан на Industrial Strength C ++, но с тех пор я дорабатывал его при участии сообщества.

Независимо от того, что я пытался поднять, вы должны продолжать думать самостоятельно. Если вы считаете, что правило из 7 утверждений бесполезно, просто сделайте его длиннее. Черт, я даже нарушаю это правило время от времени. Я просто нарушаю это серьезно и принимаю последствия.

Деннис Доомен
источник
3
Хорошо, что вы вмешиваетесь, и я думаю, что вы делаете разумный аргумент. Тем не менее, я не согласен с вашим обоснованием «они всегда разработчики, которые хотят, чтобы их рекомендации были явными»: вы не всегда можете угодить идиотам, и вы не должны пытаться. Делать руководящие принципы явными хорошо, если это не делает их неправильными: теперь это уже не руководство, а произвольное правило. Как вы уже убедились, введение произвольных чисел - это абсолютно верный способ быть застреленным и оправданным.
Конрад Рудольф
3

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

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

Доминик Кронин
источник
2

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

Falcon165o
источник
6
«Я согласен с приведенным выше утверждением». Избегайте подобных предложений на сайтах стек-обмена. Помните, что порядок размещения ответов не обязательно соответствует порядку их отображения.
luiscubal
Я знаю, я не думал, пока не стало слишком поздно. Но я все равно +1 тебе за то, что ты указал на мой мозг пердеть.
Falcon165o
2

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

После «попробуй, поймай, наконец» у вас останется четыре утверждения на метод!

Также рассмотрите метод validateForm для формы из 20 полей, даже если вы обрабатываете все отдельные проверки в отдельных методах, у вас все еще есть 20 методов проверки полей, которые нужно вызвать. В соответствии с этими рекомендациями вы получите бессмысленное разделение, например «validateTopOfScreen», «validateMiddleOfScreen» и «validateBottomOfScreen».

Джеймс Андерсон
источник
Я думаю, что можно с уверенностью сказать, что try/ catch/ finallyне являются заявлениями в C #. См. Ecma-334 § 12.3.3.15 и окружающие разделы. (сокращенно) « в примерочных кетчупа , наконец , утверждение формы : попробуйте примерочных блок поймать (...) поймать-блок-н , наконец , наконец-блок »
CVn
Ну, как я уже говорил, это решение, которое вы должны принимать снова и снова. Тем не менее, ваш конкретный пример может быть примером неправильного выполнения объектно-ориентированного проектирования. Возможно, вы захотите разделить ваш экран на несколько элементов управления, которые выполняют проверку сами.
Деннис Доомен
@Dennis - правда, слишком долго делал HTML-формы!
Джеймс Андерсон
@James И это то, для чего предназначено это конкретное руководство. Попытка заставить вас думать об альтернативных, потенциально лучших решениях.
Деннис Думен
2

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

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

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

authentictech
источник
0

Я согласен с комментариями выше. 7 для меня является произвольным и может быть полезным в некоторых языках, где ruby, но для таких языков, как C #, Java, C ++, я сомневаюсь в этом соглашении «7 строк». Позвольте привести пример. В моем текущем приложении 22 текстовых поля, и я выполняю проверку на стороне сервера. Метод называется validateInput (), и я предпочитаю проверять все поля в одном методе, если только у меня нет проверки чего-то сложного, такого как checkEmailFormat (). Так что в основном мой код метода validateInput состоит из 108 строк со случайными вызовами сложной проверки.

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

Что я действительно делаю, чтобы сделать мой код понятным, так это предоставить чистые комментарии, которые в основном говорят о том, что эти 4 строки делают ex -

validateInput (пользователь UserObj) {

// Подтвердите имя ....... ......

// подтвердить фамилию ...... ......

// проверка электронной почты ..... // слишком сложный, чтобы проверить формат электронной почты обычное выражение checkEmailFormat (); .... .....

и так далее.. }

Динеш Арора
источник
1
Смотрите также мой ответ на вопрос Джеймса Андерсона. В вашем конкретном случае мне интересно, не нарушает ли этот метод проверки несколько принципов и рекомендаций одновременно.
Деннис Доомен
0

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

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

                Parallel.ForEach(regions, region => {   Console.Write(region.Resorts.Where(x => x.name == "Four Seasons").OrderBy(x => x.RegionId).ThenBy(x => x.ResortId).ThenBy(x => x.name).ToList());   });
Джастин
источник
Опять же, отличный пример слишком многого в одном методе. Почти в каждом контраргументе люди нарушают принцип единой ответственности (в контексте метода).
Деннис Доомен
-1

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

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

dawidg
источник