Ответ
Layered Architecture — это классический паттерн организации кода приложения, где ответственность разделена на горизонтальные слои. В Node.js-проектах это помогает поддерживать порядок, особенно в больших приложениях на Express.js или аналогичных фреймворках.
Типичные слои в Node.js-приложении:
- Слой представления/контроллеров (Presentation/Controller Layer): Обрабатывает HTTP-запросы и ответы. Его задача — валидация ввода, вызов бизнес-логики и форматирование вывода.
- Слой сервисов/бизнес-логики (Service/Business Logic Layer): Содержит ядро приложения — правила, алгоритмы, orchestration между разными сущностями.
- Слой доступа к данным (Data Access Layer / Repository): Инкапсулирует всю работу с источниками данных (базы данных, внешние API, кэш).
Пример структуры проекта Express.js:
src/
├── controllers/ # Presentation Layer
│ └── userController.js
├── services/ # Business Logic Layer
│ └── userService.js
├── repositories/ # Data Access Layer
│ └── userRepository.js
├── models/ # Data Models (например, Mongoose схемы)
└── app.js
Пример кода:
// repositories/userRepository.js (Data Access Layer)
const UserModel = require('../models/User');
class UserRepository {
async findById(id) {
return await UserModel.findById(id).lean(); // Используем Mongoose
}
async create(userData) {
const user = new UserModel(userData);
return await user.save();
}
}
module.exports = UserRepository;
// services/userService.js (Business Logic Layer)
const UserRepository = require('../repositories/userRepository');
class UserService {
constructor() {
this.userRepo = new UserRepository();
}
async registerUser(email, password) {
// 1. Проверка бизнес-правил
if (!this.isValidEmail(email)) {
throw new Error('Invalid email format');
}
// 2. Хеширование пароля (бизнес-логика безопасности)
const hashedPassword = await bcrypt.hash(password, 10);
// 3. Делегирование сохранения в репозиторий
const user = await this.userRepo.create({ email, password: hashedPassword });
// 4. Дополнительные действия (отправка welcome email и т.д.)
await this.sendWelcomeEmail(user.email);
return user;
}
}
module.exports = UserService;
// controllers/userController.js (Presentation Layer)
const UserService = require('../services/userService');
const userService = new UserService();
const userController = {
async createUser(req, res, next) {
try {
const { email, password } = req.body;
// Валидация ввода (можно использовать Joi или express-validator)
if (!email || !password) {
return res.status(400).json({ error: 'Email and password are required' });
}
// Вызов бизнес-логики
const newUser = await userService.registerUser(email, password);
// Форматирование ответа
res.status(201).json({
message: 'User created',
userId: newUser._id
});
} catch (error) {
next(error); // Проброс ошибки в middleware обработки ошибок
}
}
};
module.exports = userController;
Преимущества в Node.js:
- Тестируемость: Сервисы и репозитории можно легко тестировать изолированно с помощью моков (Jest, Sinon).
- Замена технологий: Можно сменить базу данных (с MongoDB на PostgreSQL), переписав только репозиторий, не затрагивая бизнес-логику.
- Читаемость: Код организован по функциональному признаку.
Недостатки:
- Over-engineering для мелких проектов: Для простого CRUD API может создавать излишнюю сложность.
- Potential для «анемичных» сервисов: Если вся логика просто передаёт данные между слоями, это становится бесполезным абстракцией.