Антипаттерн

Pause

Антипа́ттерн (англ. anti-pattern, antipattern) — это распространённый подход к решению класса часто встречающихся проблем, являющийся неэффективным, рискованным или непродуктивным[1]. В отличие от шаблона (паттерна) проектирования, антипаттерн включает в себя как неправильное решение проблемы с его признаками и последствиями, так и выход из ситуации[2].

Термин происходит из информатики, из книги 1994 года «Шаблоны проектирования» / «Паттерны проектирования» (англ. Design Patterns), написанной четырьмя авторами, прозванными «бандой четырёх». Данная книга дала примеры практики хорошего программирования и заложила основы такого программирования. Авторы назвали эти хорошие методы «шаблонами» / «паттернами», и противоположными им являются «антипаттерны». Частью хорошей практики программирования является избегание антипаттернов.

До появления термина все проблемы назывались ловушки (англ. pitfalls). Антипаттерны — это самые распространённые ловушки, но не все ловушки будут антипаттернами.

Антипаттерны концептуально похожи на паттерны в том, что они документируют повторяющиеся решения общих проблем. Они известны именно как антипаттерны, потому что их использование (или злоупотребление ими) даёт негативные последствия[3].

Общие сведения
Что важно знать
Антипаттерн
англ. anti-pattern, antipattern
Описан в Design Patterns Да

История

С развитием ИТ-индустрии масштабы программных проектов и затраты ресурсов на них стремительно росли, что порождало большое количество проблем, встававших перед программистами. Большинство этих проблем были типичными и встречались практически в каждом крупном проекте. В начале 1990-х годов приобрели значительную популярность каталоги шаблонов проектирования, «паттернов» (англ. design patterns), — элегантных и проверенных на практике способов решения типичных задач. Паттерны и на сегодняшний день являются мощными и чрезвычайно популярны, однако многие разработчики, используя популярные паттерны в ситуациях, для которых они не предназначены, порождали этим больше проблем, чем решали. Кроме того, у ИТ-инженеров, как и у работников любой другой сферы деятельности, можно выделить типичные совершаемые ошибки, обусловленные недостаточной базой знаний или отсутствием опыта, спешкой и оказываемым давлением из-за сроков сдачи проекта, финансовыми ограничениями и проч.

Впервые термин «антипаттерн» в смысле обобщённого описания типичного неудачного решения был применён в 1996 году Майклом Эйкройдом (англ. Michael Akroyd) на конференции Object World West Conference, посвящённой аспектам объектно-ориентированного программирования[4]. В своей презентации «Антипаттерны: предотвращение неправильного использования объектов» Эйкройд обращал внимание на вредные, но частые программные конструкции, в частности те, что противоречат принципам ООП. К тому же для каждой такой конструкции он предлагал эффективную замену.

Термин в смысле «плохая идея» встречался и до Эйкройда, но не публиковался и особой популярностью не пользовался. И всё же приписывать авторство одному человеку не стоит. Как считает Уильям Браун, автор книги «Антипаттерны: рефакторинг приложений, архитектур и проектов», антипаттерн — это этап эволюции понятия паттерна проектирования, расширение их модели.

Классификация

Уильям Браун выделяет антипаттерны с трёх точек зрения — разработчика, архитектора и менеджера:

  • Антипаттерны разработки (development antipatterns)
  • Архитектурные антипаттерны (architectural antipatterns)
  • Организационные антипаттерны (managerial antipatterns)

Нейл и Лапланте приводят четвёртый тип[5][6]:

  • Антипаттерны среды, или антипаттерны обстановки (environmental antipatterns)

Кроме того, антипаттерны были описаны для отдельных информационных технологий, таких как[6]:

Антипаттерны разработки

Технические проблемы и решения, с которыми имеют дело программисты[6]:

