TIL#54 Node) Layered Pattern

luneah·2021년 12월 21일
0

Node

목록 보기
6/6
post-thumbnail

Layered Pattern

모듈화가 필요한 이유

모듈화 : 역할에 따라 코드를 분리하는 행위

한 파일에 모든 코드를 다 넣어도 노드 서버는 문제 없이 동작한다. 간단한 규모의 어플리케이션이라면 굳이 모듈화가 필요없지만, 우리는 실제 서비스에서 사용할 수 있는 어플리케이션을 구현하는 것이 목표다. 즉, 혼자서 개발하는 것은 극히 드물다.

결국 좋은 코드(협업 가능한 코드)를 작성하는 것이 좋은 개발자의 역할이다. 좋은 코드를 나누는 기준은 크게 다섯가지로 분류할 수 있다.

  • 확장성(extensibility)
    확장성을 고려하지 않은 코드는 시스템의 규모가 커질수록 문제가 생길 확률이 높다.

  • 재사용성(reusability)
    반복되는 로직을 함수로 분리하는 코드상의 재사용성 뿐만 아니라, 우리가 설계한 구조가 재사용 되어야 한다.

  • 유지-보수 가능성(maintability)
    여러 로직이 뒤엉켜 있는 코드는 유지 보수가 안 된다.

  • 가독성(readability)
    어려운 로직 일수록 더 가독성이 높아야 한다. 어려운 로직을 쉽고 간단하게 구현하는 것이 좋은 코드다. 프로젝트의 구조 또한 한 눈에 그려져야 한다.

  • 테스트 가능성(testability)
    테스트를 하기 쉬운 코드는 모듈화가 잘 되어 있고, 한 가지 역할만 하는 함수 단위의 코드를 의미한다. 프로젝트의 구조도 추상화가 잘 되어 있고, 역할이 잘 나뉘어 있는 구조가 테스트하기 쉬운 구조다.

MVC Pattern

MVC 패턴은 FrontEnd 에서 프로젝트를 관리 할 때에도 사용될 수 있는 레이어링 패턴이다. 모든 소프트웨어 로직에 적용가능한 패턴임을 기억할 것!

코드의 구조에 대한 대표적인 설계 방법이 아래 다이아그램에서 볼 수 있는 MVC 패턴이다. 각각의 레이어는 Model, View, Controller 를 의미한다.

View

SPA(Single Page Application)과 Mobile App 의 빠른 성장으로 FrontEnd 개발자의 역할이 커지면서 서비스를 위한 소프트웨어는 FrontEnd 와 BackEnd 로 나뉘게 되었다. 본래 MVC는 서버 사이드에서 한번에 다뤄지던 구조이다. 예를 들어서, Django 의 템플릿 기능이나 Express 에도 ejs 를 사용하면 View 를 구현할 수 있다.

View는 쉽게 말해서 클라이언트(유저)와 상호작용이 일어나는 것을 의미한다. 즉, 화면에 보여주기 위한 역할을 하는 것이다. User Interface(유저 인터페이스)가 바로 View 레이어에 있는 코드로 핸들링 된다. React, Angular, Vue 같은 라이브러리 또는 프레임워크로 개발하는 앱을 생각하면 된다. 모바일 iOS, 안드로이드 앱도 View 를 담당한다고 할 수 있다. (프론트엔드와 백엔드를 모두 포함하는 하나의 서비스 관점에서 보았을 때)

Controller

View 레이어에서 유저의 동작이 닿는 곳은 대부분 데이터의 변화가 필요하다. 예를 들어서 내가 담은 장바구니를 보고싶을 때 장바구니 버튼을 클릭하게 되고, 이 때 HTTP 요청이 백엔드 서버로 보내진다. 이 요청을 받아서 처리하는 곳이 컨트롤러이다. View(유저 인터페이스 레이어)Model(데이터를 담당하는 레이어)을 잇는 다리 역할을 하는 부분이다. 유저의 요청을 처리해서 응답하는 부분이라고 할 수 있다. Controller 는 Model 과 소통하게 된다.

Model

서비스에 필요한 모든 데이터는 모델에서 정의된다. 오로지 Model 레이어에 정의된 데이터베이스 schema(모델 또는 테이블)를 통해서만 데이터베이스에 접근해서 CRUD 로직을 처리할 수 있다.

