Skip to content
Веб-разработка
GitHub

Создание абстракций

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

Подготовка

Изучить объявление классов, создание экземпляров классов, использование функции конструктора, публичные и приватные поля и методы. Повторить замыкания для функций и модулей.

В этом задании упор делается на организацию и удобство в работе с кодом и упрощением добавления новых путей и методов, с которыми может работать сервер. Для этого потребуется создать классы для приложения и шаблонизатора.

Многоуровневая архитектура

Многоуровневая архитектура или N-уровневая архитектура. Эта архитектура организует приложение на логические уровни, каждый из которых несет определенную ответственность:

  1. Уровень контроллера: принимает запросы от пользователей и взаимодействует с уровнем сервиса.
  2. Уровень сервиса: выполняет операции бизнес-логики и взаимодействует с DAL для доступа к данным.
  3. Уровень доступа к данным (DAL): обрабатывает CRUD-операции с базой данных.

Эта структура помогает разделить задачи и упрощает обслуживание и масштабирование приложения.

Поток в трехуровневой архитектуре

  1. Клиент отправляет запрос.
  2. Соответствующий контроллер получает запрос на основе URL-адреса и метода.
  3. Контроллер вызывает сервис для обработки входящего запроса. В сервис передается необходимый минимум информации.
  4. Сервис запрашивает данные из хранилища.
  5. Сервис обрабатывает данные, извлеченные из хранилища, и возвращает их контроллеру.
  6. Контроллер передает ответ клиенту.

Источники

  1. learn.javascript.ru: Классы
  2. MDN: Классы
  3. learn.javascript.ru: Замыкания
  4. Методы рефакторинга
  5. Node.js project architecture best practices

Практика

Класс приложения

  • В отдельном файле объявите класс VanillaApp, который инкапсулирует логику настройки и работы сервера.
  • Используйте встроенный в Node.js модуль http для создания HTTP-сервера.
  • Реализуйте метод add в классе VanillaApp, который позволяет добавлять новые url и методы HTTP с контроллерами - функции работающие с request, response.
  • Реализуйте метод listen, который запускает сервер на указанном порту и хосте.
  • Реализуйте метод static, который позволяет возвращать статические файлы из папки в качестве ответа.
  • Рассмотрите возможность использования объекта или map для хранения обработчиков маршрутов (url + метод) и соответствующих им функций.

Шаблонизатор

  • В отдельном модуле объявите класс TemplateEngine, который инкапсулирует логику шаблонизации: санитизации html, подстановки значения.
  • Создайте исходный набор правил для санитизации и символы для поиска шаблона, но дайте возможность их менять.
  • Реализуйте метод compile, который принимает строку, а возвращает функцию, которая принимает объект и выполняет подстановку в шаблон.

Правила замены можно задавать в виде массива, например [[/&/g, "&amp;"], [/</g, "&lt;"]].

Контроллеры

Далее код нашего приложения будет разделен на слои. Контроллеры - это первый слой. Задача контроллера (функции) заключается в работе с объектами запроса и ответа, то есть он должен в итоге подготовить корректный ответ для клиента и он вызывает сервисы для получения обработанной информации.

Функции, которые вы передаете в качестве аргумента в метод add, теперь должны храниться в модулях в папке controllers и быть импортированы в основной файл приложения.

Сами контроллеры при вызове должны получать в качестве аргументов объекты запроса и ответа.

Сервисы

В функции сервисного слоя передается необходимый минимум информации от контроллера, далее он выполняет вычисления и возвращает данные контроллеру для подготовки ответа.

В вашем коде логика реализована, ваша задача только корректно ее разделить.

Примерная структура проекта

project/
├── controllers/
│   ├── usersController.js
│   └── ...
├── services/
│   ├── userService.js
│   └── ...
├── app.js
└── package.json

Пример файла app.js

import { Server } from './server.js'
import { TemplateEngine } from './templateEngine.js'
import { rootGetController, rootPostController } from './controllers/rootControllers.js'
import { getAllComments } from './services/commentService.js'

const PORT = 5500
const HOST = '127.0.0.1'
const FILES = { ...}

const myServer = new Server()

myServer.static(FILES)


myServer.add('GET', '/', rootGetController)
myServer.add('POST', '/', rootPostController)


const template = TemplateEngine.compile(template)
myServer.add('GET', '/comment', (req, res) => {
  const data = template(getAllComments())
  res.setHeader('Content-Length', Buffer.byteLength(data))
  res.writeHead(200)
  res.end(data)
})

myServer.listen(PORT, HOST, () => {
  console.log(`Server is running on http://${HOST}:${PORT}`);
})

Тестирование

После рефакторинга должен работать весь функционал из предыдущей работы. Тесты для сервера у вас уже написаны, используйте их для проверки работоспособности кода.

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

Требования к коду и результат выполнения

  • Код отформатирован, не содержит ошибок и замечаний от статического анализа кода ESLint, сохранен в системе контроля версий.
  • Отсутствуют ошибки в консоли.
  • Работающий локально сервер с логикой, которая соответствует требованиям задания.
  • Сервер проходит все тесты.

Вопросы для защиты (3 вопроса по 10 баллов)

  1. Рефакторинг и примеры его методов.
  2. Классы в JS. Объявление, создание экземпляра.
  3. Приватные и публичные поля и методы. Назначение и создание в JS.
  4. Статические методы класса.
  5. Объект this и его работа в классе.
  6. Слоистая архитектура (Layered Architecture). Слои контроллеров и сервисов.