Антипаттерны в объектно-ориентированном программировании

  • Базовый класс-утилита (BaseBean[12]): наследование функциональности из класса-утилиты вместо делегирования к нему.
  • Anemic Domain Model[12]: боязнь размещать логику в объектах предметной области.
  • Вызов предка (Call super): для реализации прикладной функциональности методу класса-потомка требуется в обязательном порядке вызывать те же методы класса-предка.
  • Ошибка пустого подкласса (Empty subclass failure): создание класса (в Perl), который не проходит «проверку пустоты подкласса» (Empty Subclass Test) из-за различного поведения по сравнению с классом, который наследуется от него без изменений.
  • Божественный объект (God object): концентрация слишком большого количества функций в одной части системы (классе).
  • Объектная клоака (Object cesspool): переиспользование объектов, находящихся в непригодном для переиспользования состоянии.
  • Полтергейст (Poltergeist[13]): объекты, чьё единственное предназначение — передавать информацию другим объектам.
  • Проблема йо-йо (Yo-yo problem): чрезмерная размытость сильно связанного кода (например, выполняемого по порядку) по иерархии классов.
  • Одиночество (Singletonitis): неуместное использование паттерна одиночка.
  • Френд-зона (Friend zone): неуместное использование дружественных классов и дружественных функций в языке C++.
  • Каша из интерфейсов (Interface soup[14]): объединение нескольких интерфейсов, разделённых согласно принципу изоляции интерфейсов (Interface segregation), в один.
  • Висящие концы: интерфейс, большинство методов которого бессмысленны и реализуются «пустышками».
  • Заглушка (Stub): попытка «натянуть» на объект уже имеющийся малоподходящий по смыслу интерфейс вместо создания нового.

Антипаттерны при написании кода

  • Ненужная сложность (Accidental complexity): внесение ненужной сложности в решение.
  • Действие на расстоянии (Action at a distance): неожиданное взаимодействие между широко разделёнными частями системы.
  • Накопить и запустить (Accumulate and fire): установка параметров подпрограмм в наборе глобальных переменных.
  • Слепая вера (Blind faith): недостаточная проверка корректности исправления ошибки или результата работы подпрограммы.
  • Лодочный якорь (Boat anchor)[13]: сохранение более не используемой части системы.
  • Активное ожидание (Busy spin, busy waiting): потребление ресурсов ЦПУ (процессорного времени) во время ожидания события, обычно при помощи постоянно повторяемой проверки, вместо того чтобы использовать асинхронное программирование (к примеру, систему сообщений или событий).
  • Кэширование ошибки (Caching failure): забывать сбросить флаг ошибки после её обработки.
  • Воняющий подгузник (The Diaper Pattern Stinks): сброс флага ошибки без её обработки или передачи вышестоящему обработчику.
  • Проверка типа вместо интерфейса (Checking type instead of membership, Checking type instead of interface): проверка того, что объект имеет специфический тип в то время, когда требуется только определённый интерфейс.
  • Инерция кода (Code momentum): сверхограничение части системы путём постоянного подразумевания её поведения в других частях системы.
  • Кодирование путём исключения (Coding by exception): добавление нового кода для поддержки каждого специального распознанного случая.
  • Таинственный код (Cryptic code): использование аббревиатур вместо мнемоничных имён.
  • Жёсткое кодирование (Hard code): внедрение предположений об окружении системы в слишком большом количестве точек её реализации.
  • Мягкое кодирование (Soft code): патологическая боязнь жёсткого кодирования, приводящая к тому, что настраивается всё что угодно, при этом конфигурирование системы само по себе превращается в программирование.
  • Поток лавы (Lava flow)[13]: сохранение нежелательного (излишнего или низкокачественного) кода по причине того, что его удаление слишком дорого или будет иметь непредсказуемые последствия.
  • Волшебные числа (Magic numbers): использование числовых констант без объяснения их смысла.
  • Процедурный код (Procedural code): когда другая парадигма является более подходящей.
  • Спагетти-код (Spaghetti code, иногда «макароны»)[13]: код с чрезмерно запутанным порядком выполнения.
  • Лазанья-код (Lasagnia code, или «лук» (onion)): чрезмерное связывание между собой уровней абстракции, приводящее к невозможности изменения одного уровня без изменения остальных.
  • Равиоли-код (Ravioli code, или «пельмени»): объекты настолько «склеены» между собой, что практически не допускают рефакторинга.
  • Мыльный пузырь (Soap bubble): объект, инициализированный мусором, максимально долго притворяется, что содержит какие-то данные.
  • Мьютексный ад (Mutex hell): внедрение слишком большого количества объектов синхронизации между потоками.
  • (Мета-)шаблонный рак (Template cancer): повсеместное использование шаблонов (в основном C++), в том числе там, где их использование не оправдано. Это уменьшает понимание и сопровождение кода и замедляет компиляцию.

