NodeJS - (4) : 계층화

­이승환·2021년 9월 24일
0

NodeJS

목록 보기
4/5

프로젝트 구조 설계


이번 포스팅에서는 프로젝트 구조설계에서 가장 중요한 계층화, 특히 Express에 맞추어 한번 정리해보고자 한다.

1-2. 컴포넌트를 계층화하고, Express를 그 경계에 두자

각각의 컴포넌트는 웹, 로직, 데이터 접근코드(DAL) 등을 위한 계층을 분리해야한다. 이것은 예상되는 버그를 잡고, 개발자 입자에서 깨끗하게 역할이 분담되며 모의 객체(mock) 를 만들어 단위 테스트 과정에서 굉장히 유용하다.

예시

router.get('/:banner_id', jwt.graphql.isLoggedIn, async (req, res) => {
   try {
       ///////////// 1. client에서 넘어오는 데이터 처리
       const { banner_id } = req.params; 
       
       ///////////// 2. DB에서 원하는 데이터 조회
       var transaction = await sequelize.transaction();
       const banners = await Banner.findOne({
           where: {
               id: banner_id
           },
           include: [
               {
                   model: Banner_sub_img,
                   order: [
                       ['order', 'ASC']
                   ]
               }
           ],
           transaction
       });
       await transaction.commit();

       ///////////// 3. client에 response 전송
       res.status(200).json(response.success(resMessage.READ_SUCCESS, banners));
   } catch (err) {
       error_handling.normal(err, res, transaction);
   }
});

위와 같이 Get 메소드의 처리를 Express 의 router와 콜백함수 형태를 섞어버리는 것은 최악이다. 일반적인 패턴임에도 불구하고, API 서버 개발자들은 Express req, res 를 비즈니스 로직과 뒤섞어 버리는 경우가 많다.

이것은 어플리케이션 내부 기능들에 서로 의존성을 만들고 Express 를 통해서만 접근이 가능하게하는 단점이 있다. 테스트도 postman을 이용하는 것 외에는 불가능하며(직접 작성하기 까다롭다), 수정시에도 귀찮다는 단점이 있다. Cron 작업의 경우에서 그렇다.

3 Layer Architecture

3 layer architecture는 비즈니스 로직을 분리하는 것을 목적으로 하며 Controller, Service Layer, Data Access Layer 라는 세개의 층으로 나뉜다.

  • Controller : client와 통신에서 필요한 req, res를 처리

  • Service : 비즈니스 로직 처리

  • Data Access Laer : JPA, ORM, MYBATIS.. 데이터베이스 통신 처리

    위 3가지 단계를 나눔으로서의 가장 큰 장점은 확장성이다. 레이어 별로 분리하면 언제든지 필요에 따라 독립적으로 크기를 조정하거나 수정할 수 있다는 장점이 있다.

Controller

  1. 클라이언트의 요청을 받고 서비스에 전달
  2. 서비스에서 작업을 마친 데이터를 다시 클라이언트에 전달
  3. 데이터를 가공하는 등의 비즈니스 로직은 절대 첨가 X
route.post('/', 
  validators.userSignup, // this middleware take care of validation
  async (req, res, next) => {
    // ... The actual responsability of the route layer.
    const userDTO = req.body;

    // ... Call to service layer.
    const { user, company } = await UserService.Signup(userDTO);

    // ... Return a response to client.
    return res.json({ user, company });
});

참고로 이전 포스팅에서 언급한 Express 와 로직의 분리를 위해 req.body를 userDTO로 변경했다.

Service

서비스 계층은 나머지 애플리케이션에서 모든 비즈니스 로직을 캡슐화하고 추상화한다.

해야할 것

  • 비즈니스 로직 포함

  • 데이터 액세스 계층을 활용해서 데이터베이스와 상호 작용

  • Controller 계층에 전달할 데이터를 리턴

    하지 말아야 것

  • req 직접 활용

  • 클라이언트에 대한 res

  • 데이터베이스 접근

module.exports = {
    readAll: () => {
        return new Promise(async (resolve, reject) => {
            // ... User DAL methods
            const city = await City.findAll({});
            if(city.length == 0) {
                resolve({
                    json: utils.successFalse(sc.NO_CONTENT, rm.CITY_EMPTY)
                });
                return;
            }
            if (!city) {
                resolve({
                    json: utils.successFalse(sc.INTERNAL_SERVER_ERROR, rm.CITY_READ_ALL_FAIL)
                });
                return;
            }
            resolve({
                json: utils.successTrue(sc.SUCCESS, rm.CITY_READ_ALL_SUCCESS, city)
            });
        });
    }
}

Data Access Layer

  • 데이터베이스와 상호작용
  • Sequelize 라는 ORM을 사용하는것이 일반적
  • 아니면 쿼리문을 직접 모아서 Service 계층에서 호출해서 사용
profile
Mechanical & Computer Science

0개의 댓글