Які речі миттєво дзвонять дзвіночками тривоги при перегляді коду? [зачинено]


98

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

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

Почну з легкого:

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


61
Іноді я стикаюся з людьми, які коментують код, перевіряють і кажуть: "Мені це може знадобитися знову в майбутньому - якщо я його зараз видалю, я втрачу його". Мені доводиться протистояти "Ер, ... але для цього потрібен контроль джерела".
talonx

6
Іноді, особливо під час оптимізації, зручно залишати старий код як коментар, тож ви знаєте, що замінює неясний оптимізований код. Подумайте залишити 3-рядковий своп з тимп. На місці, замінивши його однорядковим подвійним свопом. (Хоча, я не бачу необхідності використовувати один рядок - EVER, якщо тільки розмір програми не має критичного значення.)
Кріс Кадмор,

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

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

24
Хм. printf("%c", 7)Зазвичай для мене дзвонить дзвінок тривоги. ;)

Відповіді:


128
/* Fuck this error */

Зазвичай зустрічається всередині нісенітницького try..catchблоку, він, як правило, привертає мою увагу. Так само, як і /* Not sure what this does, but removing it breaks the build */.

Ще кілька речей:

  • Кілька вкладених складних ifвисловлювань
  • Спробуйте блокувати блоки, які використовуються для регулярного визначення логічного потоку
  • Функції з родовими назвами process, data, change, rework,modify
  • Шість-сім різних стилів зміцнення в 100 рядках

Я щойно знайшов:

/* Stupid database */
$conn = null;
while(!$conn) {
    $conn = mysql_connect("localhost", "root", "[pass removed]");
}
/* Finally! */
echo("Connected successfully.");

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


19
Якби я міг підтвердити це 6 разів! Всі хороші приклади. Мені також не подобаються зарозумілі / смішні коментарі (особливо якщо вони включають лаянку) - це може бути дещо цікавим, коли ви їх прочитаєте, але дуже швидко старієте (і, отже, відволікаєте).
FinnNk

5
Мені подобається твій приклад, хоча я б сказав, що в певних контекстах багато разів вкладені, якщо заяви неминучі. З великою кількістю логіки бізнесу, код може бути трохи заплутаним, але якщо бізнес сам заплутаний для початку, спростити код було б менш точно моделювати процес. Як сказав Ейнштейн: "Речі повинні бути максимально простими і не на один біт простішими".
Морган Херлокер

2
@Prof Plum - Який приклад ви можете навести? Зазвичай альтернативою декількох вкладеним if є розбиття його на (безліч) методів. Молодші розробники, як правило, уникають цього як би менш бажаного, ніж якщо; але, як правило, при натисканні вони кажуть "якщо робити це в меншій кількості рядків". Потрібно, щоб хтось впевнений в OOP вступив і нагадував їм, що менше рядків! = Кращий код.
STW

2
@STW Це хороший момент, однак я б сказав, що це залежить від того, наскільки глибоке гніздування. Я, безумовно, погоджуюся, що що-небудь більше, ніж три глибині гнізда, часто потребує реконструкції, тому що воно стане досить волохатим. Однак, цитування страхування є хорошим прикладом, коли багатостороннє вкладення насправді може досить добре моделювати реальний світ. За винятком певних ставок / премій, посібник буквально прочитає щось на кшталт "якщо це майно і якщо він має мінімальну ставку нижче 5,6, і якщо він знаходиться в штаті Північна Корея, і якщо у нього є човен у приміщенні, то робіть таке і таких ». з багатьма іншими варіантами.
Морган Херлокер

4
@josh, якщо "вони" є колегами, то я б задумався над тим, чому ви не сказали "ми" ...

104

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

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


1
+1: Я побачив якийсь код від колеги, який рекламував себе як експерта linux, який написав просту циклічну програму як одну довгу функцію, вся справа знову і знову в основному (). Yikes.
KFro