Методологические антипаттерны

  • Программирование методом копирования-вставки (Copy and paste programming)[13]: копирование (и лёгкая модификация) существующего кода вместо создания общих решений.
  • Дефакторинг (De-Factoring): процесс уничтожения функциональности и замены её документацией.
  • Золотой молоток (Golden hammer[13]): сильная уверенность в том, что любимое решение универсально применимо. Название происходит от поговорки «когда в руках молоток, все проблемы кажутся гвоздями».
  • Фактор невероятности (Improbability factor): предположение о невозможности того, что сработает известная ошибка.
  • Преждевременная оптимизация (Premature optimization): оптимизация на этапе проектирования сегмента кода, приводящая к его усложнению или искажению.
  • Программирование методом подбора (Programming by permutation): подход к разработке программного обеспечения небольшими изменениями без понимания их смысла.
  • Изобретение колеса/велосипеда (Reinventing the wheel[13]): создание с нуля вместо использования хорошего готового решения.
  • Изобретение квадратного колеса (Reinventing the square wheel): создание плохого решения, при условии, что уже существует известное решение лучше.
  • Самоуничтожение (Self-destruction): фатальная ошибка (либо нестандартное поведение) программы, приводящая к отказу в обслуживании, возникшая вследствие другой, менее серьёзной ошибки. Например, при возникновении ошибки приложение начинает очень быстро и много писать в лог, вследствие чего заканчивается место на жёстком диске быстрее, чем это обнаружит мониторинг.
  • Два тоннеля: вынесение новой функциональности в отдельное приложение вместо расширения уже имеющегося. Чаще всего применяется, когда по каким-либо причинам (в основном при нехватке времени либо нежелании менеджмента) внесение изменений в уже имеющийся код требует больших затрат, чем создание нового. При этом у клиента в конечном итоге работают два приложения, запускаясь одновременно либо попеременно друг из друга.
  • Коммит-убийца (Commit assasin): внесение отдельных изменений в систему контроля версий без проверки влияния их на другие части программы. Как правило, после подобных коммитов работа коллектива парализуется на время исправления проблем в местах, которые ранее работали безошибочно.

Антипаттерны управления конфигурацией

  • Ад зависимостей (Dependency hell, на платформе Microsoft Windows также называется DLL hell, «DLL-ад»): разрастание графа взаимных зависимостей программных продуктов и библиотек, приводящее к сложности установки новых и удаления старых продуктов. В сложных случаях различные установленные программные продукты требуют наличия разных версий одной и той же библиотеки. В наиболее сложных случаях один продукт может косвенно потребовать сразу две версии одной и той же библиотеки.

Разные

  • Дым и зеркала (Smoke and mirrors[13]): демонстрация того, как будут выглядеть ненаписанные функции (название происходит от двух излюбленных способов, которыми фокусники скрывают свои секреты).
  • Раздувание ПО (Software bloat): разрешение последующим версиям системы требовать всё больше и больше ресурсов.
  • Функции для галочки: превращение программы в конгломерат плохо реализованных и не связанных между собой функций (как правило, для того, чтобы заявить в рекламе, что функция есть).

