Безглуздий код у вашому джерелі


34

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

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

Тільки для назви декількох. Мені сказали, що це тому, що програмісти хочуть навмисно зробити код заплутаним, щоб підвищити власну цінність для організації або переконатися у повторному бізнесі у випадку контрактної роботи або підрядних робіт.

Моє запитання. Хтось ще бачив такий код? Яким був ваш висновок, чому саме цей код був там?

Якщо хтось написав подібний код, можете поділитися чому?


4
if (false) {...}блоки чудово підходять для коментування коду! </sarcasm>
dlras2

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

1
@ dlras2 сюжет твіст: #DEFINE false false :)
Сільвіу Бурча

Відповіді:


17

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

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


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

18
@Ali: Ніколи не приписуйте злобі, що краще пояснюється некомпетентністю. Іншими словами - код, ймовірно, перетворився на подібний безлад, тому що ніхто не був достатньо сміливим, щоб витратити час, щоб насправді його подивитися і побачити, що він насправді робить. Це все звучить як купа швидких виправлень, застосованих знову і знову, поки все, що залишилося, не є великим похолом.
quick_now

1
+1 для @quickly_now. Ось зазвичай це і закінчується; всі бояться торкнутися будь-чого, що «працює», боячись зламати його (або, Нехай боже, зайнявшись довше завданням насправді покращити код! Жах!). Тож код гниє і гніється, і нарешті руйнується багато років вниз.
Уейн Моліна

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

73

Я не бачив такого коду, але я бачив код, який виглядає безглуздо або безглуздо з інших причин:

  1. Зворотна сумісність. Ви знайшли набагато кращий спосіб робити речі, але ви повинні зберегти старий (і на сьогоднішній день не дуже корисний) API / функцію, тому що якийсь сторонній модуль там може використовувати цей API / функцію для чогось. Навіть якщо функція не робить нічого корисного, її відсутність може порушити деякий код.

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

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

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

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


22
Я думаю, що №3, органічне зростання пояснює велику частину марного коду, який я бачив на роботі. Але всі 4 з цих причин припускає розумного програміста. Якийсь марний код випливає з того, що хтось не розуміє, що має статися, а що ні, і залишає безліч кодів виключно з-за страху змінити те, що (свого роду) працює.
Брюс Едігер

2
Я бачив №4 у своєму проекті: часто це робиться не навмисно, щоб мати більше влади всередині компанії, швидше є люди, які завжди намагаються створити більш загальне рішення, навіть якщо воно не потрібне. Щодо №2, я багато використовую сам саме з тих причин, які ви пояснили: ІМХО навіть найменша функція чи метод не повинні робити жодних припущень щодо того, як працює або зміниться решта коду. Натомість мій код слідує простому шаблону: "якщо введення в порядку, то виведіть ще помилку". Це відповідає загальному принципу проектування мінімізації залежностей.
Джорджіо

3
Ви також забули: погані розробники. Деяким людям, які пишуть код, цього не повинно бути, і хороших процесів перегляду немає у багатьох магазинах.
Джо

20

Моє запитання. Хтось ще бачив такий код? Яким був ваш висновок, чому саме цей код був там?

1) Так.

2) У випадках, які я бачив, я б по-різному ставив це до:

  • Досвід програміста
  • Програміст не розуміє особливо складної та / або неякісно виконаної конструкції, яку він намагається модифікувати
  • Програміст переривається посеред (скажімо) рефактора.
  • Недбалість

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

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


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

ІМО, це не є результативним і не сприяє хорошим робочим відносинам з вашими колегами.


+1 Набрав відповідь і виявив, що ви майже перерахували всі причини, про які я збирався зазначити.
канадський секретар

+1 за добродійність. Виправляйте чиїсь помилки, не вказуючи пальцями, і ваші колеги будуть поважати як ваші технічні вміння, так і навички своїх людей. Постановте автора за їхній хитрий код, і ваші колеги будуть обурюватися вашим підходом і знижувати ваші здібності.
Калеб

13

Все це часто є симптомами того, як старіє проект.

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

Я, мабуть, пам’ятаю це з dailywtf:

@deprecated // he might have been crazy enough to use reflection...
boolean getTrue() {
    return false; 
}

 2. Надмірні перевірки, виконані в окремому файлі класу, об'єкті чи методі. Шари спілкування також недосконалі (коли-небудь читати Міфічний місяць місяця? Якщо ні, то що ти робиш на комп’ютері!? Переход! ЧИТАТИ!). Часто одна людина над чимось попрацює, а потім покине проект, а потім наступний хлопець, знайшовши якусь химерну помилку, кидає тут і там додаткову перевірку, щоб спробувати її усунути. Коли помилка видалена, перевірки не відбувається, тому що, якщо вона не зламана, не виправляйте її.

 3. якщо твердження, які завжди оцінюють як істинні. О, я це зробив. Я отримав проект один раз, він мав серію, ймовірно, 10-15 if / else блоків. Щоб змінити поведінку, я просто ставлю true||на перший блок. Лише місяці (роки?) Пізніше я повернувся і сказав: "О, уау, цей код повинен був бути знищений, але ніколи не був"

 4. Нитки, які відкручуються і нічого не роблять помітними. Я можу уявити собі такий вигляд думки:

  1. Я знаю! Я можу впоратися з цими двома проблемами асинхронно! Я буду створювати нитки foo та bar.
  2. (через два місяці) Так, ви знаєте, функціональність від бару трохи краща в foo. Я трохи переїду.
  3. (через рік) Ви знаєте, переводити цей інший матеріал з бару в куме має сенс.
  4. (багато, багато років пізніше) "Ей, ця barтема не схожа на те, що робить щось, ми можемо її зняти?" "Краще ні, це було багато-багато років ..."

