Бессмысленный код в вашем источнике

34

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

  • Вызовы методов или функций, которые не имеют никакого значения.
  • Резервные проверки выполняются в отдельном файле класса, объекте или методе.
  • if заявления, которые всегда оценивают как истинные.
  • Потоки, которые крутятся и ничего не делают из заметок.

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

Мой вопрос Кто-нибудь еще видел такой код? Каков был ваш вывод, почему этот код был там?

Если кто-то написал такой код, можете поделиться почему?

Али
источник
4
if (false) {...}блоки отлично подходят для комментирования кода! </
sarcasm
18
Никогда не приписывайте злобе то, что адекватно объясняется глупостью , особенно в разработке программного обеспечения, где временные быстрые взломы редко бывают временными.
wildpeaks
1
@ dlras2 поворот сюжета: # ОПРЕДЕЛИТЬ ложные истины :)
Сильвиу Бурча

Ответы:

17

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

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

JeffO
источник
2
Я склонен дать вам правильный ответ в этом случае, потому что часть кода, который я вижу, просто не может быть непреднамеренной ... нет, если кто-то не был высок, когда они кодировали и думали, что это будет просто смешно! Я верю, что у других также есть веские причины для бесполезного кода, но код, который я вижу, относится к проектам, над которыми работало несколько человек, и я первый парень за пределами оригинальной команды разработчиков, работающий над ним. Я должен сказать, что это похоже на случай сложности, добавленной к шоку и страху.
Али
18
@ Али: Никогда не приписывайте злобе то, что лучше объяснить некомпетентностью. Другими словами - код, вероятно, эволюционировал до такого рода беспорядков, потому что никто не был достаточно смел, чтобы тратить время на то, чтобы реально посмотреть на него и посмотреть, что он на самом деле делает. Все это звучит как куча быстрых исправлений, применяемых снова и снова, пока все, что осталось, это куча гадости.
fast_now
1
+1 для @quickly_now. Обычно так и происходит; все боятся дотрагиваться до всего, что «работает», опасаясь его сломать (или, боже упаси, больше времени на выполнение задачи по улучшению кода! Ужас!). Так что код гниет, гниет и, наконец, рушится через много лет.
Уэйн Молина
@ Али, были случаи, когда код, который кажется наиболее семантическим и разумным, был описан как я, вероятно, думающий, что это смешно или хвастается. И наоборот, когда я вижу чужой код. Вы никогда не знаете, кто сумасшедший, и в большинстве случаев все сводится к опыту и предпочтениям. (здесь речь не идет об объективно плохом коде, просто о том, что такие описания легко разбрасываются)
Михаил Малостанидис
73

Я не видел подобного кода, но видел код, который выглядит бессмысленным или бессмысленным по другим причинам:

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

  2. Защитное кодирование. Вы знаете, что проверки в этом коде бессмысленны, потому что это уже было проверено в другом месте. Но что, если кто-то изменит этот код в другом месте и удалит или изменит проверки, чтобы они больше не соответствовали вашим предварительным условиям?

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

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

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

StasM
источник
22
Я думаю, что № 3, «Органический рост», объясняет большую часть бесполезного кода, который я видел на работе. Но все 4 эти причины предполагают умного программиста. Некоторый бесполезный код происходит от того, что кто-то не понимает, что должно произойти, а что нет, и оставляет большой объем кода исключительно из-за страха изменить то, что (вроде) работает.
Брюс Эдигер
2
Я видел № 4 в своем проекте: часто не делается специально для того, чтобы иметь больше власти внутри компании, скорее есть люди, которые всегда пытаются создать более общее решение, даже если оно не нужно. Что касается # 2, я сам его часто использую именно по тем причинам, которые вы объяснили: ИМХО, даже самая маленькая функция или метод не должны делать никаких предположений относительно того, как остальная часть кода работает или изменится. Вместо этого мой код следует простому шаблону: «если ввод в порядке, то вывести ошибку else». Это следует общему принципу минимизации зависимостей.
Джорджио
3
Вы также забыли: плохие разработчики. Некоторых людей, которые пишут код, не должно быть, и хороших процессов обзора не существует во многих магазинах.
Джо
20

Мой вопрос Кто-нибудь еще видел такой код? Каков был ваш вывод, почему этот код был там?

1) да.

