Антипаттерны (по автору)
Сборник контрарианских позиций автора а о том, что в JS-сообществе считается «хорошей практикой», но он считает антипаттерном.
1. Middleware (Express/Koa-стиль)
См. Middleware Pattern.
Кратко: цепочка обработчиков, мутирующих req/res. Reference pollution, неявное зацепление, race conditions. Решение: Chain of Responsibility + Context Pattern с приватными полями.
2. ORM
«ORM не нужен» — повторяющийся тезис автора.
- ORM скрывает SQL → разработчик не понимает производительность
- Сложные join'ы и денормализованные view плохо ложатся на ORM
- Query Builder — золотая середина
3. EventEmitter как замена promise/callback
«Event-emitter подобен go-to»
- Эмит из одного модуля передаёт управление в неизвестное место
- Зацепление через события неявное, хуже явного
- Тестировать невозможно изолированно — две абстракции вместе
- Решение: использовать
awaitи явные интерфейсы
4. Singleton
«На JavaScript это почти бессмысленная вещь»
- Часто относят к антипаттернам — shared state
- Усложняет тестирование, скрывает зависимости
- В JS заменяется ES-модулями (
export default new X) - Решение: dependency injection вместо синглтона
5. Active Record
«Нарушает SOLID и GRASP, separation of concerns»
- Один класс отвечает за данные и persistence
- Перемешивает domain logic и CRUD
- Решение: DAO или Repository
6. Внешняя MQ для маленькой задачи
«Хватило бы структуры данных в коде»
- Простую очередь между модулями решают подключением Kafka/RabbitMQ
- Лишняя машина, настройка, deploy, мониторинг
- Задача не выходила за рамки одного инстанса приложения
- Решение: in-process queue, паттерны GoF в коде
7. Зависимость от порядка подписчиков на события
«Если нам нужно знать про последовательность подписчиков, у нас уже проблема с архитектурой»
- Завязка на порядок
addEventListener— архитектурный дефект - Эмиттер не знает числа подписчиков (0 или много)
- Решение: явный pipeline вместо событий
8. Декоратор как синтаксис языка вместо паттерна
«Декоратор-синтаксис ≠ GoF-Decorator»
- TS-декораторы постоянно ломали обратную совместимость
@privateв TS ≠ настоящий#field(наследуется как public)- TS приходит к JS-стандарту, но через эмуляции и хаки
- Решение: для метаданных — Reflect.metadata API; для GoF Decorator — обычный класс-обёртка
9. Магические числа в коде стандартной библиотеки
Пример: FixedQueue.BASE_SIZE = 2048 в Node.js — почему именно 2048? Нельзя настроить через options. Лучше — параметризация.
10. Циркулярность там, где не нужна
«Очередь: с одного конца пишем, с другого читаем. Циркулярность избыточна»
- Node.js FixedQueue делает циркулярный буфер, хотя это очередь
- Усложняет логику без выгоды
- Решение: Unrolled list с тремя указателями (Head/Tail/Current)
11. Использовать паттерн ради паттерна
«Если решение не переиспользуется — это не паттерн»
- Делать
class TimerFlyweight { ... }для одного использования — не Flyweight - Это просто код, оверинжиниринг
- Решение: применять паттерн, когда видишь повторяющуюся проблему
12. Завязка на фреймворк вместо моделирования
«Между языком и фреймворком должно быть моделирование»
- Прыгают с языка прямо на фреймворк, пропуская проектирование
- Фреймворк прячет 1-2 паттерна, переименовав их, и считают это архитектурой
- Решение: тренировка моделирования через паттерны до фреймворков
Главные тезисы автора
- Большинство «лучших практик» в JS — упрощения для junior'ов, не оправданные для middle/senior.
- Сложность не исчезает, а перераспределяется. Прячете куда-то — всплывёт.
- Паттерны GoF, SOLID, GRASP — это знания, которые AI не заменит (он их знает, но не понимает применимость).
🎓 Источники
- 🎓 Middleware это антипаттерн · 2026-03-13
- 🎓 Observer Pattern: EventEmitter подобен go-to · 2025-11-06
- 🎓 Anti-patterns common to all paradigms · 2019-10-01
- 🎓 Антипаттерны процедурного программирования · 2019-10-08
- 🎓 OOP Anti-Patterns (Part 1) with JavaScript Examples · 2019-11-21
- 🎓 Active Record, Repository, DAO · 2025-12-16
- 🎓 Шаблон Singleton — почти бессмысленная вещь · 2018-12-10
- 🎓 Зачем GoF, SOLID, GRASP, если есть AI · 2025-12-15
- 🎓 Краткий обзор GoF Patterns · 2025-04-07
- Фреймворки прячут 1-2 паттерна