Архитектурные антипаттерны

Типичные проблемы, связанные со структурой системы[6]:

  • Инверсия абстракции (Abstraction inversion): сокрытие части функциональности от внешнего использования, в надежде на то, что никто не будет её использовать.
  • Неопределённая точка зрения (Ambiguous viewpoint[13]): представление модели без спецификации её точки рассмотрения.
  • Большой комок грязи (Big ball of mud): система с нераспознаваемой структурой.
  • Блоб (Blob[13]): см. Божественный объект (God object).
  • Бензиновая фабрика (Gas factory): необязательная сложность дизайна.
  • Затычка на ввод данных (Input kludge[13]): забывчивость в спецификации и выполнении поддержки возможного неверного ввода.
  • Раздувание интерфейса (Interface bloat): разработка интерфейса очень мощным и очень сложным для реализации.
  • Волшебная кнопка (Magic pushbutton): выполнение результатов действий пользователя в виде неподходящего (недостаточно абстрактного) интерфейса. Например, в системах типа Delphi это написание прикладной логики в обработчиках нажатий на кнопку.
  • Перестыковка (Re-Coupling): процесс внедрения ненужной зависимости.
  • Дымоход (Stovepipe System[13]): редко поддерживаемая сборка плохо связанных компонентов.
  • Состояние гонки (Race hazard, Race condition): непредвидение возможности наступления событий в порядке, отличном от ожидаемого.
  • Мышиная возня[15]: неоправданное создание множества мелких и абстрактных классов для решения одной конкретной задачи более высокого уровня.
  • Членовредительство (Mutilation): излишнее «затачивание» объекта под определённую очень узкую задачу таким образом, что он не способен будет работать с никакими иными, пусть и очень схожими задачами.
  • Сохранение или смерть (Save or die): сохранение изменений в конфигурации на жёсткий диск лишь при завершении приложения; приводит к тому, что в случае отказа в программе эти данные будут утеряны.

Организационные антипаттерны

Проблемы, с которыми встречаются менеджеры (или группы менеджеров)[6]:

  • Аналитический паралич (Analysis paralysis)[13]: неоправданно большие затраты на анализ и проектирование. Часто приводит к закрытию проекта до начала его реализации.
  • Дойная корова (Cash cow): при наличии продукта, приносящего выгоду без существенных вложений, не вкладываются средства в развитие и разработку новых продуктов.
  • Продолжительное устаревание (Continuous obsolescence)[13]: выделение непропорционально больших усилий на портирование системы в новые окружения.
  • Сваливание расходов (Cost migration): перенос расходов на проект к слабому отделу или бизнес-партнёру.
  • Раздутый улучшизм (Creeping featurism): добавление новых улучшений в ущерб суммарному качеству системы.
  • Раздутый элегантизм (Creeping elegance): непропорциональное улучшение красивости кода в ущерб функциональности и суммарному качеству системы.
  • Разработка комитетом (Design by committee)[13]: разработка проекта без централизованного управления или без компетентного руководства.
  • Неуёмная преданность (Escalation of commitment): продолжение реализации решения после того, как доказана его ошибочность.
  • Я тебе это говорил (I told you so): игнорирование мнения эксперта.
  • Управление, основанное на числах (Management by numbers): излишнее внимание к численным показателям, имеющим очень косвенное отношение к управляемой системе, сложным для получения либо подверженным эффекту Гудхарта.
  • Драконовские меры (Management by perkele): неоправданно жёсткий стиль управления.
  • Управление грибами (Mushroom management)[13]: недостаточное информирование работников о выполняемой работе.
  • Расползание рамок (Scope creep): потеря контроля над разрастанием проекта.
  • Привязка к поставщику (Vendor lock-in)[13]: жёсткая привязка к поставщику.
  • Тёплое тело (Warm Bodies)[13]: человек, чей вклад в проект под сомнением.
  • Единственный знающий человек (Single head of knowledge, SHOK): когда жизненно важными для проекта сведениями или навыками обладает только один человек в команде, а с его уходом работа останавливается.
  • Рыцарь на белом коне (Knight in shining armor, KISA): когда на сцене появляется человек, который пытается починить всё, не сообщая никому, что он сделал и почему.

