@romaro

Не является ли создание глобального контекста антипаттерном?

Коллеги, интересует вопрос об использовании архитектурного паттерна "глобальный контекст" в веб-серверном приложении (поправьте меня, если есть более подходящее название).

Я имею в виду readonly объект, в который упаковываются часто используемые сервисы, для которых не нужно создавать отдельные инстансы под каждый пользовательский запрос. В моем случае это конфиг, экземпляры провайдеров БД, мейл-сервиса, шаблонизатора, а так же логгер.

Когда я делал свой первый пет-проект на чистом JS, использование такого объекта было не слишком удобно, т.к. приходилось держать в голове его структуру. С переходом на TS эта проблема решается подсказками IDE.

async function GlobalContextConstructor(): Promise<GlobalContext> {
    // Собираю объект глобального контекста
}

GlobalContextConstructor()
    .then(g => {
        // Затем этот объект передается в конструктор сервера
        const server = new FastifyServer(g);
        server.start();
    })
    .catch(err => console.log(err.message));


Теперь объект доступен экземпляру приложения и я могу передавать его в контроллеры, а затем и во все "рабочие" классы. Например, за подготовку html для ответа на get-запрос /about у меня отвечает AboutPage:
// В контроллере создается экземпляр этого класса, в конструктор передается глобальный контекст и контекст http-запроса
const page: IPage = new AboutPage(g, ctx);
const html: string = page.render();


Внутри классов не требуется каждый раз создавать инстанс логгера или импортировать конфиг, т.к. достаточно обратиться к this.g:
this.g.logger.trace('Something happened');

Все это нормально работает, особенно в связке с TS, но меня интересуют две вещи:
1) не является ли такой подход антипаттерном? Есть ощущение, что он противоречит идее модульности.
2) улучшается ли производительность за счет того, что экземпляры классов не пересоздаются? Например, не нужно поднимать инстанс мейлера перед отправкой письма, т.к. экземпляр этой службы создается однократно при старте приложения.

Второй вопрос я задаю потому, что предполагаю наличие в интерпретаторе каких-то кешей для таких случаев.
  • Вопрос задан
  • 119 просмотров
Пригласить эксперта
Ответы на вопрос 2
Alexandroppolus
@Alexandroppolus
кодир
Да, такой подход считается антипаттерном.

Истинный путь - вот он
Ответ написан
Комментировать
Maksclub
@Maksclub
maksfedorov.ru
в Golang, например, контекст есть на уровне стандартной библиотеки (нужен для управления конкурентными сущностями (закрытие как правило)), а на уровне http роутеров — контекст используют как контейнер для значений почти все реализации, тк через жизненный цикл запроса протаскивать значения — типовая задача роутера

в целом, вам нужно минимизировать такое явление. Если http-контекст остается только в http слое, то ваша задумка покушается на бизнес-логику. В бизнес-логике никакого контекста быть не может, если у вас есть конфиги или что-то такое — это часть контракта, просто его вы задаете в конфиге и инжектите ту часть контракта, что нужна
Ответ написан
Ваш ответ на вопрос

Войдите, чтобы написать ответ

Войти через центр авторизации
Похожие вопросы