MVC Pattern 의 장점

  • 염려의 분리 (Seperation of Concerns)
    유저 인터페이스와 관련된 부분은 모두 View 에 의해서 관리되고, 모든 데이터와 관련된 로직은 Model 에 의해서 관리되며 오로지 Controller 에 의해서 Model 에 접근할 수 있게 된다. 각각의 레이어가 하는 역할이 명확하다.

  • 동시적인 개발 (Simultaneous Development)
    세개의 레이어로 역할이 나뉘어져 있기 때문에 동시다발적인 개발이 가능하다. 역할분담에 용이하며 협업이 가능한 프로젝트를 구성할 수 있다.

  • 수정의 용이함 (Ease of Modification)
    다른 레이어에 영향을 주지 않고 문제가 있는 로직을 찾아서 문제를 해결할 수 있다.

  • 테스트-주도 개발(Test Driven Development)
    각각의 레이어, 그리고 그 레이어 속에 속한 각각의 모듈을 테스트 하기 좋다.

Node.js Project Layering

위에서 살펴본 바에 따르면 우리가 개발하는 Node.js 를 통한 BackEnd 어플리케이션은 큰 서비스의 관점에서 보았을 때 Controller 와 Model 의 레이어를 담당하게 된다.

하지만 오로지 이 두 개의 레이어로만 로직을 분리하기에는 코드의 복잡성과 레이어 하나가 담당하는 비중이 너무 커지기 때문에 더 확장해서 프로젝트 코드를 레이어링 해야 한다.

아래의 다이아그램은 프로젝트 레이어링을 도식화 해놓은 것이다.

Route, Controller, Service, Model 각각의 레이어가 하나의 폴더이자 역할을 의미한다.

  1. 큰 박스에서 작은 박스로 갈수록 더 데이터를 다루는 로직(데이터베이스 접근하는 로직)에 근접하게 된다.
  2. 또한, 각각의 레이어는 오로지 바로 아래에 있는 레이어에만 의존하게 된다.
    • Route → Controller
    • Controller → Service
    • Service → Model

예를 들어, Route 는 Service 로직을 전혀 모른다. 아예 관여 조차 하지 않는다. 따라서, Service 로직을 변경해도 Route 와 Controller 의 코드는 바뀔 필요가 없다.

서비스를 구현하다가 RDBMS(관계형 데이터 베이스) → NoSQL(ex. mongoDB) 로 이전하는 경우가 있는데, Route와 Controller 의 로직은 전혀 바뀌지 않은 채로 데이터를 다루는 Service 와 Model 의 로직만 변경 해 주면 된다.

1. Project Layering (알파벳 순서)

2. Project Layering (의존성 순서)

위에서 아래로 갈수록 데이터베이스의 접근에 가까워진다. 또한, 위의 레이어는 오직 아래의 레이어에만 의존한다.

  • server.js: Express App 으로 서버를 여는 로직
  • routes: 라우팅(엔드 포인트 나누기) 로직
  • controllers: 엔드포인트에 해당하는 함수 로직 - Http 요청에 따른 에러 핸들링, service 로직에서 데이터를 받아와서 응답으로 내보내는 로직
  • services: controller 에서 넘겨받은 인자로 다양한 알고리즘(필터, 정렬 등..)을 처리해서 데이터에 접근하는 로직
  • prisma (=model): 데이터베이스에 접근하기 위한 모델이 정의되어 있는 폴더

아래 모듈은 의존성 없이 다양한 레이어에서 사용될 수 있지만 반복되는 로직이기에 분리해 놓은 폴더이다.

  • middlewares: 컨트롤러에 닿기 전에 반복되는 로직을 모듈화 해 놓는 폴더
    (ex. validateToken - 인증 / 인가)
  • utils: 의존성 없이 모든 레이어에서 공통적으로 자주 사용되는 로직을 모듈화 해 놓는 폴더
    (ex. errorGenerator)

  • .env: 프로젝트 내에서 사용할 환경 변수를 선언해 놓는 곳
  • node_modules: 노드 패키지 모듈
  • .gitignore: 위의 두 모듈을 깃이 관리하지 않도록 함
  • package.json: 노드 모듈을 관리하는 파일
profile
하늘이의 개발 일기

0개의 댓글