Что такое паттерны проектирования и зачем они нужны

При работе с кодом больше всего времени уходит на его чтение и понимание, а не написание. Код — не только инструкция для компьютера, но и объяснение ваших намерений другим людям. Если написать хаотичный, но работающий код, то другим разработчикам станет труднее понимать его и вносить осмысленные изменения.

Что такое паттерн?

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

Сила паттернов

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

Некоторые паттерны относятся только к JS или React, а часть из них, как структуры данных и алгоритмы, можно реализовать в любом языке программирования.

«Идеального» паттерна не существует. Каждый проект, приложение или программа индивидуальны и поэтому для принятия решения, какой паттерн использовать (или не использовать), нужно оценить, какую выгоду паттерн может дать.

Преимущества паттернов

Что такое антипаттерн?

Антипаттерн, в противоположность паттерну, это плохое решение проблемы, которое может и решать её, но в долгую приводит ухудшению качества кода. Хорошая сторона антипаттера — он явно отвечает на вопрос «как не надо делать». Часто бывает так, что релиз требуется здесь и сейчас, что приводит к появлению временных решений и добавлению «костылей». Если ими злоупотреблять, то накопится большой техдолг, состоящий из антипаттернов, который ухудшает ситуацию по всем фронтам.

Антипаттерн

Категории паттернов

«Классические» паттерны (из легендарной книги Design Patterns: Elements of Reusable Object-Oriented Software) относятся прежде всего к объектно-ориентированному программированию, их можно разделить на три категории:

  1. Порождающие (Creational)
  2. Структурные (Structural)
  3. Поведенческие (behavioral)

Порождающие паттерны

Этот вид паттернов фокусируется на механизме создания объектов, порождающие паттерны позволяют контролировать этот процесс. Например:

К порождающим относятся паттерны: Constructor, Factory, Abstract, Prototype, Singleton, Builder.

Структурные паттерны

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

К структурным паттернам относятся: Decorator, Facade, Flyweight, Adapter, Proxy.

Поведенческие паттерны

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

К поведенческим паттернам относятся: Iterator, Mediator, Observer, State, Visitor.

Паттерны в JS и вокруг него

Так как «классические» паттерны ориентированы прежде всего на объектно-ориентированное программирование, то не все их них могут быть одинаково полезны в контексте JS или React.

А некоторые паттерны, наоборот, появились благодаря JS/React или нативно реализованы в них. Например, паттерн Module — модульная система встроена в сам язык ES2015, а паттерн Headless Component — более высокоуровневый паттерн, который можно реализовать не только в React, но и в других библиотеках и фреймворках.

Другие паттерны, например, State Machine или Signal — это логическое развитие «классических» паттернов в современных библиотеках и фреймворках.

Отдельно выделяются паттерны асинхронного программирования Promise, Async/await специфичные для JS, но присутствующие и в других средах и языках.

Ещё более высокоуровневые, архитектурные паттерны помогают выстраивать вокруг определённой идеи целиком все взаимосвязи и поток данных внутри клиентского или клиент-серверного приложения: например, это паттерны MVC, MVP, MVVM, которые обычно реализуются уже на уровне фреймворков.