PurpleSchool — курсы программирования онлайн
  • Пути
    • Frontend React разработчик
    • Frontend Vue разработчик
    • Backend разработчик Node.js
    • Fullstack разработчик React / Node.js
    • Mobile разработчик React Native
    • Backend разработчик Golang
    • Devops инженер
    • Backend разработчик Python
  • AI для кодаНовое
  • О нас
    • Отзывы
    • Реферальная программа
    • О компании
    • Контакты
  • Иконка открытия меню
    • Сообщество
    • PurpleПлюс
    • AI Собеседование
    • AI тренажёр
    • Проекты
PurpleSchool — платформа бесплатных roadmap и курсов для разработчиков
ютуб иконка
Telegram иконка
VK иконка
VK иконка
Курсы
ГлавнаяКаталог курсовFrontendBackendFullstack
Практика
КарьераПроектыPurpleПлюс
Материалы
БлогБаза знаний
Документы
Договор офертаПолитика конфиденциальностиПроверка сертификатаМиграция курсовРеферальная программа
Реквизиты
ИП Ларичев Антон АндреевичИНН 773373765379contact@purpleschool.ru

PurpleSchool © 2020 -2026 Все права защищены

  • Курсы
    • FrontendИконка стрелки
    • AI разработкаИконка стрелки
    • BackendИконка стрелки
    • DevOpsИконка стрелки
    • MobileИконка стрелки
    • ТестированиеИконка стрелки
    • Soft-skillsИконка стрелки
    • ДизайнИконка стрелки
    Иконка слояПерейти в каталог курсов
  • Бесплатно
    • Курсы
    • JavaScript Основы разработкиPython Основы PythonCSS CSS FlexboxКарта развитияВопросы для собеседований
    • База знанийИконка стрелки
    • Новостные рассылкиИконка стрелки
  • PurpleSchool — курсы программирования онлайн
    • AI для кодаНовое
    • Сообщество
    • PurpleПлюс
    • AI Собеседование
    • AI тренажёр
    • Проекты
    Главная
    Сообщество
    Архитектура Node.js: слои, модули и Dependency Injection

    Архитектура Node.js: слои, модули и Dependency Injection

    Аватар автора Архитектура Node.js: слои, модули и Dependency Injection

    Антон Ларичев

    Иконка календаря08 июня 2026
    Node.jsАрхитектураBackendDependency InjectionmiddleИконка уровня middle
    Картинка поста Архитектура Node.js: слои, модули и Dependency Injection

    Введение

    Когда Node.js проект вырастает из учебного «hello world» в реальный продукт, привычный подход «всё в одном файле» начинает мешать. Контроллеры обращаются к базе напрямую, бизнес-логика переплетается с HTTP-слоем, а тесты превращаются в боль. Решение — продуманная архитектура: разделение на слои, выделение модулей и внедрение зависимостей (Dependency Injection, DI).

    В этой статье разберём, как организовать Node.js приложение так, чтобы оно оставалось гибким при росте кодовой базы, легко тестировалось и позволяло безболезненно менять реализации компонентов.

    Слоистая архитектура

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

    • Controller (Presentation) — принимает HTTP-запросы, валидирует входные данные, формирует ответ.
    • Service (Business Logic) — содержит бизнес-правила, не знает про HTTP и базу данных.
    • Repository (Data Access) — работает с источником данных: ORM, SQL, внешние API.
    • Domain (Entity) — модели предметной области и инварианты.

    Главное правило: зависимости направлены строго вниз. Контроллер знает о сервисе, сервис — о репозитории. Обратные связи запрещены.

    // controllers/user.controller.js
    export class UserController {
      constructor(userService) {
        // зависимость передана извне
        this.userService = userService;
      }
    
      async getById(req, res) {
        const user = await this.userService.findById(req.params.id);
        if (!user) return res.status(404).json({ error: 'Not found' });
        res.json(user);
      }
    }
    
    // services/user.service.js
    export class UserService {
      constructor(userRepository) {
        this.userRepository = userRepository;
      }
    
      async findById(id) {
        // здесь только бизнес-логика, без HTTP и SQL
        return this.userRepository.findById(id);
      }
    }
    

    Модули и границы

    Слои описывают «горизонтальное» деление. Но при росте проекта важнее «вертикальное» — по доменам или фичам. Это называется модульной (feature-based) структурой.

    src/
      users/
        user.controller.js
        user.service.js
        user.repository.js
        user.model.js
      orders/
        order.controller.js
        order.service.js
        order.repository.js
      shared/
        logger.js
        db.js
    

    Каждый модуль самодостаточен: имеет собственный слой данных, бизнес-логики и контроллеров. Общение между модулями идёт через явные публичные интерфейсы, а не через прямой импорт внутренних файлов соседа.

    Dependency Injection: зачем и как

    Dependency Injection — это паттерн, при котором объект получает свои зависимости извне, а не создаёт их сам. Без DI код выглядит так:

    // плохо: жёсткая связь
    import { db } from '../db.js';
    
    export class UserService {
      async findById(id) {
        return db.query('SELECT * FROM users WHERE id = $1', [id]);
      }
    }
    

    Здесь сервис намертво привязан к конкретному инстансу базы. Замокать его в тестах сложно, заменить Postgres на MongoDB — почти нереально.

    С DI зависимости передаются через конструктор:

    // хорошо: зависимость инжектируется
    export class UserService {
      constructor(userRepository) {
        this.userRepository = userRepository;
      }
    
      async findById(id) {
        return this.userRepository.findById(id);
      }
    }
    

    Теперь сервис не знает, откуда берутся данные — это решает тот, кто его собирает.

    Простейший DI-контейнер

    Для небольшого проекта достаточно ручной сборки в одной точке (composition root):

    // container.js
    import { Pool } from 'pg';
    import { UserRepository } from './users/user.repository.js';
    import { UserService } from './users/user.service.js';
    import { UserController } from './users/user.controller.js';
    
    const pool = new Pool({ connectionString: process.env.DATABASE_URL });
    
    const userRepository = new UserRepository(pool);
    const userService = new UserService(userRepository);
    const userController = new UserController(userService);
    
    export { userController };
    

    Для более крупных приложений подойдут библиотеки вроде awilix, tsyringe или встроенный DI в NestJS.

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

    DI делает юнит-тесты тривиальными — достаточно передать заглушку:

    import { test } from 'node:test';
    import assert from 'node:assert';
    import { UserService } from './user.service.js';
    
    test('возвращает пользователя по id', async () => {
      // мок-репозиторий вместо настоящего
      const fakeRepo = {
        findById: async (id) => ({ id, name: 'Anna' }),
      };
      const service = new UserService(fakeRepo);
    
      const user = await service.findById(1);
      assert.strictEqual(user.name, 'Anna');
    });
    

    Частые ошибки

    • Сквозные импорты слоёв. Контроллер тянет репозиторий напрямую — слоистость нарушена, бизнес-логика размазывается по проекту.
    • «Анемичные» сервисы. Сервис превращается в тонкую прокладку, которая просто вызывает репозиторий — это знак, что логику стоит вынести в доменные модели.
    • Глобальные синглтоны. Импорт готового инстанса базы или логгера из модуля убивает тестируемость и плодит скрытые зависимости.
    • Слишком ранняя абстракция. Не стоит писать пять интерфейсов «на вырост» для маленького проекта — DI вводится тогда, когда появляется реальная боль с тестами или заменой реализации.
    • DI-контейнер как сервис-локатор. Если компоненты сами достают зависимости из контейнера, это уже не DI, а антипаттерн Service Locator.

    Заключение

    Грамотная архитектура Node.js приложения строится на трёх китах: разделении на слои с однонаправленными зависимостями, модульной организации по доменам и внедрении зависимостей через конструкторы. Такой подход даёт предсказуемую структуру, простое тестирование и возможность менять реализации без переписывания половины кода.

    Начните с малого: вынесите бизнес-логику из контроллеров в сервисы, отделите работу с данными в репозитории и передавайте зависимости явно. Когда проект подрастёт — добавьте DI-контейнер. Архитектура должна служить задаче, а не наоборот.

    Иконка глаза483

    Комментарии

    0

    Постройте личный план изучения Основы Git до уровня Middle — бесплатно!

    Основы Git — часть карты развития Frontend, Backend, DevOps

    • step100+ шагов развития
    • lessons30 бесплатных лекций
    • lessons300 бонусных рублей на счет

    Бесплатные лекции

    Лучшие курсы по теме

    изображение курса

    HTML и CSS

    Антон Ларичев
    AI-тренажерыAI-тренажеры
    Практика в студииПрактика в студии
    Гарантия
    Бонусы
    иконка звёздочки рейтинга4.9
    3 999 ₽ 6 990 ₽
    Подробнее
    изображение курса

    CSS Flexbox

    Антон Ларичев
    Гарантия
    Бонусы
    иконка звёздочки рейтинга4.9
    бесплатно
    Подробнее
    изображение курса

    Основы JavaScript

    Антон Ларичев
    AI-тренажерыAI-тренажеры
    Практика в студииПрактика в студии
    Гарантия
    Бонусы
    иконка звёздочки рейтинга4.8
    3 999 ₽ 6 990 ₽
    Подробнее

    Похожие статьи

    Картинка поста Как установить Node.js на Windows: пошаговая инструкция
    Иконка аватараАнтон
    Иконка календаря17 июля 2026
    Node.jsWindowsnpm+ 2juniorИконка уровня junior

    Как установить Node.js на Windows: пошаговая инструкция

    Как установить Node.js на Windows — пошаговая инструкция через официальный установщик и nvm-windows с разбором частых ошибок.

    Иконка чипа0
    Иконка глаза176
    Иконка комментариев0
    Картинка поста CI/CD с GitHub Actions: автоматизация деплоя для начинающих
    Иконка аватараАнтон
    Иконка календаря03 июля 2026
    CI/CDGitHub ActionsDevOps+ 2juniorИконка уровня junior

    CI/CD с GitHub Actions: автоматизация деплоя для начинающих

    CI/CD с GitHub Actions: пошаговая настройка pipeline для автоматического тестирования и деплоя Node.js-приложений без сторонних сервисов.

    Иконка чипа0
    Иконка глаза195
    Иконка комментариев0
    Картинка поста JWT токены: структура, работа и аутентификация в Node.js
    Иконка аватараАнтон
    Иконка календаря01 июля 2026
    JWTаутентификацияNode.js+ 2juniorИконка уровня junior

    JWT токены: структура, работа и аутентификация в Node.js

    JWT токены — стандарт для безопасной передачи данных между клиентом и сервером. Разбираем структуру, реализацию и частые ошибки.

    Иконка чипа0
    Иконка глаза204
    Иконка комментариев0
    Иконка чипа0