Посібник з кодування: Методи не повинні містити більше 7 заяв?


78

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

AV1500

Методи не повинні перевищувати 7 тверджень Метод, який вимагає більше 7 тверджень, робить занадто багато або має занадто багато обов'язків. Він також вимагає від людського розуму проаналізувати точні твердження, щоб зрозуміти, що робить код. Розбийте його на кілька маленьких та зосереджених методів із самостійно пояснюючими іменами.

Чи дотримуєтесь ви більшості з цього правила? Навіть якщо від створення нового методу мало що врятувати (окрім того, ваш код все-таки сухий ), окрім значного збільшення читабельності? А чи все ще ваше число дорівнює 7? Я би схилявся більше до 10.

Я не кажу, що я порушую це правило повсюдно - навпаки, мої методи на 95% малі та цілеспрямовані, але кажу, що ви ніколи не повинні порушувати це правило, насправді мене підірвало.

Мені дуже хочеться знати, що всі думають про те, що НІКОЛИ не порушує це правило (це "1" у стандарті кодування - тобто НІКОЛИ цього не робити). Але я думаю, у вас виникнуть проблеми з пошуком кодової бази, яка цього не робить.


48
Чи зараховують вони також caseтвердження в синглі switch? У будь-якому випадку, це не що інше, як ідіотська, марна вимога. Ті, хто це написав, нічого не знають про програмування.
SK-логіка

86
Єдиним правилом, яке повинно бути "1" для стандарту кодування, повинно бути правило "ти візьмеш усі рекомендації щодо кодування із зерном солі".
Майк Накіс

6
@ SK-логіка 1027 теж не погана - це повинен бути весело написання коду, який повинен обробляти відсутні дані, якщо ви повинні вважати порожній рядок рівним нулю.
Quant_dev

25
Читаючи це керівництво, я очікував би побачити базу коду, повну: void DoSomething () {DoSomethingFirstSevenLines (); DoSomethingSecondSevenLines (); DoSomethingThirdSevenLines (); тощо; }
буксири

12
Спробуйте відобразити більшу частину .NET Framework і подивіться, скільки методів має менше 7 заяв ...
Девід Бойк,

Відповіді:


195

Це для мене "стандартний запах". Щоразу, коли я бачу стандарти кодування з певними обмеженнями в них, я хвилююся. Ви майже завжди натрапляєте на випадок, коли метод повинен бути більшим, ніж дозволяє стандартний (будь то довжина / кількість рядків, кількість змінних, кількість точок виходу тощо). Стандарти повинні бути більше схожими на керівні принципи та забезпечувати достатню свободу для здійснення належних оцінок. Не зрозумійте мене неправильно, добре мати стандарти, але вони не повинні ставати "мікроуправлінням через проксі".


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, що ви не завжди більш продуктивні при використанні коротких методів. Якщо ви поділитесь, коли це не має сенсу, ви додасте складність коду без користі.

Як завжди з рекомендаціями, добре пам’ятати, чому існують обмеження, щоб ви могли дізнатися, коли вони не застосовуються. У більшості коду методи будуть короткими, або у вас, ймовірно, є проблеми з DRY або розділенням проблем . Але якщо це не так, то добре.


1
Чудова відповідь. Останні два рядки особливо ведуть додому точку.
Xonatron

6
Я думаю, що важливим правилом є перевірка того, чи є підметоди ортогональними. Якщо вони незалежні, їх можна назвати в будь-якому порядку і поважати клас інваріантних, тоді краще тримати їх окремо. Якщо методи щільно поєднані, інваріанти класового розбиття та / або потребують виклику в певному порядку, то, можливо, краще їх тримати разом.
хугомг

4
Код повний хороших речей. Кожен програміст повинен з'їдати шматочок його в обід щодня.
deadalnix

29

Це слід розглядати як правило.

Такі речі, як "Не більше 80 (100 120) стовпців тексту", "одна точка виходу на метод", "не більше 2 рівнів вкладеності", - це те, що я б назвав пороговими показниками для показників запаху коду. Якщо ви порушуєте їх при нагоді, це не обов'язково означає, що код поганий. Якщо ви виявите, що ви постійно їх порушуєте, то в коді щось пахне, і ви, можливо, захочете зробити паузу і переосмислити свій підхід.

Для мене найважливішими критеріями є: "Чи зрозумілий цей код?", "Чи повторюється він?", "Чи розбитий він у логічних місцях?", "Чи вільно з'єднаний?" Є ще кілька, але я думаю, що основну думку можна підсумувати, пам’ятаючи поради Дональда Кнута: «Програми призначені для читання людьми і лише випадково, щоб комп'ютери виконувались».


