Признаюсь честно: однажды я построил рабочий API, используя только основные модули Node.js. Когда коллеги это увидели, их реакции варьировались от «Ты просто маньяк!» до «Погоди… это и правда работает?». Спойлер: всё работало. Хотя такие фреймворки, как Express или NestJS, — это замечательная страховка, иногда только отказ от них помогает понять, как всё работает на самом деле.

Скрытые издержки удобства фреймворков

Потеря производительности

Фреймворки включают в себя всё, что только можно представить. Тот самый Express-приложе́ние «hello world» размером в 40 КБ? Вот версия на голом Node.js:

const http = require('http');
const server = http.createServer((req, res) => {
  res.end('Hello Framework-Free World!');
});
server.listen(3000);

Это 5 строк кода против 15+ в Express. Для микросервисов с высокой нагрузкой такое различие накапливается, как проценты на ростовщической конвенции.

Иллюзия продуктивности

Фреймворки обещают скорость, но отладка сбоев в парсинге req.body в 2 часа ночи кажется разгадыванием загадок для сфинкса. Из жизни: однажды я потратил 3 часа на отладку конфликта промежуточного ПО в Express, что заняло бы 10 минут с нативным http.

graph LR A[Разработчик] --> B[Фреймворк] B --> C{Чёрный ящик} C --> D[Ад отладки] C --> E[Потеря производительности]

Опасность атрофии навыков

Полагаться на ReactDOM.render(), не понимая DOM, — это как использовать кухонный комбайн для нарезки клубники. Когда во время недавнего проекта произошёл сбой в системе синтетических событий React, наше общее молчание на вопрос «Как на самом деле работает всплытие событий в браузере?» было оглушительным.

Когда стоит писать код без фреймворков

Сценарий 1: Микросервисы на стероидах

Создаёте высокопроизводительный аналитический эндпоинт? Сравните:

ПодходЗапросы/секИспользование памяти
Express.js8 50045 МБ
Нативный Node.js14 20028 МБ
(Тестировалось на AWS t3.micro, Node 21)

Нативная версия использует всего 3 модуля: http, url и querystring. Без body-parser, без cookie-session, без 57 зависимостей node_modules.

Сценарий 2: Изучение устройства

Попробуйте такой вызов: создайте REST API без какого-либо фреймворка, а затем воссоздайте его с Express. Этот процесс покажет, что абстрагируют фреймворки — как будто вы видите матрицу за цифровым дождём.

Пошаговое нативное маршрутизирование

  1. Парсинг URL вручную:
const { pathname, query } = new URL(req.url, `http://${req.headers.host}`);
  1. Обработка маршрутизации становится явной:
if (pathname === '/users' && req.method === 'GET') {
  // Получение пользователей из БД
}
  1. Промежуточное ПО? Просто функции:
const logger = (req, res, next) => {
  console.log(`${new Date().toISOString()} - ${req.method} ${req.url}`);
  next(req, res); // Ручной вызов next()
};

Искусство стратегического бунта

Практическое правило

Если в вашем проекте меньше 5 маршрутов и в следующем квартале вам не понадобятся GraphQL/Auth0/WebSockets, пропустите фреймворк.

Исключения, подтверждающие правило

  • Создаёте корпоративное SaaS? Используйте фреймворк.
  • Срок сдачи через 48 часов? Используйте фреймворк.
  • Изучаете WebSockets? Сначала напишите свой, а затем используйте Socket.io.

Заключение: примите осознанную примитивность

Фреймворки похожи на GPS: они прекрасны для неизведанной территории, но иногда нужно ориентироваться по звёздам, чтобы вспомнить, как соединяются континенты. В прошлом месяце наша команда создала WebSocket-сервер без библиотек. Первоначальное разочарование было настоящим, но обнаружение элегантности net.createServer() было как находка секретной двери в доме детства.

Так что в следующий раз, когда будете выполнять npm install, спросите себя: «Нужен ли мне этот парашют для прыжка в подвал?» Иногда сырой код не просто легче — он освобождает.