4
@KFro, це цикл розгортається. Ось що роблять компілятори весь час :) ДУЖЕ ефективний!

3
@Thorbjorn: Іноді вам доведеться трохи допомогти компілятору; зрештою, ти розумна людина, а він просто німий комп'ютер.
yatima2975

3
Ще одна причина, яку я бачив: консультанту заплатили за те, щоб якомога швидше реалізувати цю функцію (тому, звичайно, відсутні і тести, і документація). Копіювати / вставляти швидше, ніж думати про те, як зробити все правильно.
LennyProgrammers

4
Уникнення дублювання коду може бути одержимістю. У такій мові, як C ++, це не завжди так просто, як слід було б визначити різні частини, але все ще має надійний та ефективний код. Іноді, трохи вирізати і вставити - більш практичний варіант. Також може застосовуватися принцип оптимізації - вирізати і вставити можна швидко і просто рішення, яке ви зможете пізніше змінити, якщо потрібно. Ви можете економити головний біль обслуговування для подальшого використання , але ви знаєте напевно , що ви уникнути затримок прямо зараз.
Стів314

74

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

x ^= y ^= x ^= y;

12
Ого, це так набагато читабельніше, ніжswap(x, y);
JBRWilkinson

8
якщо x і y - покажчики, і це призначення відбувається протягом розумного проміжку часу, воно чітко порушує консервативні збирачі сміття, як Boehm GC.
SingleNegationElimination

12
До речі, цей код не визначений у C та C ++ через безліч змін без втручання точки послідовності.
fredoverflow

9
Дивлячись на це, єдине, що спадало на думку, були смайлики:^_^
Дарієн

62
  • 20000 функцій ліній (перебільшення). Будь-яка функція, яка займає більше декількох екранів, потребує повторного факторингу.

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

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


9
Я схильний обмежувати функції лише одним екраном, коли це можливо.
Метт Дітроліо

20
1 екран - це навіть розтяжка. Я починаю відчувати себе брудною після 10-ти рядків.
Брайан Роу

54
Гаразд, я озвучую те, що може бути непопулярною думкою. Я кажу, що це запах коду для написання функцій, які є атомарними, згори донизу процесами, які розбиваються на окремі функції, тому що розробник чіпляється за деякі "функції, повинні бути короткими" вантаж-культизм. Функції слід порушувати по ФУНКЦІОНАЛЬНИМ прямим не лише тому, що вони повинні мати якийсь міфічний "правильний розмір". Тому їх називають ФУНКЦІЯМИ.
Dan Ray

7
@Dan, Функції не повинні бути короткими, щоб бути короткими, але є лише стільки інформації, яку ви можете потримати в голові за один раз. Можливо, у мене маленький мозок, як на мене, ця межа - пара екранів :). Розбиття функцій на кілька функцій, коли вони починають перевіряти цю межу, необхідно, щоб уникнути помилок. З одного боку, він забезпечує інкапсуляцію, так що ви можете думати на більш високому рівні, а з іншого приховує те, що відбувається, тому ускладнює роботу над тим, як функція працює. Я думаю, що розбиття функцій слід робити для сприяння читабельності, а не для досягнення «ідеальної довжини».
Домінік МакДоннелл

6
@Dominic, @ Péter, я думаю, що нас троє насправді говорять те саме. Коли є вагомий привід для факторного коду на меншу функцію, я за це. Те, що я відкидаю, - це стислість заради стислості в дизайні функцій. Ви знаєте, стек викликів, який втричі довший, ніж повинен бути, але принаймні ці функції короткі. Я вважаю за краще налагоджувати високу функцію, яка робить одне добре і чітко, ніж переслідувати шлях виконання через десяток ланцюгових функцій, які викликуються лише з попередньої.
Ден Рей

61
{ Let it Leak, people have good enough computers to cope these days }

Що гірше, що це з комерційної бібліотеки!


32
На цьому не дзвонить дзвінок тривоги. Це практично стукає вас між ніг.
Стівен Еверс