7
Обмеження стовпців "80/100/120" - це можливість ми можемо читати код. Більшість терміналів відкриваються в 80 стовпцях, і менше зусиль змусити автора перетворитись на 80 стовпців, ніж це зробити так, щоб кожен читач міняв розмір свого терміналу щоразу, коли він хотів прочитати код. На відміну від інших меж, межа N-стовпців не впливає на семантику коду, це суто стилістичне правило; у тій же категорії, що і "використовувати 4-пробільні вкладки" або "поставити дужки відкриття для функцій у власному рядку".
Дітріх Епп

4
Звичайно, це естетичний аспект більше, ніж семантичний аспект. Однак саме тут стосується мого останнього речення. Не рідкість можна знайти твердження Java, які перевищують правило 80 стовпців, не мають місця «приємного» для розділення рядка. Це впливає на читабельність та розуміння коду. Це також може вказувати на порушення Закону про Деметер
сегмент

7
У 21 столітті мій IDE має цю особливість під назвою "динамічне обгортання слів".
György Andrasek

9
@ GyörgyAndrasek: Але кожен не завжди використовує ваш IDE: ми дивимось код у GitHub, у терміналах з less, в vimта emacs; а автоматичне обгортання в кращому випадку здається випадковим. Стандарти кодування не на вашу користь, а на користь людей, які працюють у командах.
Дітріх Епп

2
@DietrichEpp Особисто мені важко читати код, який завжди обговорюється в колонці 80. Нещодавно мені довелося працювати над проектом Java, де використовувався стандартний формат Eclipse. І всередині методу було дуже важко відслідковувати рядки, які перейшли дві або навіть три лінії (я теж звинувачую в цьому інші параметри форматера). Підсумок полягає в тому, що я думаю, що 80 трохи застарів. Я особисто використовую ліміт 120, налаштовуйте мої редактори на виконання цього закону, мати консоль шириною 120 стовпців, а Github насправді відображає 125 стовпців. І я думаю, що це набагато зручніше читати.
ткнути

18

Я ніколи не витрачав часу, щоб насправді рахувати кількість висловлювань у своїх методах, але я намагаюся писати методи, які чітко виконують єдину, чітку мету. Поки ваш код чистий, читабельний і дотримується принципів DRY та єдиної відповідальності , ви, ймовірно, зробили свою роботу. Я думаю, що довільне розщеплення методу, окрім того, щоб застосувати ліміт із семи висловлювань, може зробити ваш код менш читабельним / доступним.


1
+1 для читабельності. Це навіть не має значення, якщо метод довгий 20, 30 або навіть 50 рядків. Якщо ваші цілі - DRY і SRP, не має значення, якщо методи здаються трохи довгими ... хоча найчастіше ви виявите, що чим читабельніше ви намагаєтеся зробити свій код, тим коротші ваші методи природно стане.
S.Robins

11

Це приблизно

Такі правила не слід сприймати занадто буквально. Вони могли сказати, що " методи повинні бути короткими ". Однак деякі люди трактували б це як "менше 1 сторінки", а інші - як "максимум 2 рядки".

Я б припустив, що вони сказали "7 тверджень", щоб дати вам приблизне уявлення (хоча, я думаю, вони повинні були сказати "про 7"). Якщо вам потрібно 9 разів, не потійте. Але якщо ви досягнете 20, ви будете знати, що ви не в правильному положенні для цього правила.


Це робить це досить явним наближенням. У розділі "Вказівки" позначено, що ви ніколи не повинні пропускати та застосовуватись до всіх ситуацій ".
Брайан

1
@brian - можливо, письменники-путівники випадково пропустили слово "грубо", а може, вони були божевільними диктаторами. Моя думка полягає в тому, що ОП повинна сприймати це як номер-рейтинг. Будь-яке правило, яке компілятор чи інтерпретатор не виконує, є лише пропозицією.
Натан Лонг

"Будь-яке правило, яке компілятор чи інтерпретатор не виконує, є лише пропозицією" Не обов'язково правдою. Я не переглянув його власні правила перерозподілу або fxcop, і якщо вони насправді застосовують саме це правило, але є компанії, які змушують вас підтвердити всі правила стилю. Я зустрів людей, компанія яких змушує їх писати код, який може пройти суворі інструкції Microsoft щодо кодування.
Брайан

Я погоджуюсь, що вона приблизна, і її слід брати з зерном солі, оскільки абзац кодового стандарту піднести довільне число неминуче спричинить плутанину. У більшості випадків стандарти будуть виведені з контексту, і "люди" будуть дотримуватися цього довільного наближення як догми.
Спойк