Нейл и Лапланте приводят следующие антипаттерны[5]:

  • Заочный менеджер (Absentee Manager): менеджер ведет себя уклончиво или невидим в течение длительного времени — он прячется где-то в офисе или вдали от офиса.
  • Иметь только молоток (All You Have Is A Hammer): однонаправленное управление, где одни и те же приёмы используются на всех подчинённых и во всех ситуациях. Иногда также называется One-Trick Pony.
  • Дикий менеджер (Cage Match Negotiator): любой менеджер, который упрям не по разуму и использует подход к управлению «Победа любой ценой» или «Я прав, а вы нет». У них часто есть кофейная кружка с «Правилами управления»: «Правило №1: Босс всегда прав. Правило №2: Если босс не прав, см. Правило №1».
  • Доппельгангер (Doppelganger): менеджер или коллега, с которым то легко работать, то трудно.
  • Бесплодные прыжки (Fruitless Hoops): вы готовите для менеджеров всё новые и новые данные, нужные им для принятия решения, но менеджеры так и не принимают никакого решения, продолжая запрашивать у вас данные. Вы не знаете, зачем им нужны эти данные.
  • Золотой ребёнок (Golden Child): «золотой ребёнок» («золотое дитя») появляется в ситуациях, когда менеджер предоставляет особую ответственность, возможность, признание или вознаграждение члену своей команды на основе личных взаимоотношений с ним и вопреки его действительным действиям. Всех раздражает «золотой ребёнок», но настоящая проблема заключается в менеджере.
  • Безглавая курица (Headless Chicken): менеджер без фокуса и плана, который никогда ничего не заканчивает.
  • Лидер не менеджер (Leader Not Manager): подчёркивает важность эффективного руководства.
  • Менеджер попугай (Managerial Cloning): менеджеры среднего звена, начинающие со временем вести себя, как их начальники.
  • Менеджер не лидер (Manager Not Leader): такой менеджер хорошо справляется с административными и управленческими обязанностями, но не обладает лидерскими способностями.
  • Злоупотребление метриками (Metric Abuse): неправильное использование метрик из-за некомпетентности или умышленного манипулирования данными.
  • Классный чувак (Mr. Nice Guy): менеджер, который сосредотачивается на том, чтобы быть другом каждого, в конечном итоге разочаровывает всех и не справляется со своими обязанностями.
  • Управление грибами (Mushroom Management): ситуация, в которой руководство не может эффективно общаться с персоналом. По сути, информация намеренно скрывается, чтобы все были «толстыми, глупыми и счастливыми». Название связано с аналогией: шампиньоны выращивают в темноте и в навозе.
  • Полирование тарелок (Plate Spinning): менеджер скрывает свою неэффективность, заставляя работников заниматься трудоёмкой и бесполезной работой.
  • Герой пролетариата (Proletariat Hero): менеджер ведёт себя с подчинёнными, как с идеальными работниками, но это лишь его опора, используемая для маскировки плохого управления. Это форма «мотивации» персонала, которая даёт повод руководству повысить ожидаемые результаты или получить больше с меньшими затратами.
  • Звёздный выскочка (Rising Upstart): суперзвёзды, которые не могут терять время на обучение и поиск своего места. Иногда это может быть из-за невежества (они не знают, что они что-либо не знают), а иногда из-за нетерпения (они знают то, чего не знают другие). Такой выскочка представляет настоящий вызов для всех, кроме самых опытных менеджеров.
  • Дорога в никуда (Road to Nowhere): Отсутствие плана вызывает замешательство и кризис руководства.
  • Бесхребетный руководитель (Spineless Executive): любой менеджер, который не имеет смелости вступить в необходимую конфронтацию или справиться со сложной ситуацией. Вместо этого он полностью избегает конфронтации или ситуации или просит вас сообщить ему плохие новости.
  • Трёхглавый рыцарь (Three-Headed Knight): нерешительный менеджер.
  • Абсолютный инструмент (Ultimate Weapon): менеджер объявляет, что все могут положиться на выдающихся сотрудников настолько, что эти сотрудники станут проводником всего.
  • Тёплое тело (Warm Bodies): управленческая ситуация, в которой работник, который едва соответствует минимальным требованиям, перемещается от проекта к проекту или от команды к команде. Слабый работник называется «тёплым телом», хотя настоящая проблема заключается в менеджере. Этот антипаттерн является противоположностью «звёздного выскочки» в отношении навыков и потенциала.

