Худшие анти-паттерны, с которыми вы столкнулись [закрыто]

9

Какие наихудшие анти-паттерны вы встретили в своей карьере программиста?

Я в основном занимаюсь Java, хотя, вероятно, это не зависит от языка.

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

стривігор
источник

Ответы:

38

Закомментированный код. Блоки этого, возможно, сотни строк. Теория такова: эй, это закомментировано, это не приносит никакого вреда, и, возможно, нам это понадобится в будущем.

Navi
источник
7
Ну, по крайней мере, вы можете безопасно удалить его. В отличие от того, с кем я работал, он часто переименовывал процедуры и оставлял мертвый код доступным. Blech.
Джей
@ Кирена, ты тоже работал с Эриком?!?
CaffGeek
Однажды у меня была куча кода, который использовал #ifdef COMMENT для блокировки вещей. Отлично работал, пока кто-то не определил КОММЕНТАРИЙ.
Майкл Кохне
9
Это еще один случай, когда использование контроля версий окупается. Вы можете удалить код, не спрашивая, нужен ли он вам в будущем, потому что он может быть получен снова несколькими нажатиями клавиш.
Джейсон Б.
5
Я думаю, что закомментированный код имеет место, если вы префикс его комментарием, который объясняет, почему он там. Иногда я оставляю закомментированный блок, представляющий потенциальную дорогу, о которой я думал, и оставляю в ней комментарий о том, почему я этого не сделал. @ Джейсон, я определенно слышал о том, что это роль контроля версий, но удаленный код в управлении версиями не очень заметен.
Nlawalker
19

Я ударю другой очевидный с "копи-паста". Копирование кода, который почти идентичен тому, что вы хотите, затем изменение нескольких вещей (вместо извлечения в метод).

Это особенно распространено в некоторых функциональных и API-тестовых кодах конца 90-х годов: буквально сотни (или даже тысячи) практически идентичных тестовых примеров, которые можно было бы разбить на несколько функций, которые принимают 3 или 4 параметра - или, что еще лучше что-то управляемое данными. Моей первой работой после колледжа было буквально 8 месяцев переписывания и рефакторинга тысяч строк копировальной пасты с использованием устаревших методов. К тому времени, как я закончил, тестовые файлы были менее чем на десятую часть от их первоначального размера и намного более удобны в обслуживании (и читаемы!).

Этель Эванс
источник
16

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

Как (не) писать Факториал на Java или так, мы вводим фабрику в ваш алгоритм

Андрей Таптунов
источник
3
Потрясающие! Теперь, где находится FactorialWebService? : P
FrustratedWithFormsDesigner
1
Я называю это Pattern Fever ... каждый получает это в один момент в своей карьере. Чем лучше среди нас расти, тем больше. У меня было интервью, где парень спросил меня, когда я должен думать о моделях. Я сказал ему, что позволю им эволюционировать в систему. Он сказал: «Нет, вы должны использовать шаблоны с самого начала».
Майкл Браун
FactoryFactories - это всего лишь признак желания отложить реальный выбор настолько, насколько это возможно, но он все равно заканчивается жестким кодированием или отображением значения внешней строки в фрагмент кода. Инъекция зависимости - лучшее решение.
Шаблоны - это артефакты хорошего дизайна - их следует рассматривать как таковые. Мне нравится описывать их как определения, а не как решения. Они полезны при общении, но не обязательно при проектировании.
Майкл К
Спасибо за это, хорошее чтение.
Сыг
14

районы

В C # вы можете определить область кода, которая может быть свернута в IDE, тем самым скрывая ее, если вы не хотите иметь дело с этим кодом. Я принимал (в настоящее время включаю) проект, в котором регионы охватывали сотни строк (если бы я преувеличивал), и в функции из тысячи строк было несколько регионов (опять же, я хотел бы шутить).

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

Регионы поощряют разработчиков «прятать» свое дерьмо на виду.