10

7 - це абсолютно довільне число, яке абсолютно не має значення.

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

Хоча це досить екстремальний випадок, справа в тому, що вам потрібно зберегти код DRY та низьку цикломатичну складність. Це важливіше, ніж кількість рядків у методі.

Візьмемо, наприклад, вимикач / випадок. Якщо у вас більше 7 можливих значень, вам потрібно розбити оцінку на кілька методів? Звичайно ні, це було б нерозумно.

Штучне розбиття коду на більшу кількість методів лише для того, щоб число висловлювань не перевищувало 7, тільки погіршує ваш код.

Посібник повинен бути: Кожен метод повинен робити 1 річ і зберігати свій код ДУХОМ.


1
+1: Довільні обмеження корисні лише довільно. Метод повинен містити одну цілісну операцію на одному рівні абстракції. Порушення такої атомної одиниці робить код складнішим, ускладнює розуміння коду.
Аллон Гуралнек

СУХА завищена. Досить часто це означає щільно з'єднати два аспекти чогось, що не повинно бути настільки щільно з'єднаним.
Бред Томас

4

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


8
Ви не можете абстрагувати код котла на свій метод?
erjiang

Після публікації я помітив, що це C # не Java, але я думаю про подібні речі. stackoverflow.com/questions/321418 / ...
Jaydee

@erjang: можна. На Java це дуже некрасиво, оскільки потрібно запитати кожен запит в анонімний клас, але все-таки варто це зробити. Не так потворно в C #, і, безумовно, варто це зробити.
кевін клайн

Особисто я вважаю, що декілька додаткових рядків коду рядкового рядка є більш зрозумілими. Але, мабуть, це тільки я.
Джейді

