Ответ
GRASP (General Responsibility Assignment Software Patterns) — это набор принципов для распределения ответственностей в объектно-ориентированном дизайне. В контексте Node.js с его модульной архитектурой, эти принципы помогают создавать поддерживаемый код даже без классических классов.
Применение GRASP в Node.js проектах:
-
Информационный эксперт:
// Сервисный класс, владеющий логикой работы с заказами class OrderService { constructor(orderRepository) { this.orderRepository = orderRepository; } // Этот класс знает как вычислять общую стоимость async calculateTotal(orderId) { const order = await this.orderRepository.findById(orderId); return order.items.reduce((sum, item) => sum + item.price * item.quantity, 0); } } -
Создатель:
// Фабрика создает сложные объекты class LoggerFactory { static create(config) { const transports = [ new transports.File({ filename: config.filePath }), new transports.Console() ]; return new winston.createLogger({ transports }); } } -
Контроллер:
// Express контроллер обрабатывает HTTP запросы class UserController { async createUser(req, res) { try { const userData = req.body; const user = await this.userService.create(userData); res.status(201).json(user); } catch (error) { res.status(400).json({ error: error.message }); } } } -
Низкая связанность: Достигаю через Dependency Injection:
// Вместо жесткой зависимости const paymentService = new PaymentService();
// Использую DI class OrderProcessor { constructor(paymentService, notificationService) { this.paymentService = paymentService; this.notificationService = notificationService; } }
5. **Высокая связность:** Группирую связанные функции в модулях:
```javascript
// auth-module.js
const validateToken = (token) => { /* ... */ };
const generateToken = (user) => { /* ... */ };
const hashPassword = (password) => { /* ... */ };
module.exports = { validateToken, generateToken, hashPassword };
В моих Node.js проектах эти принципы помогают создавать архитектуру, которую легко тестировать и расширять.
Ответ 18+ 🔞
А, GRASP, говоришь? Ну это, блядь, такая штука, чтобы код не превращался в пиздопроебибну, где всё завязано на всё, и ты потом сам от себя охуеешь, когда надо одну кнопку поменять, а у тебя полпроекта накрывается медным тазом.
Короче, это типа свод правил, кто за что в твоей программе должен отвечать. В Node.js, где классов в чистом виде может и не быть, они всё равно пригодятся, чтобы не наделать архитектурного говна.
Как это в Node.js применить:
-
Информационный эксперт (тот, кто всё знает). Отдавай задачу тому модулю или сервису, у которого уже есть все нужные данные. Не тащи данные через всю вселенную, чтобы посчитать хуй с горы.
// Сервис заказов — он и есть главный эксперт по заказам, ёпта. class OrderService { constructor(orderRepository) { this.orderRepository = orderRepository; // Он знает, где данные лежат } // Он же знает, как посчитать итог. Не заставляй контроллер этим заниматься! async calculateTotal(orderId) { const order = await this.orderRepository.findById(orderId); // Вот он, на месте всё делает. Красота. return order.items.reduce((sum, item) => sum + item.price * item.quantity, 0); } } -
Создатель. Если объект сложный, как мартышлюшка с гранатой, не собирай его вручную в десяти местах. Сделай фабрику, которая этим будет заниматься. Доверия к ручному сбору — ноль ебать.
class LoggerFactory { static create(config) { // Вот эта фабрика — она профессиональный создатель логгеров. const transports = [ new transports.File({ filename: config.filePath }), new transports.Console() ]; return new winston.createLogger({ transports }); // И только она знает, как его правильно склепать. } } // А потом везде просто LoggerFactory.create(config). И не еби мозг. -
Контроллер. Это как диспетчер на проходной. Его работа — принять входящий запрос (HTTP, сообщение из очереди), разобрать, позвать нужных экспертов (сервисы), и отправить ответ. Он не должен сам бизнес-логику выполнять, а то получится хитрая жопа, которая всё умеет и ничего не делает нормально.
class UserController { async createUser(req, res) { try { const userData = req.body; // Принял данные const user = await this.userService.create(userData); // Передал эксперту (UserService) res.status(201).json(user); // Отправил ответ } catch (error) { res.status(400).json({ error: error.message }); // Обработал косяк } } } // Видишь? Он не лезет в базу и не хэширует пароли. Он координирует. И всё. -
Низкая связанность. Это святое, ёб твою мать. Твои модули должны знать друг о друге по минимуму. Достигается это через внедрение зависимостей (DI). Не пиши
const payment = new PaymentService()внутри класса. Лучше попроси передать его снаружи.// Плохо: жёсткая привязка. Заменишь PaymentService — придёшь сюда. // const paymentService = new PaymentService(); // Хорошо: зависимость принесли снаружи. Хоть манда с ушами, лишь бы интерфейс подходил. class OrderProcessor { constructor(paymentService, notificationService) { this.paymentService = paymentService; // Мне похуй, что там внутри, главное — плати. this.notificationService = notificationService; // И уведомляй. } } // Теперь OrderProcessor не привязан к конкретным реализациям. Гибко, тестируемо. Красота. -
Высокая связность. А это про то, что всё родственное должно лежать в одном месте. Не размазывай функции для работы с аутентификацией по двадцати файлам. Собери их в одном модуле, чтобы не было волнения ебать, когда ищешь, где же
hashPasswordспрятался.// auth-module.js — здесь живёт ВСЁ про аутентификацию. const validateToken = (token) => { /* ... */ }; const generateToken = (user) => { /* ... */ }; const hashPassword = (password) => { /* ... */ }; module.exports = { validateToken, generateToken, hashPassword }; // Идеально. Открыл один файл — и там всё, что нужно. Связность высокая, как у хорошего коллектива.
Если в своих проектах придерживаться этой простой, блядь, идеи — кто за что отвечает — то код живёт долго и счастливо. Его легче тестировать (подсовываешь заглушки), легче менять (меняешь один эксперт, а не двадцать мест) и легче понимать новым людям. А иначе — пиши пропало, через полгода будешь смотреть на свой же код и думать: «Какого хуя? Кто это писал?».
Видео-ответы
▶
▶
▶
▶
▶
▶