Майкл Браун
источник
15
+1 за регионы поощряют разработчиков «прятать» свое дерьмо на виду. Тем не менее, при правильном использовании я обнаружил, что регионы помогают логически сгруппировать код и легко находят его позже.
Даррен Янг
Это долго было проблемой со сворачиванием редакторов. Когда я последний раз программировал в OCCAM, я делал то же самое.
Майкл Кохне
2
Я люблю регионы ... но только для организации ... не скрывая цифровые пакеты кода.
IAbstract
3
+1. Вот почему использование регионов нарушает правило StyleCop SA1124 DoNotUseRegions.
Арсений Мурзенко
1
У меня есть проекты, которые работают с огромным количеством полей в SQL, и код, который обновляет / создает его, состоит из множества строк. Регион #region SQL Updateделает его разборным, поэтому требуется меньше прокрутки.
Джелтон
12

Для меня худший шаблон это Копировать / Вставить .

LennyProgrammers
источник
28
Для меня худший шаблон это Копировать / Вставить.
Эндрю Арнольд
9

Не перегруженные методы:

// Do something
public int doSomething(Data d);

// Do same thing, but with some other data
public int doSomething2(SomeOtherData d);

Наглядно видно, что программист не понимал перегрузки.

Майкл К
источник
5

Последовательности петлевого переключателя

http://en.wikipedia.org/wiki/Loop-switch_sequence

Они бесконечно раздражают меня и показывают, насколько неопытным был

CaffGeek
источник
Ах,
Почему вы должны вспомнить эти похороненные воспоминания? У меня был такой хороший день.
Малахи
5

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

AareP
источник
4

Сохраняйте состояние в клиенте.

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

user1249
источник
Не могли бы вы уточнить? Имхо, для веб-приложения нормально, когда в браузере находится только одно состояние (т. Е. Файлы cookie), а на сервере ничего не передается. Или вы имеете в виду «состояние», как в «базе данных приложений»?
Кеппла
Состояние: как в фактических данных для работы.
OO у вас есть мои глубокие соболезнования.
Keppla
4

Массивные Checkins

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

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

Майкл Браун
источник
1
Ничего не делать - это не всегда худший сценарий. Иногда лучше написать его с нуля, чем переписать код ...
Малахия
4

В настоящее время я работаю с устаревшим кодом, и мне нравится, как предыдущий кодер получает первый элемент списка:

String result;
for(int i = 0; i < someList.size(); i++) {
    result = someList.get(i);
    break;
}

Но самое худшее, что я видел в этом коде, это определение классов встроенных страниц JSP, написание всего HTML, CSS и Javascript с использованием scriptlet и out.println :-(

SourceRebels
источник
4

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

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

Малахи
источник
3

Блокировка на строковом литерале

synchronized("one") { /* block one A*/ }

synchronized("one") { /* block one B*/ }

Очень длинные имена классов. (в JRE)

com.sun.java.swing.plaf.nimbus.
InternalFrameInternalFrameTitlePaneInternalFrameTitlePaneMaximizeButtonWindowNotFocusedState

Плохая структура наследования

com.sun.corba.se.internal.Interceptors.PIORB extends
com.sun.corba.se.internal.POA.POAORB extends
com.sun.corba.se.internal.iiop.ORB extends
com.sun.corba.se.impl.orb.ORBImpl extends
com.sun.corba.se.spi.orb.ORB extends
com.sun.corba.se.org.omg.CORBA.ORB extends 
org.omg.CORBA_2_3.ORB extends
org.omg.CORBA.ORB

Исключение, которого нет.

public interface FlavorException { }

Бессмысленная и загадочная обработка ошибок

if (properties.size() > 10000)
   System.exit(0);

Ненужное создание объектов

Class clazz = new Integer(0).getClass();
int num = new Integer(text).intValue();

Бросать исключение для других целей

try {
    Integer i = null;
    Integer j = i.intValue();
} catch (NullPointerException e) {
    System.out.println("Entering "+e.getStackTrace()[0]);
}

Использование объектов экземпляра для статических методов.

Thread.currentThread().sleep(100);

Синхронизация на не финальном поле

synchronized(list) {
   list = new ArrayList();
}

Бессмысленная копия постоянной строки

String s = new String("Hello world");

Бессмысленный вызов String.toString ()

String s = "Hello";
String t = s.toString() + " World";

Вызов System.gc () для освобождения памяти

Установка локальной переменной на ноль для освобождения памяти

    // list is out of scope anyway.
    list = null;
}