2) В случаях, которые я видел, я бы по-разному описал это:

  • Неопытность программиста
  • Программист не понимает особенно сложный и / или плохо выполненный дизайн, который он пытается изменить
  • Программист прерывается посреди (скажем) рефакторинга.
  • небрежность

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

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


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

ИМО, это не продуктивно и не способствует хорошим рабочим отношениям с вашими коллегами.

Стивен С
источник
+1 Набирал ответ и обнаружил, что вы в значительной степени перечислили все причины, которые я собирался упомянуть.
canadiancreed
+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. (год спустя) Знаете, помещать эти другие вещи из бара в foo имеет смысл.
  4. (много, много лет спустя) "Эй, эта barветка, похоже, ничего не делает, мы можем удалить это?" «Лучше нет, это было там много, много лет ...»
cwallenpoole
источник
5
+1 за «Лучше нет, это было там много, много лет ...» - это происходит снова и снова. Страх удаления из-за боязни последствий («Как мы проверяем, что мы что-то не сломали» - особенно если вокруг нет модульных тестов).
fast_now
11

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

Джонатан Ху
источник
13
Хотя это трудно, никогда не приписывай Малис то, что можно объяснить глупостью.
Брюс Эдигер
8

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

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

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

Большинство ответов сводятся к этим двум простым фактам:
[1] код отражает историю кода, а
[2] код отражает ожидаемое будущее кода.

Я написал функции, которые не имеют никакой ценности, в СРЕДЕ СОВРЕМЕННОГО ПРИЛОЖЕНИЯ, учитывая СОВРЕМЕННЫЕ ТЕХНИЧЕСКИЕ ХАРАКТЕРИСТИКИ, но могут понадобиться в будущем.

Я написал заявления if, которые в НАСТОЯЩЕМ всегда оценивают как истинные. Но, возможно, в прошлом это могло быть ложным.

Что касается избыточных проверок, эй, я не доверяю другому коду, я даже не доверяю своему собственному коду. Если модуль зависит от N, равного 1, 2 или 3, он чертовски хорош, лучше убедиться в этом и информативно потерпеть крах, если это не так. Модуль B не может взорваться, потому что модуль A облажался; для модуля B вполне законно жаловаться, что модуль A облажался. И помните, что в следующем месяце этот параметр может поступить из еще не написанного модуля C.

Энди Кэнфилд
источник
1
Я называю это плохим кодированием. Вы ожидаете, что это понадобится вам в будущем, но это случается редко. YAGNI. Написание if, которое всегда оценивается как true, - это напрасная трата усилий и запутывание человека, который должен добавить весьма вероятные различные функции для начала. Этот параметр, который появится в следующем месяце, может ждать до следующего месяца, чтобы быть добавленным. Загромождать код сейчас бессмысленно.
Энди
1
if (language = 'en' или language = th ') - может быть, в следующем месяце мы попробуем китайский? if (! isset ($ TITLE)) - все модули ПРЕДЛОЖЕНЫ для установки $ TITLE, но, возможно, кто-нибудь когда-нибудь произнесет это неправильно. if (file_exists ($ TARGET)) - хороший код уже создал файл, но, возможно, произошла системная ошибка, и он не был создан. Мой стандартный код интерфейса PHP / MySQL всегда проверяет наличие ошибок, хотя я еще ни разу их не обнаруживал.
Энди Кэнфилд
3

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

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

DBlackborough
источник
3

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

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

Скотт К Уилсон
источник
2
  • Вызовы методов или функций, которые не имеют никакого значения.

Не обязательно плохо. Методы в базовом классе часто вызывают пустые методы, которые подразумеваются как точки переопределения для подклассов. Пример: UIView Cocoa Touch имеет -didAddSubview:метод, который задокументирован как ничего не делающий в версии по умолчанию. Метод UIView -addSubview:должен вызывать, -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;
}
ndim
источник
5
Нет необходимости в «if (1)», почему бы просто не иметь блок?
FigBug
3
И C / C ++, и C #, и я уверен, что Java (как и многие другие подобные языки) допускает блоки анонимных операторов; нет необходимости в if, whileили подобная конструкция. Маловероятно, что он будет очень чистым, но, безусловно, это разрешено в соответствии со спецификацией языка.
CVN
0

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

Casey
источник
0

Как уже упоминалось @Andy, большой компонент я видел нарушение YAGNI .

Кто-то начинает с предположения о том, какими будут все элементы вместо того, что может понадобиться многим элементам , что является путаницей отношений "есть" и "имеет" .

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

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

MaxWell
источник