15
Дочка - мета-наркоман. Кого хвилює, принаймні вона не стане ожирінням. :: зітхання ::
Еван Плейс

17
Коли я опиняюся в неприємні періоди, до мене приходить мати buntu. Говорячи слова мудрості, нехай вона просочиться. ДАЙТЕ ЛІК .. МАЙТЕ ЛІК. НЕ МАЄТЬ ЛІК, ой БУДЬ ЛИШЕ. Якщо він просто протікає один раз, це не піааааак. (якщо ви читаєте це далеко, +1). Мені справді потрібно розглянути безкафе.
Tim Post

13
"Коли термін швидко наближається, ЛІКС - це все, що я бачу, десь хтось шепоче:" Пишіть на С ...... eeeeee !!! ""
chiurox

9
Колись було дві ОС. Один просочився і врізався, якщо він пробіг більше 49 днів, інший був ідеальним і працював би назавжди. Один був запущений у 1995 році у величезний фанфайр, і його використовували мільйони людей - інший ніколи не постачався, тому що вони все ще перевіряють, чи не є помилками. Існує різниця між філософією та технікою.
Мартін Бекетт

53

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

//Copy the value of y to temp.
temp = y;
//Copy the value of x to y.
y = x;
//Copy the value of temp to x.
x = temp;

Крім того, коментарі щодо коду, які могли бути усунені, дотримувались деяких основних вказівок:

//Set the age of the user to 13.
a = 13;

15
Є, це називається COBOL :-)
Гай

26
Другий випадок - не найгірший. Найгірше: / * Встановити вік користувача на 13 * / a = 18;
PhiLho

4
@PhiLho - ні, ще гірше, коли /від */зниклого немає, тому весь код до кінця наступного */ігнорується. На щастя, виділення синтаксису робить такі речі рідкісними в наші дні.
Стів314

3
Ще гірше, aдля user_age? Дійсно?
glasnt

2
Я використовував стандартний документ коду у попереднього роботодавця, один розділ якого був відповідним коментарем. Мій улюблений приклад був з MSDN:i = i + 1; //increment i
Майкл Іцо

42

Код, який створює попередження при компілюванні.


1
Є кандидат для додавання параметра компілятора "Усі попередження як помилки" до makefile / проекту.
JBRWilkinson

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

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

13
Я вважаю за краще збивати свій код майже зайвим, (unsigned int)ніж захаращувати свої списки попереджень / помилок доброякісними попередженнями. Я б ненавиджу, щоб список попереджень став сліпою плямою. Це також набагато більше ЛАВАШ пояснити іншим людям , чому ви ігноруєте попередження , чим це пояснити , чому ви робите кидок природно intsдля unsigned ints.
Рей Міясака

Інколи доводиться працювати з API, який видаляє помилки, що б ви не робили. Класичними прикладами є те, коли API визначається з точки зору речей, які порушені дизайном (деякі старі константи ioctl () були такими, а іноді розробники ОС наполягають на тому, щоб використовувати неправильний тип у своїх заголовках) або де вони знецінили щось без залишаючи хорошу заміну (дякую, Apple).
Дональні стипендіати

36

Функції з цифрами в імені замість описових імен , наприклад:

void doSomething()
{
}

void doSomething2()
{
}

Будь ласка, зробіть так, щоб імена функцій щось означали! Якщо doSomething і doSomething2 роблять подібні речі, використовуйте назви функцій, які диференціюють відмінності. Якщо doSomething2 - це вирив функціональності від doSomething, назвіть його для його функціональності.


Так само @Parm для SQL
Дейв