Использование ++ i вместо i ++ по соображениям производительности (или любой другой микро-микро-оптимизации)

Питер Лори
источник
Это не обязательно анти-паттерны, просто плохое кодирование.
Гэри Уиллоуби
@ Гэри, или плохие модели развития, я вижу, повторяется. Возможно, не в рамках строгого определения анти-паттерна.
Питер Лоури
1
@Peter: «Вызовы System.gc () для освобождения некоторой памяти», я видел один случай, когда .NET взорвался бы с исключением OutOfMemory, если GC не был вызван явно. Конечно, это было скорее исключением, чем правилом.
Кодер
3

Код посыпан:

// TODO: 

или

// TODO: implement feature 

без дополнительной информации.

Малахия
источник
2

Итератор для чайников:

Iterator iCollection = collection.iterator();
for(int i = 0 ; i < collection.size() ; i++ ){
    if(collection.get(i) == something){
       iCollection.remove();
    }
 }

Singletono-Factory:

public class SomeObject{
   private SomeObject() {}
   public static SomeObject getInstance(){
       return new SomeObject();
   }
}

разработка, управляемая if-else (также называется принципом открытого закрытия - открытым для модификации, близкого для понимания):

if (sth1){
...  
}else if(sth2){
..
}
...
..
else if(sth1000000000000){
...
}

StringPattern (также называется StringObject):

a) sendercode
if(sth1)
   str+="#a";
if(sth2)
   str+="#b";
...
if(sth1000)
   str+="#n";

b) receiver
   regexp testing if str contains #a, #b, ... #n
Марчин Михальский
источник
Однако else ifзачастую это единственный способ добиться цели. Я думаю о строках; не могу использовать переключатель. Условия должны быть одинаковыми, чтобы это было полезно.
Майкл К
ИМХО каждый if / else может быть заменен простым отображением или шаблоном посетителя. В случае строк, т. Е. У вас может быть файл свойств, например: someString1 = some.package.ObjectToHandleSomeString1
Марчин Михальски,
2
Синглтон является завод . В этом коде нет ничего плохого. Единственное, что может быть неправильным, это то, что внешний код предполагает, что каждый вызов getInstanceвозвращает один и тот же экземпляр. Такое предположение нарушит инкапсуляцию и является одним из самых распространенных анти-паттернов.
back2dos
именно поэтому это так сбивает с толку :) если бы метод вызывался create () или он возвращал бы один и тот же экземпляр каждый раз, когда все было бы отлично
Marcin Michalski
2

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

Это связано с более общим шаблоном, который будет делать , вот примерная строка кода для него:

int num = new Integer( stringParam ).parseInt( stringParam );

Это работает, в конце концов.

бизиклоп
источник
2

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

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

  2. В MATLAB и R настойчивое требование, что все является вектором / матрицей, а не примитивом.

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

  4. Чисто функциональные языки, где вы должны использовать вызовы функций для написания цикла.

dsimcha
источник
1

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

И если бы разрешались шаблоны проектирования, я бы сказал: «Выполнение проекта как набора действий из плана, без какого-либо проектирования или анализа предметной области».

Coyote21
источник
1

Многофункциональный боб Java -

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

Кроме того, не могу забыть любимого

try{ 
   ... //many lines of likely dangerous operations
}
catch(Exception e){}
Стив Б.
источник
ИМХО, исключения воняют. Они слишком сложны, чтобы понять их правильно, и они добавляют ложное чувство безопасности.
Кодер
Каково бы ни было ваше мнение о вонючих исключениях, при молчаливом глотании нужно больше вонять.
Стив Б.
1

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

