Node.js의 레이어 패턴 (Layered Pattern)
레이어패턴이란?
레이어 패턴은 소프트웨어 아키텍처 디자인 패턴 중 하나로, 애플리케이션을 서로 다른 관심사 별로 분리된 레이어로 나누어 관리하는 방식을 의미합니다. 이 패턴은 각 레이어간의 높은 응집도와 낮은 결합도를 유지하면서, 유지 보수와 확장성을 향상시키기 위해 사용됩니다.
레이어 패턴(layered pattern)을 사용하는 이유
1.모듈성 (Modularity): 레이어 패턴을 사용하면 애플리케이션을 독립적인 단위로 분할할 수 있습니다. 이를 통해 각 레이어는 자신의 관심사에만 집중할 수 있습니다.
2.관심사의 분리 (Separation of Concerns): 각 레이어는 명확하게 정의된 책임을 가집니다. 예를 들어, 데이터 액세스 레이어는 데이터베이스와의 통신에만 집중하며, 비즈니스 로직 레이어는 비즈니스 규칙의 실행에만 집중합니다.
3.재사용성 (Reusability): 레이어를 독립적으로 개발하면 다른 프로젝트나 애플리케이션에서 해당 레이어를 재사용하기 쉽습니다.
4.확장성 (Scalability): 애플리케이션의 특정 부분이나 레이어를 확장해야 할 경우, 해당 레이어만 수정하거나 확장하면 됩니다. 다른 부분의 코드는 거의 그대로 유지될 수 있습니다.
5.유지보수성 (Maintainability): 각 레이어는 독립적으로 유지보수될 수 있습니다. 예를 들어, 데이터베이스 액세스 방법이 변경될 경우 데이터 액세스 레이어만 수정하면 되며, 비즈니스 로직에는 영향을 주지 않습니다.
6.테스트 용이성 (Testability): 관심사가 분리되어 있기 때문에, 각 레이어를 독립적으로 테스트하기가 쉽습니다.
7.유연성 (Flexibility): 필요에 따라 특정 레이어를 대체하거나 업그레이드하는 것이 쉽습니다. 예를 들어, 다른 종류의 데이터베이스 시스템을 사용하려는 경우, 데이터 액세스 레이어만 변경하면 됩니다.
// routes/userRoutes.js
const express = require('express');
const userController = require('../controllers/userController');
const router = express.Router();
router.post('/create', userController.createUser);
module.exports = router;
Routes (라우트):
- 역할: 들어오는 HTTP 요청과 해당 요청을 처리할 컨트롤러 함수를 연결하는 역할을 합니다.
- 특징: URL 경로, HTTP 메서드(GET, POST, PUT, DELETE 등)에 따라 적절한 컨트롤러 함수를 호출합니다.
// controllers/userController.js
const userService = require('../services/userService');
const createUser = async (req, res) => {
const userId = req.body;
const user = await userService.createUser(userId);
res.status(201).send(user);
};
module.exports = {
createUser
};
Controllers (컨트롤러):
- 역할: 사용자의 요청을 받아 처리하고, 적절한 응답을 반환하는 로직을 관리합니다.
- 특징: Service 레이어나 Model을 호출하여 비즈니스 로직을 수행하고 결과를 View에 전달하거나 API 응답으로 반환합니다.
// services/userService.js
const UserModel = require('../models/user');
const createUser = async (userId) => {
return await UserModel.create(userId);
};
module.exports = {
createUser
};
Services (서비스):
- 역할: 비즈니스 로직의 수행을 담당합니다.
- 특징: 컨트롤러와 모델 사이에서 중재자 역할을 합니다. 복잡한 로직, 계산, 여러 모델의 조합 등의 작업을 수행하며, 컨트롤러는 이 서비스를 호출하여 필요한 작업을 진행합니다.
const { DataSource } = require("typeorm");
const AppDataSource = new DataSource({
type: 'you_db_type',
host: 'you_db_host',
port: 'you_db_port',
host: 'your_db_host',
user: 'your_db_user',
password: 'your_db_password',
database: 'your_db_name'
});
const create = async (userId) => {
try {
const result = await AppDataSource.query(
`
INSERT INTO users (
userId
) VALUES (
?
)
`,
[userId]
);
return result;
} catch{
const error = new Error("dataSource Error");
error.statusCode = 400;
throw error;
}};
Models (모델):
- 역할: 데이터의 구조, 유효성 검사, 데이터베이스와의 통신 등의 로직을 담당합니다.
- 특징: ORM(Object-Relational Mapping) 라이브러리나 데이터베이스 드라이버와 직접 연동되어 CRUD(Create, Read, Update, Delete) 작업을 수행합니다.