… a common pattern in software engineering research is the development of system-building techniques, such as object-oriented design, which are strongly advocated in the absence of evidence - K.N. Whitley, “Visual Programming Languages and the Empirical Evidence For and Against,” J. Visual Languages and Computing, vol. 8, pp. 109-142, 1997.
Паттерны проектирования стали неотъемлемой частью минимального набора знаний современного разработчика. Их упоминание вы с легкостью найдете в описании вакансии как на фронта, так и на бэка. На техническом интервью вам обязательно зададут вопрос о паттернах, а на утреннем созвоне с командой нередко прозвучит что-то типа адаптер, фабрика или обсервер. Хотя последнее, возможно, слегка притянуто за уши. Бесспорно, паттерны проектирования - это очередная тема, о которой говорят все, но о доказанной эффективности которых известно достаточно мало деталей.
Сразу оговоримся, что проблематика паттернов связана с ООП и в большей степени с такими языками как Java и C++. Большинство исследований, о которых пойдет речь дальше, рассматривает вопросы применения паттернов именно в этих языках. Однако это не означает, что, например, в JS паттерны будут работать как-то по другому. Вторая оговорка касается предмета нашего интереса. Несмотря на то, что существуют сотни вариаций паттернов проектирования, наибольшей интерес прикован к GoF. Существуют также и ограничения исследований, о которых мы поговорим в самом конце.
Линейка для паттернов
Преимущества паттернов проектирования вроде бы всем очевидны. К ним зачастую относят повышение продуктивности разработчика, быстрый вход для новичков, упрощение коммуникации и повышение качества кода. Из этой четверки нас в большей степени интересует последний фактор. Как говорится, паттерн - это не переиспользование кода, а переиспользование опыта. Очевидно, что опыта создания качественного кода, а не очередных костылей.
Но как нам оценить качество кода? Одним из самых популярных показателей является его поддерживаемость. Осторожно скажем, что если паттерны проектирования и приносят пользу, то только тогда, когда код развивается. В общем виде поддерживаемость кода представляет собой некое качество, тесно связанное с объемом усилий, предпринимаемых для его модификации. Абстрактно, не правда ли? Хотя именно так написано в стандарте ISO-9126.
Давайте посмотрим на то, как конкретизируют это понятие в исследованиях. Wedyan и Abufakher [2020] в своем обзоре весьма детально разложили поддерживаемость кода на ряд составляющих.
Первой из них является условная склонность к изменениям. Чем больше строк требуется для модификации кода и чем больше ошибок возникает в результате таких изменений, тем хуже поддерживаемость. Вторая составляющая - склонность к ошибкам. Чем чаще появляются ошибки в коде и чем сложнее их устранить, тем хуже поддерживаемость. Стабильность является следующим фактором. Она связана с тем, как изменения в окружении влияют на появление ошибок в нашем коде.
Три вышеописанные характеристики поддерживаемости кода являются доминирующими, но не исчерпывающими. Наряду с ними иногда рассматриваются также размер кода, его сложность для чтения, связанность и сцепленность.

Научные исследования
Теперь, когда мы примерно представляем себе то, как оценить качество кода, можно попытаться понять, как именно GoF паттерны влияют на поддерживаемость кода. Одна из первых попыток была предпринята в 2012 году Zhang и Budgen. В своей работе авторы отмечали, что несмотря на популярность темы паттернов в разработке, существовало достаточно небольшое количество эмпирических исследований, многие из которых лишь косвенно изучали применение паттернов в реальном коде. После анализа 219 публикаций ученые пришли к выводу о том, существуют лишь косвенные подтверждения того, что использование паттернов положительно влияет на поддерживаемость кода. Наряду с этим невозможно аргументировано сказать, когда именно необходимо использовать тот или иной паттерн в коде.

Год спустя появилось обзорное исследование [Ampatzoglou, Charalampidou, Stamelos, 2013] 120 публикаций, посвященных GoF паттернам. Оно и по сей день является наиболее полноценным и цитируемым по данной проблематике. И в нем проявились весьма интересные и неоднозначные результаты.
Так, большинство GoF паттернов положительно влияют на некоторые аспекты поддерживаемости кода. Особняком стоит стабильность кода. На нее подавляющее большинств�� паттернов влияет негативно. Однако тут стоит разделять стабильность всего кода и стабильность паттернов. Нам известно, что использование GoF паттернов на примере 65 000 лежащих в открытом доступе Java классов положительно влияет на их стабильность [Ampatzoglou et. al, 2015]. Получается, что паттерны сами по себе стабильны, но за эту стабильность расплачивается окружение.
Возвращаясь к обзорному исследованию стоить подчеркнуть, что авторы решили не останавливаться только на поддерживаемости кода и включили в исследование другие факторы, например, читаемость кода, его адаптивность или надежность. И здесь проявился новый эффект от применения паттернов в коде. Оказалось, что положительно влияя на одни характеристики, паттерны оказывают негативное влияние на другие составляющие качества кода.

Вместо заключения
Стоит отметить, что в последнее время все чаще появляются исследования, которые рассматривают те или иные паттерны по отдельности, а также направлены на изучение сопутствующих факторов, например, документирование паттернов. Однако полноценное обзорное исследование или метаанализ мне на глаза не попадались. Могла ли измениться ситуация за прошедшие с публикации десять лет? Возможно да, а возможно и нет. Стоит ли продолжать уделять внимание паттернам, если нет гарантированного подтверждения их эффективности? Тут уже вам решать.
В конце также хотелось бы упомянуть несколько моментов, которые относятся к рассмотренным выше исследованиям и применению evidence-based подхода к разработке в частности.
Во-первых, код пишут люди, которые отличаются по уровню знаний и опыту. Соответственно, качество кода на выходе у условного джуна будет ниже, чем у условного сеньора. Поэтому на практике мы скорее изучаем связку программист-паттерн, нежели чем анализируем код независимо от его автора.
Во-вторых, паттерны как таковые не являются устойчивыми феноменами. Отсюда возникают проблемы с их унифицированным пониманием, и, в частности, операционализацией для проведения исследований. По мнению одного программиста, у него в коде может быть какой-то паттерн, по мнению другого - нет. Зачастую остается только поверить наслово.
В-третьих, исследования паттернов в основном проводятся на основе опросов профессионалов. Использование объективных метрик весьма незначительно, что добавляет долю субъективности в конечные результаты.
В-четвертых, изучение паттернов в основном производится по отдельности, в отрыве от остального кода. Тогда как на конечное качество кода оказывает их совокупность и синергия.
Что почитать
C. Zhang and D. Budgen, "What Do We Know about the Effectiveness of Software Design Patterns?," in IEEE Transactions on Software Engineering, vol. 38, no. 5, pp. 1213-1231, Sept.-Oct. 2012, doi: 10.1109/TSE.2011.79.
Apostolos Ampatzoglou, Sofia Charalampidou, and Ioannis Stamelos. 2013. Research state of the art on GoF design patterns: A mapping study. J. Syst. Softw. 86, 7 (July, 2013), 1945–1964. https://doi.org/10.1016/j.jss.2013.03.063
A. Ampatzoglou, A. Chatzigeorgiou, S. Charalampidou and P. Avgeriou, "The Effect of GoF Design Patterns on Stability: A Case Study," in IEEE Transactions on Software Engineering, vol. 41, no. 8, pp. 781-802, 1 Aug. 2015, doi: 10.1109/TSE.2015.2414917.
Wedyan, Fadi and Somia Abufakher. “Impact of design patterns on software quality: a systematic literature review.” IET Softw. 14 (2020): 1-17.