deltreme
источник
1

Что-то, что вызвало у меня много горя, это шаблон «Большая карта в небе». Бродить вокруг карты вместо использования правильных объектов. Вы не представляете, какие «переменные» он содержит, без отладки, и вы не знаете, что он может содержать, не отслеживая код в обратном направлении. Обычно отображает строки в объекты или строки в строки, которые вы потенциально должны анализировать в примитивы.

Buhb
источник
Звучит так, будто вы используете Session и ViewState в ASP.NET для передачи блоков данных между страницами, что, к сожалению, часто требуется ...
Уэйн Молина
1

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

Малахи
источник
0

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

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

Наш проект имеет довольно сложный алгоритм, который сохраняет промежуточные значения для последующей обработки. Вместо того, чтобы инкапсулировать временные объекты в ... объектах, была создана таблица базы данных, например, "t_object". Каждый раз, когда значение вычислялось, оно добавлялось в эту таблицу. После того, как алгоритм завершит свою работу, он выберет все промежуточные значения и обработает их все в одном большом объекте Map. После завершения всей обработки оставшиеся значения, помеченные для сохранения, будут добавлены в реальную схему базы данных, а временные записи в таблице "t_object" будут отброшены.

Таблица также использовалась как уникальный список, данные могли существовать только один раз. Это могло бы быть приличной особенностью дизайна, если бы мы реализовали ограничения в таблице, но в итоге мы перебрали всю таблицу, чтобы посмотреть, существуют ли данные или нет. (Нет, мы даже не использовали запросы, которые использовали предложения where с CONTAINS)

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

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

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

ПРИМЕЧАНИЕ: я не говорю, что этот паттерн по своей сути плох, но в этом примере я обнаружил, что он не нужен, когда основных принципов ОО было бы достаточно.

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

оборота Юлузвик
источник
Я бы не назвал это общей проблемой. Это будет зависеть от того, сколько временных данных хранится и что с ними делается.
GrandmasterB
Я должен добавить больше к посту, но основная проблема заключалась в том, что вместо изменения объектов и доступа к данным из памяти, данные обрабатывались с помощью хакерского SQL-кода. Это привело к увеличению сложности и серьезным проблемам с производительностью.
jluzwick
2
Вы не упоминаете свою проблемную область, но это не всегда плохо, так как сохранение состояния в другом месте может позволить процессам масштабироваться и подвергаться самоанализу в течение длительного времени, а также помогает в отладке. Был ли доступ к БД причиной проблем или проблем с производительностью?
Jé Queue
Я отредактировал статью, чтобы лучше отразить, как это использовалось в нашем проекте, но у нас были многочисленные проблемы при отладке, особенно потому, что нам пришлось запрашивать базу данных, чтобы увидеть временные переменные. Также у нас были большие проблемы с производительностью из-за того, что база данных постоянно запрашивала данные и проверяла, существуют ли новые данные.
jluzwick
0

Тележка перед лошадью - так называемый YouMightNeedIt

Например:

  • Создание схемы RDMB с абстрактными понятиями, перекрестными ссылками - по сути, чрезмерно обобщенным кубом данных ... И ТОГДА написание функций вокруг модели "все делает".
Шелдон Варкентин
источник
Это был бы злой брат-близнец ЯГНИ, верно?
Уэйн Молина
0

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

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

Foobar oFoo = new Foobar();
oFoo.FooID = 42;
if (oFoo.Load()) { 
    // do something with oFoo
}

на самом деле не является анти-паттерном, но демонстрирует недостаток использования правильной архитектуры и разделения проблем.

Кроме того, такие вещи:

// this name is misleading, we may not always want to stand in fire,
// we may want to stand in slime or voidzones or ice patches...
public Foobar StandInFire() { }

// why is this here???
public string BeatWithNerfBat(string whom) { }

// ????
public int GivePony(string to) { }
Уэйн М
источник