@Jaydee Пов’язане запитання показує поширену, але дивну практику: складання винятку та ведення журналу. На наступному рівні ви можете зробити те саме ... таким чином єдиний виняток з’являється кілька разів у журналі. Було б краще оголосити метод кидання, і ви зберегли 3 рядки. Написати допоміжний метод закриття як psі rsі зберегти ще один. Або напишіть метод, List<Row> readDb(String sql, Object... args)який виконує всю роботу (працює лише для набору результатів, що вміщуються в пам'яті, але отримання занадто багато даних зазвичай означає, що роботу в будь-якому випадку слід виконувати в БД).
maaartinus

4

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

Уявіть метод, foo()який робить 7 речей. Ви можете стверджувати, що 7 речей - це занадто багато. Можливо, у багатьох випадках ви праві. З іншого боку, ці 7 речей можуть бути тісно пов'язані; логіка може плавно протікати і читатись як проза; у вас можуть бути проблеми з розумінням цього, коли вам це потрібно. Що може закінчитися набагато гірше - це розподілити ці 7 речей у великому дереві-джерелі, так що якщо ви подивитесь, foo()ви не маєте уявлення, що це робить, не дивлячись у 7 різних місцях.

Багато людей отримують подібні правила в голову, і результат - це те, що я вважаю спагетті OO. Все акуратно, укладено у свій власний маленький метод чи клас, атомічні мікро-транзакції відбуваються в кожному місці. Але прийти до такої бази коду неможливо і знати, що це робить. Ви загубитесь.


4

це не погана настанова. Я ніколи не пошкодував про розбиття методів та класів (я ніколи не виявив, що їх було занадто багато), доки вони досить групуються та взаємопов’язані.

Хитрість полягає в тому, щоб НЕ розділити його вертикально (Просто відключіть метод в одній точці і запустіть новий). Трюк, як і при тестуванні одиниць, полягає в тому, щоб з самого початку пам’ятати про таке правило, щоб ви насправді розробляли краще, передаючи 3 або 4 заяви середнього методу на інший метод, оскільки наявність виклику методу описує те, що ви робите краще, ніж ці 3 або 4 твердження посередині вашого коду.

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

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

Підсумок? Якщо порівнювати дизайнерський запах "Використовувати менше 7 тверджень" із запахом коду "Я використав більше 7 заяв", я скоріше усунув би запах коду.


4

Оце Так! Я ніколи не сподівався зустріти таку інтенсивну дискусію щодо простого керівництва, який приблизно говорить про те, що ваших методів має бути дуже мало. Оскільки вони завжди розробники, які хочуть, щоб їхні вказівки були явними, я вибираю 7, тому що це звучало як хороший поріг.

Деякі з вас вже цитували відмову на початку документа. Але для того, щоб було зрозуміло, цей документ являє собою сукупність вказівок, які намагаються допомогти вам написати кращий код та створити кращі системи. Я ніколи не заявляв, що будь-що має бути правилом, навіть якщо вказівки позначені як рівень 1. Ці рівні - це просто колективна думка багатьох людей, які деякий час користуються цим документом.

Я також ніколи не претендував на експерт. Але я займаюся цією професією вже 15 років, маючи близько 4 років досвіду C ++ та 11 років досвіду роботи на C #. Спочатку він базувався на промисловій силі C ++, але я відтоді вдосконалював це за участю громади.

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


3
Добра з того, що ви прислухаєтесь, і я думаю, що ви зробите розумний аргумент. Однак, я не згоден з вашим обґрунтуванням: "вони завжди розробники, які хочуть, щоб їхні вказівки були чіткими": ви не завжди можете задовольнити ідіотів, і не варто намагатися. Робити чіткі вказівки добре, якщо це не робить їх неправильними: тепер це вже не правило, це довільне правило. Введення довільних цифр, як ви були свідками, є мертвим певним способом збиття, і виправданим.
Конрад Рудольф

3

По-перше: це настанова, а не правило. Це називається настановою, тому будь ласка, ставитесь до нього як до такого. Це означає, що також потрібно (як завжди) ваше власне судження

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


2

Я згоден із твердженням, що перебуває над мною. Це просто настанова, і в ідеальному світі все було б предметами, повторно використаними в кожній програмі, і світ був би прекрасним місцем. Це не завжди відповідає дійсності, а іноді це може призвести до великої кількості непотрібних та марних ресурсів. Ви також повинні це мати на увазі.


6
"Я погоджуюся з твердженням вище" Уникайте подібних пропозицій на сайтах stackexchange. Пам'ятайте, що наказ
надсилаються

Я знаю, я не думав про це, поки не пізно. Але я все одно поставлю вам +1 за те, що я вказав на моє пердене.
Falcon165o

2

Дуже нерозумно, коли ви додаєте в суміш обробку виключень.

Після "спробувати, зловити, нарешті", вам залишається чотири заяви на метод!

Також розглянемо метод "validateForm" для форми поля 20, навіть якщо ви обробляєте всі індивідуальні перевірки окремими методами, ви все ще маєте 20 методів перевірки поля для виклику. Відповідно до цих вказівок, ви отримаєте безглуздий розкол, наприклад "validateTopOfScreen", "validateMiddleOfScreen" і "validateBottomOfScreen".


Я думаю, що цілком безпечно сказати, що try/ catch/ finallyне є твердженнями в C #. Див. Ecma-334 § 12.3.3.15 та прилеглі розділи. (скорочено) " випробування-нарешті формуляру : спробуйте спробувати блок- лов (...) улов-блок-н нарешті- нарешті-блокувати "
CVn,

Ну, як я вже говорив, це рішення, яке вам доведеться приймати знову і знову. Однак ваш конкретний приклад може бути прикладом неправильного виконання об'єктно-орієнтованого дизайну. Ви можете поділити екран на кілька елементів керування, які виконують перевірку самостійно.
Денніс Домен

@Dennis - правда, занадто довго займався формами HTML!
Джеймс Андерсон

@James І саме для цього призначений цей конкретний настанов. Намагаючись змусити вас думати про альтернативні, потенційно кращі рішення.
Денніс Домен

2

Питання полягає в співвідношенні "правил" з "настановами". Правила мають бути дотримані - вказівки - це поради, які повинні змусити вас розглянути те, що ви робите, і якщо це дійсно можна зробити краще.

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

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


0

Я погоджуюся з коментарями вище. 7 для мене є довільним і може бути корисним для деяких мов, де використовується рубін, але для таких мов, як C #, Java, C ++, я сумніваюся у цій умові "7 рядків". Дозвольте навести приклад. У моїй програмі 22 текстових поля, і я перевіряю серверну сторону. Метод називається validateInput (), і моїм уподобанням є перевірка всіх полів в одному методі, за винятком випадків, коли я перевірив щось складне, як checkEmailFormat (). Таким чином, мій метод validateInput має 108 рядків із випадковими викликами до складної перевірки.

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

Що я дійсно роблю, щоб зробити свій код зрозумілим - це чисті коментарі, які в основному говорять про те, що ці 4 рядки роблять колишніми -

validateInput (користувач UserObj) {

// Підтвердити ім’я ....... ......

// підтвердити прізвище ...... ......

// перевірити електронну пошту ..... // занадто складна для перевірки формату електронної пошти регулярна перевірка виразівEmailFormat (); .... .....

і так далі.. }


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 if і продовжує і повертає вплетені в нього. Це лайно. Якби програміст тільки був змушений думати про те, що він робить ...

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.