Антипаттерны обстановки

Проблемы, вызванные доминирующей в организации структурой и социальной моделью, являющейся результатом действующей в организации общественной политики[16][6][5][17]:

Примечания

  1. ↑ Budgen, D. Software design. — Addison-Wesley, 2003. — ISBN 0-201-72219-4.
  2. ↑ Brown, 1998, Chapter 2.
  3. ↑ Smith C. U., 2000.
  4. ↑ http://c2.com/cgi/wiki?AntiPattern. Cunningham & Cunningham, Inc.. Дата обращения: 15 февраля 2006. Архивировано 3 апреля 2005 года.
  5. ↑ 1 2 3 Neill, Laplante, 2005.
  6. ↑ 1 2 3 4 5 6 Settas, 2011.
  7. ↑ Miroslav Kis. Information security antipatterns in software requirements engineering. In Proceedings of the 9th Conference on Pattern Language of Programs (Plop), 2002.
  8. ↑ John Long. Software reuse antipatterns. In ACM SIGSOFT Software Engineering Notes, volume26, page 4, July 2001.
  9. ↑ Paula Kotze, Karen Renaud, and Judy van Biljona. Don’t do this — pitfalls in using anti-patterns in teaching human-computer interaction principles. Computers and Education, 50(3):979-1008, April 2008
  10. ↑ J. Krai and M. Zemlicka. The most important service-oriented antipatterns. In proceedings of the International Conference on Software Engineering Advances (ICSEA), 2007.
  11. ↑ P.A. Laplante, R.R. Hoffman, and G. Klein. Antipatterns in the creation of intelligent systems. IEEE Intelligent Systems, 22:91-95, 2007.
  12. ↑ 1 2 Rajiv Ramnath, Cheyney Loffing. Beginning IOS Programming For Dummies. — John Wiley & Sons, 2014-04-14. — С. 105. — 470 с. — ISBN 9781118799277. Архивная копия от 23 июля 2016 на Wayback Machine
  13. ↑ 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 William J. Brown. AntiPatterns: Refactoring Software, Architectures, and Projects in Crisis. — Wiley, 1998-04-03. — 156 с. — ISBN 0−471−19713−0. Архивная копия от 22 декабря 2015 на Wayback Machine
  14. ↑ Gary McLean Hall. Adaptive Code via C#: Agile coding with design patterns and SOLID principles. — Microsoft Press, 2014. — С. 267-268. — ISBN 978-0735683204.
  15. ↑ Абстрактные классы (abstract classes). The TypeScript Definitive Guide. Дата обращения: 19 июня 2026.
  16. ↑ В оригинале: socio-political forces
  17. ↑ Phillip Laplante The Burning Bag of Dung—and Other Environmental Antipatterns Архивная копия от 19 сентября 2015 на Wayback Machine ACM Queue November 30, 2004 Volume 2, issue 7

Литература

Дополнительно по теме

Pause