2
+1 - Введіть mshtml- це розбиває мені очі :(
Кайл Розендо

3
Винятком з цього буде код GUI. Наприклад, якщо у форми для електронної пошти було дві адреси; address1 та address2 є більш розумним, ніж адреса та альтернативна адреса. Неправдиві мітки, які є лише статичними, також є розумним винятком.
Еван Плейс

@Evan - досить справедливо, хоча я більше робив відмінність у функціональності.
Wonko the Sane

1
+1 - Я навіть бачив це як метод керування псевдоверсіями.
EZ Hart

36

Чарівні числа чи чарівні струни.

   if (accountBalance>200) { sendInvoice(...); }

   salesPrice *= 0.9;   //apply discount    

   if (invoiceStatus=="Overdue") { reportToCreditAgency(); }

4
Не дуже погано з двома другими, принаймні знижка пояснюється, а "Прострочена" - інтуїтивно зрозуміла. The 200, з іншого боку, ...
Тарка

9
@Slokun - Інтуїтивно зрозумілий не стільки як ремонтопридатність та крихкість. Наприклад, розгляньте, що відбувається, коли сума знижок змінюється і 0,9 жорстко кодується в шести різних місцях. Крім того, використання рядків замість констант / переліків задає проблеми в мовах з рядками, що відрізняються від регістру.
JohnFx

+1 Я просто витратив занадто багато часу на налагодження проблеми, яка виявилася причиною рядка "timeout = 15;" похований у програмі.
Aubreyrhodes

Я думаю, що останній іноді гаразд, залежно від того, звідки ці дані для рахунку-фактури. Якщо це тільки що з’явилося з публічної версії api, яка повертає JSON, щойно розшифрованому, перевірка твердо закодованої струнної константи, ймовірно, добре. Погодьтеся, що "200" і "0,9" - це лише магічні константи, і їх не слід чітко кодувати таким чином. Навіть якщо вони використовуються лише в одному місці, технічне обслуговування легше, якщо ви визначаєте їх у розділі конфігурації окремо, а не інтерпресуєте їх у логічний код. А якщо їх використовувати в декількох місцях, обслуговування стає набагато простішим.
Бен Лі

36
  • Можливо, не найгірше, але чітко показує рівень реалізації:

    if(something == true) 
  • Якщо мова має конструкцію для циклу або ітератора, то використання циклу while також демонструє рівень розуміння мови виконавцями:

    count = 0; 
    while(count < items.size()){
       do stuff
       count ++; 
    }
    
    for(i = 0; i < items.size(); i++){
      do stuff 
    }
    //Sure this is not terrible but use the language the way it was meant to be used.
  • Погане написання / граматика в документації / коментарях їсть у мене майже стільки ж, скільки і сам код. Причиною цього є те, що код був призначений для читання людьми та роботи машин. Ось чому ми використовуємо мови високого рівня, якщо вашій документації важко пройти через неї, я змушую превентивно формувати негативну думку про кодову базу, не дивлячись на неї.


29

Те, що я відразу помічаю, - це частота глибоко вкладених блоків коду (якщо є, поки є тощо). Якщо код часто заглиблюється більш ніж на два або три рівні, це ознака проблеми дизайну / логіки. І якщо він пройде, як 8 гнізд у глибину, то краще, щоб він не був розбитий.


6
Я знаю, що деякі люди дізналися, що кожен метод повинен мати лише одне returnтвердження, але коли він спричиняє 6+ рівнів, якщо / то вкладається, я думаю, що це робить набагато більше шкоди, ніж користі.
Дарієн

28

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

  • Погане або непослідовне форматування
  • Більше двох порожніх рядків поспіль
  • Нестандартні або непослідовні угоди про іменування
  • Повторний код, чим більше дослівних повторів, тим сильніше попередження
  • Те, що має бути простим фрагментом коду, надмірно складне (наприклад, перевірка аргументів, переданих основним, перекрученим способом)

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

Розглядаючи більш досконалий код, це мої інші попередження:

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

З точки зору стилю я, як правило, не люблю бачити:

  • Javadoc коментує, що лише перегукується з кодом

Це лише підказки до поганого коду. Іноді те, що може здатися поганим кодом, насправді не є, оскільки ви не знаєте намірів програміста. Наприклад, може бути вагома причина, що щось здається надмірно складним - можливо, було розглянуто ще одне враження.


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

18
Я не бачу нічого поганого в класах, які просто агрегують дані - тобто, структури. Ось що є об'єктами передачі даних (DTO) і можуть зробити код набагато легшим для читання, ніж скажімо, наприклад, передача методу в 20 параметрах.
Немі

1
Ваш коментар про структури є місцем. Це добре, коли дані перебувають у найзапущенішому вигляді та не зміняться жодним чином. Але у 95% часу у вас повинні бути деякі функції в класі для форматування / роботи з даними. Я просто згадав деякий мій код, який по суті використовує цей зразок і його слід вдосконалити.
НезадоволенняГота

2
+1 для непослідовного стилю та додаткових розривів рядків (я бачив випадкові відступи, відсутність відступів, випадкові та зміни умов імен та інше - і це у виробничому коді!). Якщо ви навіть не можете зайнятися цим правом, то що ще не можна турбувати?
Дін Гардінг

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

25

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


25

Повністю невикористані змінні , особливо коли змінна має ім'я, подібне до імен змінних, які використовуються.


21

Дуже багато людей згадували:

//TODO: [something not implemented]

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

//TODO: [something that is already implemented]

Тодо нікчемні та заплутані, якщо ви ніколи не намагаєтесь їх зняти!


1
Я щойно пройшов вправу, що потрібно скласти звіт про всі TODO у нашому випуску продукту, а також план їх розміщення. Майже половина виявилася застарілою.
AShelly

1
-1 Коментарі TODO використовуються в MS Visual Studio для відстеження частин проекту, які ще потребують роботи. IE, IDE зберігає список, який відстежує TODO, щоб ви могли легко натискати на них і бути приведеними безпосередньо до рядка, на якому існує TODO. Я б швидше бачив TODO розміщені чітко, щоб побачити, яку роботу ще потрібно зробити. Дивіться dotnetperls.com/todo .
Еван Плейс

3
@Evan Plaice: Вау, ви маєте на увазі, що VS IDE розпізнає, коли ви щось реалізували та видаляє //TODOкоментар? Дивовижно!
JBRWilkinson

4
@Prof Plum Чому б просто не створити політику, коли особа, відповідальна за TODO, вводить своє ім’я в коментар. Таким чином, якщо є якісь залишки, це
Еван Плейс

3
Краще плануйте, ніж // TODO використовуйте трекер помилок, ось для чого!
SingleNegationElimination

20

Метод, який вимагає від мене прокрутки вниз, щоб прочитати все це.


14
Хм .. це залежить від того, що реалізується. Це було б нерозумно, коли це відбувається при реалізації деяких складних алгоритмів, оскільки саме так вони визначаються. Звичайно, якщо більшість методів саме так, це червоний прапор.
Біллі ONeal

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

1
Я не погоджуюся з тим, що це правило може збільшити загальну вартість проекту, але я думаю, що це є суб'єктивним, оскільки це буде залежати від розробників. Якщо ви будете дотримуватися загального принципу "розділення проблем", поки розвиваєтесь, то переоцінка буде менш завданням, якби хтось вирішив це зробити. Щось варто врахувати, скільки коштувало б три роки вниз, коли розробники, які не кодували оригінальний проект, намагаються помилку виправити купу методів із 300+ рядками коду? Скільки це коштує?
БредБ

18
Мені більше дратується праворуч прокрутки, ніж прокручування вниз. Пробіл "безкоштовний".
Wonko the Sane

4
Я б краще прокрутити, ніж доведеться пропускати весь файл (або кілька файлів), щоб зрозуміти, що робить код.
TMN

20

Сполучення в назвах методів:

public void addEmployeeAndUpdatePayrate(...) 


public int getSalaryOrHourlyPay(int Employee) ....

Роз'яснення: Причина, в якій задзвонили сигнали тривоги, полягає в тому, що вона вказує на те, що метод, ймовірно, порушує принцип єдиної відповідальності .


Хммм ... якщо назва функції точно визначає, що функція виконує, то я не погоджуюся. Якщо метод робить дві окремі речі, які краще було б відокремити, то я можу погодитися, залежно від контексту.
Wonko the Sane

2
В тім-то й річ. Сполучення означає, що дуже ймовірно, що це робить більше, ніж одне. Що стосується питання, це просто щось, що викликає моє усвідомлення того, що МОЖЕ бути не так.
JohnFx

3
А що робити, якщо вам доведеться додати співробітника та оновити їхню оплату в декількох місцях? Якщо цей метод містить два виклики методу ( addEmployee(); updatePayrate();), я не думаю, що це проблема.
Метт Гранде

13

Очевидно пов'язування вихідного коду GPL'd з комерційною програмою із закритим кодом.

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


6
Хоча ваш пункт відмінний, ваш тон непотрібний.
JBRWilkinson

@JBRWilkinson: Спасибі, ти маєш рацію. Мої вибачення всім.
Боб Мерфі

Я думаю, що ваш заголовок потребує перезапису. Як статичне, так і динамічне посилання на вихідний код GPL'd є порушенням GPL ...
Gavin Coates

Хороші бали. Я переписав всю публікацію. Дякую всім.
Боб Мерфі

9

Мова агностика:

  • TODO: not implemented
  • int function(...) { return -1; } (те саме, що "не реалізовано")
  • Викидання винятку з невиключної причини.
  • Неправильне використання або суперечливе використання 0, -1або nullу виняткових повертаються значення.
  • Твердження без переконливого коментаря, в якому сказано, чому він ніколи не повинен провалюватися.

Специфічна мова (C ++):

  • C ++ Макроси з малих літер.
  • Статичні або глобальні змінні C ++.
  • Неініціалізовані або невикористані змінні.
  • Будь-яке, array newщо, мабуть, не безпечно для RAII.
  • Будь-яке використання масиву чи вказівника, які, мабуть, не є безпечними для меж. Сюди входить printf.
  • Будь-яке використання неініціалізованої частини масиву.

Microsoft C ++:

  • Будь-які імена ідентифікаторів, що стикаються з макросом, уже визначеним будь-яким із файлів заголовка Microsoft SDK.
  • Взагалі, будь-яке використання API Win32 є великим джерелом сигналів тривоги. Завжди відкривайте MSDN і завжди шукайте аргументи / визначення повернення значення, коли виникаєте сумніви. (Відредаговано)

Специфічний для C ++ / OOP:

  • Реалізація (конкретного класу) успадкування, коли батьківський клас має як віртуальний, так і невіртуальний методи, без чіткого явного концептуального розмежування між тим, що повинно / не повинно бути віртуальним.

18
// TODO: Прокоментуйте цю відповідь
johnc

8
Я здогадуюсь, що "мова агностик" означає "C / C ++ / Java" зараз?
Inaimathi

+1 "Викидання винятку з невиключної причини" не могло погодитися більше!
billy.bob

2
@Inaimathi - коментарі TODO, заглушки функцій, зловживання винятками, плутанина нульової / нульової / порожньої семантики та безглузді перевірки розумності притаманні всім імперативним мовам / OOP та певною мірою всім мовам програмування загалом.
Рей Міясака

Я вважаю , що C макроси препроцесора в нижньому регістрі в порядку, але тільки тоді , коли вони оцінюють свої аргументи тільки один раз , і в результаті тільки одного оператора.
Джо Д

8

Дивний стиль відступу.

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


2
або просто знак того, що вони є високо цінуваним індивідуалістичним талантом, який не потрапив у мережу гомогонізованих методів кодування, які жодним чином не пов'язані з "найкращими методами".
Анонімний тип

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

2
Є дещо незвичний стиль (я вважаю, що його називають стилем Утрехта), який я вважаю досить корисним, незважаючи на те, що він надзвичайно незвичний поза Haskell / ML / F #. Прокрутіть униз до "Модулі фігури": learnnyouahaskell.com/making-our-own-types-and-typeclasses . Що в цьому стилі приємно, що вам не потрібно змінювати роздільник на попередньому рядку, щоб додати новий - що я часто забуваю зробити.
Рей Міясака

@ReiMiyasaka На сім років пізніше, але ... Стиль Утрехт мене дуже дратує. Я вважаю, що помилка в специфікації Haskell не нав'язувати інше «правило компонування» у вертикально організованих списках. Таким чином, аналізатор міг би виявити новий запис у списку лише перевіривши відступ, таким чином кожен так чи інакше організовує свої списки.
Райан Райх

@RyanReich Дивно, сім років потому, і мені це все одно подобається. Я згоден, хоча; Незважаючи на всю синтаксичну незграбність і недоліки, F # також дозволяє обмежувати елементи просто новим рядком і відступом (у більшості випадків), що спричиняє охайний код.
Рей Міясака

8

Використання безлічі текстових блоків, а не перерахунків або глобально визначених змінних.

Не добре:

if (itemType == "Student") { ... }

Краще:

private enum itemTypeEnum {
  Student,
  Teacher
}
if (itemType == itemTypeEnum.Student.ToString()) { ... }

Кращий:

private itemTypeEnum itemType;
...
if (itemType == itemTypeEnum.Student) { ... }

Або bestest: Використовуйте поліморфізм.
Lstor

8

Слабо набрані параметри або повернені значення методів.

public DataTable GetEmployees() {...}

public DateTime getHireDate(DataTable EmployeeInfo) {...}

public void FireEmployee(Object EmployeeObjectOrEmployeeID) {...}

2
+1: Я повинен працювати з деякими веб-службами "REST", які повертають усе як таблиці псевдо-HTML, навіть там, де ви передаєте речі, які є явною синтаксичною помилкою. Не дозволено? Вхід повний мотлох? Сервер над ємністю? 200 (плюс повідомлення у жахливому форматі в одному стовпчику, одній рядковій таблиці). AAaaaaaaaargh!
стипендіати Дональ

7
  • Кілька потрійних операторів поєднуються разом, тому замість того, щоб нагадувати if...elseблок, він стає if...else if...[...]...elseблоком
  • Довгі назви змінних без підкреслень або camelCasing. Приклад із якогось коду я витягнув:$lesseeloginaccountservice
  • Сотні рядків коду у файлі, без зауважень, і код дуже неочевидний
  • Надмірно складні ifзаяви. Приклад з коду: на if (!($lessee_obj instanceof Lessee && $lessee_obj != NULL))який я наголосивif ($lessee_obj == null)

7

Запах коду: не дотримання найкращих практик

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

Ось ваш спалах новин для вас: 50% світового населення менше середнього рівня інтелекту. Гаразд, деякі люди мали б точно середній інтелект, але не будемо вибагливі. Крім того, одним із побічних ефектів дурості є те, що ти не можеш розпізнати власну дурість! Речі виглядають не так добре, якщо поєднувати ці твердження.

Які речі миттєво дзвонять дзвіночками тривоги при перегляді коду?

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

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

Одним із прикладів найкращої практики може бути використання фігур з кожним блоком if, навіть якщо він містить лише один рядок:

if (something) {
    // whatever
}

Ви можете не вважати, що це потрібно, але я нещодавно прочитав, що це головне джерело помилок. Завжди використання дужок також обговорювалося в Stack Overflow , і перевірка наявності if-операторів дужок - це також правило в PMD , аналізаторі статичного коду для Java.

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


2
Це може бути педантичним, але я думаю, що має значення, який середній рівень ви обираєте. Як я розумію, 50% світового населення нижче медіанного інтелекту (за визначенням); але інші середні не працюють так само. Для прикладу візьмемо населення (1, 1, 1, 5), яке має середнє арифметичне значення 2.
flamingpenguin

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

@Evan: так, ти маєш рацію. Я додав трохи більше про це, сподіваюся, це допоможе.
Vetle

4
Перевернути це - люди, які по-рабськи дотримуються "найкращих практик", не маючи критичної думки щодо того, чому щось є "найкращою практикою". Ось чому я сильно не люблю термін «найкраща практика», адже для деяких людей це привід перестати думати і слідкувати за стадом. "Тому що це найкраща практика" ніколи не є прийнятною відповіддю на питання "чому ти це робиш?" Якщо ви не можете сформулювати, чому щось є найкращою практикою, то це не найкраща практика, це забобони.
Дан Дайер

Дуже хороший коментар, Ден! Я додав два останні рядки до відповіді.
Vetle

6

Зауваження, які говорять "це тому, що дизайн підсистеми froz повністю захищений".

Це продовжується над цілим абзацом.

Вони пояснюють, що повинен відбутися наступний рефактор.

Але не зробив цього.

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

Якщо керівник вважає, що j.випадково. програміст не може зробити рефакторинг, тоді це повинен зробити керівник.

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

Правдива історія. Це може статися з вами.


6

Чи може хтось придумати приклад, коли код повинен законно посилатися на файл за абсолютним шляхом?


1
Кількість схем XML?
Нік Т

1
Файли конфігурації системи. Як правило, слід встановити ./configure, але навіть десь потрібне значення за замовчуванням десь.
eswald

4
/dev/nullі з друзями все в порядку. Але навіть такі речі /bin/bashє підозрюваними - що робити, якщо ви є якась така система, яка має /usr/bin/bash?
Том Андерсон,

1
Код клієнта веб-служби, згенерований інструментами JAX-WS (як мінімум, JBossWS та Metro), містить жорсткий провідний абсолютний шлях до файлу WSDL (двічі!). Що, мабуть, щось дико недоречне /home/tom/dev/randomhacking/thing.wsdl. Це злочинно шалено , що це поведінка по замовчуванню.
Том Андерсон

4
про /dev/null: У мене є звичка, коли розробляю на Windows, щоб тримати додатки та контури c:\dev. Якимось чином папка nullзавжди автоматично створюється всередині цієї папки. Клянусь, я не маю уявлення, хто це робить. (Один із моїх улюблених помилок / особливостей)
Шон Патрік Флойд

6

Ловля загальних винятків:

try {

 ...

} catch {
}

або

try {

 ...

} catch (Exception ex) {
}

Регіональне використання

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


Вилов загальних винятків є лише проблемою, якщо ви їх повторно скидаєте, не роблячи нічого. Дійсно, для більшості речей достатньо одного винятку. Я схильний використовувати runtime_error.
CashCow

+1 для прикладу "вилучення та викидання". Якщо ви нічого не робите за винятком, не вловлюйте це. Як мінімум, заносіть його. У самому, вкрай міру, в коментарях, пояснюючи, чому добре піймати всі винятки і рухатися далі до цього коду.
EZ Hart

5

Конвенції про іменування класів, які демонструють слабке розуміння абстракції, яку вони намагаються створити. Або це зовсім не визначає абстракцію.

Надзвичайний приклад приходить до тями в класі VB, який я бачив одного разу, під назвою якого Dataбуло 30 000+ рядків ... у першому файлі. Це був частковий клас, розбитий щонайменше на півдесятка інших файлів. Більшість методів були обгортками навколо збережених програм з такими іменами FindXByYWithZ().

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


5

Функції, що повторюють основні функціональні можливості мови. Наприклад, якщо ви коли-небудь бачите метод "getStringLength ()" в JavaScript замість виклику до властивості ".length" рядка, ви знаєте, що у вас виникли проблеми.


5
#define ...
#define ...
#define ...
#define ...
#define ...
#define ...
#define ...
#define ...
#define ...
#define ...
#define ...
#define ...
#define ...
#define ...
#define ...

Звичайно, без будь-якої документації та випадкових вкладених #defineс


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