0 added
0 removed
Original
2026-01-01
Modified
2026-02-26
1
<p>До сих пор мы пользовались фреймворком Express как чёрным ящиком. Что, кстати, характеризует его как хорошую абстракцию. Но помимо очевидного внешнего поведения у микрофреймворков есть ещё одно интересное свойство. Давайте зададим себе вопрос: какими качествами должен обладать хороший фреймворк?</p>
1
<p>До сих пор мы пользовались фреймворком Express как чёрным ящиком. Что, кстати, характеризует его как хорошую абстракцию. Но помимо очевидного внешнего поведения у микрофреймворков есть ещё одно интересное свойство. Давайте зададим себе вопрос: какими качествами должен обладать хороший фреймворк?</p>
2
<p>Самое очевидное и важное - это концептуальный дизайн, который определяет то, с какими абстракциями мы имеем дело. Бывают фреймворки, в которых абстракции не очень удачные, и разработка на них обрастает<strong>случайной сложностью</strong>. С другой стороны, в вебе более-менее выработан единый подход к организации серверных фреймворков. Доминирующей является архитектура MVC, с которой мы и работаем. Controller - контроллеры это наши обработчики, View - это шаблоны, а Model - это наши сущности и бизнес-логика.</p>
2
<p>Самое очевидное и важное - это концептуальный дизайн, который определяет то, с какими абстракциями мы имеем дело. Бывают фреймворки, в которых абстракции не очень удачные, и разработка на них обрастает<strong>случайной сложностью</strong>. С другой стороны, в вебе более-менее выработан единый подход к организации серверных фреймворков. Доминирующей является архитектура MVC, с которой мы и работаем. Controller - контроллеры это наши обработчики, View - это шаблоны, а Model - это наши сущности и бизнес-логика.</p>
3
<p><em>Замечание. Исторически MVC, который принят в вебе, сильно отличается от первоначального MVC, основное применение которого было толстые клиенты. В литературе можно встретить обозначение "MVC v2" для веб версии.</em></p>
3
<p><em>Замечание. Исторически MVC, который принят в вебе, сильно отличается от первоначального MVC, основное применение которого было толстые клиенты. В литературе можно встретить обозначение "MVC v2" для веб версии.</em></p>
4
<p>Если предположить, что с дизайном всё в порядке, то на сцену выходят более утилитарные качества:</p>
4
<p>Если предположить, что с дизайном всё в порядке, то на сцену выходят более утилитарные качества:</p>
5
<ul><li>Гибкость</li>
5
<ul><li>Гибкость</li>
6
<li>Расширяемость</li>
6
<li>Расширяемость</li>
7
<li>Модульность</li>
7
<li>Модульность</li>
8
</ul><p>В этом месте мы поговорим о расширяемости, которая в свою очередь приводит к модульности. Рассмотрим самый простой пример - функции. Как можно расширить поведение функции?</p>
8
</ul><p>В этом месте мы поговорим о расширяемости, которая в свою очередь приводит к модульности. Рассмотрим самый простой пример - функции. Как можно расширить поведение функции?</p>
9
<h2>Wrapping</h2>
9
<h2>Wrapping</h2>
10
<p>Нет ничего проще, чем расширять поведение функции. Нужно написать новую функцию, в которой используется первоначальная. Единственное условие, которое нужно соблюсти, это совпадение входов этих функций (количество и тип аргументов) и выходов (тип выхода). В таком случае код, использующий вашу обёрнутую функцию, даже не сможет догадаться о том, что она обёрнута, ну а главное, что его не нужно переписывать, ведь интерфейс функции не поменялся, хотя и появилось новое поведение. Такой способ так же называют декорированием, и в справочниках по шаблонам проектирования описывают как "паттерн декоратор".</p>
10
<p>Нет ничего проще, чем расширять поведение функции. Нужно написать новую функцию, в которой используется первоначальная. Единственное условие, которое нужно соблюсти, это совпадение входов этих функций (количество и тип аргументов) и выходов (тип выхода). В таком случае код, использующий вашу обёрнутую функцию, даже не сможет догадаться о том, что она обёрнута, ну а главное, что его не нужно переписывать, ведь интерфейс функции не поменялся, хотя и появилось новое поведение. Такой способ так же называют декорированием, и в справочниках по шаблонам проектирования описывают как "паттерн декоратор".</p>
11
<p>По похожей идее устроен Express, а точнее connect, который является ядром микрофреймворка Express.</p>
11
<p>По похожей идее устроен Express, а точнее connect, который является ядром микрофреймворка Express.</p>
12
<h2>Connect</h2>
12
<h2>Connect</h2>
13
<h2>Middleware</h2>
13
<h2>Middleware</h2>
14
<p>Connect представляет из себя механизм, который расширяется функциями, называемыми middleware. Каждый раз, когда мы используем use, очередная middleware добавляется в общую очередь. В конечном счёте получается объект, наполненный мидлварами. Каждый запрос, отправляемый на обработку в connect, проходит через цепочку этих middleware пока не наткнётся на терминальную мидлвару.</p>
14
<p>Connect представляет из себя механизм, который расширяется функциями, называемыми middleware. Каждый раз, когда мы используем use, очередная middleware добавляется в общую очередь. В конечном счёте получается объект, наполненный мидлварами. Каждый запрос, отправляемый на обработку в connect, проходит через цепочку этих middleware пока не наткнётся на терминальную мидлвару.</p>
15
<p>В свою очередь каждая мидлвара принимает на вход три параметра: request, response и next. Она может поменять их и в конце должна вызвать next для передачи управления следующей по списку мидлваре. В этом и заключается вся мощь микрофреймворков. Удачный дизайн позволяет легко разбивать систему на модули-мидлвары и расширять за счёт мидлвар, которые, в большом количестве, пишут сторонние разработчики.</p>
15
<p>В свою очередь каждая мидлвара принимает на вход три параметра: request, response и next. Она может поменять их и в конце должна вызвать next для передачи управления следующей по списку мидлваре. В этом и заключается вся мощь микрофреймворков. Удачный дизайн позволяет легко разбивать систему на модули-мидлвары и расширять за счёт мидлвар, которые, в большом количестве, пишут сторонние разработчики.</p>
16
<p>В Connect нет ничего кроме метода use добавляющего очередную мидлвару в стек.</p>
16
<p>В Connect нет ничего кроме метода use добавляющего очередную мидлвару в стек.</p>
17
<h2>Mount middleware</h2>
17
<h2>Mount middleware</h2>
18
<p>Самое интересное в Connect, что обработчики конкретных маршрутов - это тоже, всего-навсего, мидлвары. Их особенностью является привязка к конкретному маршруту, в отличие от мидлвар, которые выполняются для всех запросов.</p>
18
<p>Самое интересное в Connect, что обработчики конкретных маршрутов - это тоже, всего-навсего, мидлвары. Их особенностью является привязка к конкретному маршруту, в отличие от мидлвар, которые выполняются для всех запросов.</p>
19
<p>Такие мидлвары позволяют реализовывать базовый роутинг без привязки к конкретному глаголу http и без поддержки динамических маршрутов. В Express роутинг реализован без привязки к Mount Middlewares.</p>
19
<p>Такие мидлвары позволяют реализовывать базовый роутинг без привязки к конкретному глаголу http и без поддержки динамических маршрутов. В Express роутинг реализован без привязки к Mount Middlewares.</p>
20
<h2>Terminate</h2>
20
<h2>Terminate</h2>
21
<p>Но далеко не всегда мы хотим двигаться вглубь. Более того, в какой-то момент одна из мидлвар должна взять обработку на себя.</p>
21
<p>Но далеко не всегда мы хотим двигаться вглубь. Более того, в какой-то момент одна из мидлвар должна взять обработку на себя.</p>
22
<p>У такого поведения, когда есть цепочка функций и любая из них в процессе обработки может принять решение остановки цепочки и возврата ответа, есть имя. Такие цепочки называют chain responsibility, и это тоже паттерн.</p>
22
<p>У такого поведения, когда есть цепочка функций и любая из них в процессе обработки может принять решение остановки цепочки и возврата ответа, есть имя. Такие цепочки называют chain responsibility, и это тоже паттерн.</p>