5
+1 за "Краще ні, це було багато-багато років ..." - це трапляється знову і знову. Страх зняти через страх перед наслідками ("Як ми перевіряємо, щоб ми щось не зламали" - особливо якщо навколо немає одиничних тестів).
quick_now

11

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


13
Хоча це важко, Ніколи не приписуйте злобі того, що можна пояснити дурістю.
Брюс Едігер

8

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

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


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

6

Більшість відповідей зводиться до цих двох простих фактів:
[1] Код відображає історію коду, а
[2] Код відображає очікуване майбутнє коду.

У мене є написані функції, які не мають нічого цінного, В СУЧАСНОМУ ЗАЯВКІ ЗАСТОСУВАННЯ з урахуванням СУЧАСНИХ СПЕЦИФІКАЦІЙ, але вони можуть знадобитися в майбутньому.

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

Щодо зайвих чеків, ей, я не довіряю іншому коду, я навіть не довіряю своєму коду. Якщо модуль залежить від N 1 або 2 або 3, він заграв, то краще переконайтесь у цьому, і якщо це не так, вийти з ладу. Незалежно від того, щоб модуль B вибухнув, тому що модуль A вкрутився; Модуль B цілком правомірно скаржиться, що Модуль А накрутив. І пам’ятайте, що наступного місяця цей параметр може надходити з ще неписаного модуля C.


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

1
якщо (language = 'en' або language = th ') - можливо, наступного місяця ми спробуємо китайську? if (! isset ($ TITLE)) - всі модулі ПОДАЄТЬСЯ для встановлення $ TITLE, але, можливо, хтось колись написав це неправильно. if (file_exists ($ TARGET)) - хороший код вже створив файл, але, можливо, є системна помилка, і він не створився. Мій стандартний код інтерфейсу PHP / MySQL завжди перевіряє наявність помилок, хоча я ще ніколи його не спіймав.
Енді Кенфілд

3

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

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


3

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

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


2
  • Виклики методу або функції, які нічого не мають значення.

Не обов’язково погано. Методи базового класу часто називають порожніми методами, які мають на увазі як заміщення точок для підкласів. Приклад: UIView Cocoa Touch має -didAddSubview:метод, задокументований як нічого не робити у версії за замовчуванням. -addSubview:Метод UIView повинен викликати, -didAddSubview:хоча він нічого не робить, оскільки підкласи можуть його реалізувати, щоб зробити щось. Методи, які нічого не роблять, і причини для них повинні бути задокументовані, звичайно.

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

  • Надмірні перевірки, виконані в окремому файлі, об'єкті чи методі класу.

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

  • якщо твердження, які завжди оцінюють як істинні.

Існує велика різниця між:

if (1) {
    // ...
}

і:

if (foo() == true) {
    // ...
}

куди foo()трапляється завжди повертатися true.

Перший випадок трапляється багато, коли люди налагоджують. Це легко використовувати if (0) {...для тимчасового видалення шматка коду, коли ви намагаєтесь виділити помилку, а потім змінити 0на, 1щоб відновити цей код. ifПовинно бути видалено , як тільки ви зробили, звичайно, але це легко забути цей крок, або пропустити один або два , якщо ви зробили це в декількох місцях. (Це гарна ідея ототожнювати такі умови з коментарем, який можна пізніше шукати.) Єдина шкода - це плутанина, яка може спричинити в майбутньому; якщо компілятор може визначити значення умови під час компіляції, він видалить його повністю.

Другий випадок може бути прийнятним. Якщо умову, представлену foo()потребою, потрібно перевірити з декількох місць у коді, часто розбиваючи їх на окрему функцію чи метод, це часто правильна річ, навіть якщо зараз це foo()завжди відповідає дійсності. Якщо можливо, що foo()врешті-решт повернеться false, то виділення цієї умови методом чи функцією - це один із способів визначити всі місця, де код покладається на цю умову. Однак це робить певний ризик того, що foo() == falseумова залишиться неперевіреною і може призвести до проблем пізніше; рішення полягає в тому, щоб переконатися, що ви додаєте одиничні тести, які явно перевіряють цей falseвипадок.

  • Нитки, які відкручуються і нічого не роблять.

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


1

Це буває. Досить часто насправді.

Іноді ці кодові тупики більше схожі на старі козячі стежки, які прийшли в непридатність, коли навколо них встановлена ​​більш ефективна / сучасна / швидка автострада.

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

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


1

Іноді у мене встановиться глобальний булевий параметр true, а пізніше в моєму коді - if (bool), тоді під час виконання я можу встановити точку перерви в операторі if і переключити булевий файл, щоб щось перевірити.


0

Я заперечую проти того, щоб if trueтвердження без розбору класифікували як "безглуздий код".

Існує законний випадок використання if (1) { ... }блоку в коді C, який або хоче бути сумісним зі стандартом C, який наполягав на визначенні змінних, щоб бути на початку функції, або просто хоче, щоб локальні змінні були визначені якомога локальніше.

switch (i) {
    case 23:
        if (1) {
            /* I can declare a local var here! */
        }
        break;
}

5
Немає потреби в "if (1)", чому б просто не мати блок?
FigBug

3
І C / C ++, і C #, і я впевнений, що Java (а також, ймовірно, багато інших подібних мов) дозволяють блокувати анонімні блоки заяв; немає необхідності в if, whileабо подібна конструкція. Навряд чи це буде дуже чисто, але це, безумовно, дозволено відповідно до мовної специфікації.
CVn

0

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


0

Як згадував @Andy, велика складова, яку я бачив, зламає YAGNI .

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

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

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

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