견고한 node.js 아키텍쳐
폴더 구조
- app.js : 앱의 진입 포인트
- api : 앱의 모든 엔드포인트를 위한 라우트 컨트롤러(endpoint : 최종 목적지)
- config : configuration과 관련된 것들과 환경 변수들
- jobs : agenda.js에 대한 작업 정의 // cronjob을 관리하기 위한 노드 모듈
- loaders : 시작 프로세스를 모듈로 분할
- models : 데이터베이스 모델
- services : 비즈니스 로직은 모두 여기!
- subscribers : 비동기 테스크를 위한 이벤트 핸들러
- types : 타입스크립트를 위한 타입 정의 파일들
3 계층 설계 - 3 Layer Architecture
관심사 분리 원칙을 적용하기 위해 비즈니스 로직을 node.js의 API Routes와 분리해준다.
비즈니스 로직 : 데이터를 생성&표시&저장&변경 하는 파트를 일컫는다
👉 언젠가 반복되는 작업을 하다보면 CLI 도구를 통해 비즈니스 로직을 사용하고 싶어질 것임.
👉 node.js server에서 API를 호출하는 것은 좋은 생각은 아니다.
비즈니스 로직을 controller에 넣지 마세요!!
👉 스파게티 코드가 되어버릴 것이다.
- 이 코드의 문제점
- 중간에 많은 business 로직이 존재한다.
- res.json()에 복잡한 것들의 최종적인 것을 담아서 response로 만든다.
- 하지만 이 이후에도 다른 코드의 execution이 일어난다.
비즈니스 로직은 service 계층에 있어야 한다.
Service Layer(API 꼐층)에 SQL query의 형태의 코드가 있어서는 안된다. 이는 Data Access Layer계층에 있어야 한다.
- 해당 코드를 router에서 분리하기
- service 레이어에는 req와 res 객체를 전달하지 말기
- 상태 코드 또는 헤더와 같은 HTTP 전송 계층과 관련된 것들은 반환하지 말기
User Service를 호출함
👉 비즈니스 로직은 Service Layer에 캡슐화!
백그라운드 작업에는 Pub/Sub 계층도 사용하십시오 with Event
- 전형적인 3계층 구조 범위를 넘어서지만 매우 유용함.
IF, 간단한 node.js API 엔드포인트에서 유저를 생성한 이후, third-party (제 3자)서비스를 호출하거나 서비스 분석을 시도하거나, 이메일 전송과 같은 작업을 하고 싶다?
👉 create라는 작업이 여러 일을 하게 될 것이고, 하나의 함수안에 1000줄이 넘어가는 코드가 생길 것
이는 단일 책임 원칙을 위배한다!
👉 해당 코드를 분리하여 간결하게 코드를 유지(함수로 빼내기)
👉 독립적인 서비스들을 직접 호출하는 것은 최선의 방법이 아니다!
👉 이벤트를 발생시켜 리스너들이 해당 일을 하도록 한다!
의존성 주입
의존성 주입(D.I), 제어 역전은 코드를 구조화하는데 많이 사용되는 패턴이다. 생성자를 통해 클래스와 함수의 의존성을 전달해주는 방식이다.
👉 호환가능한 의존성 을 주입함으로써 유연하게 코드를 유지할 수 있다.
(어떠한 생성자내에 클래스를 전달함으로써 의존성을 높이는 방식)
👉 서비스가 가질 수 있는 종속성의 양은 무한하고, 새 인스턴스를 추가할 때 서비스의 모든 인스턴스화를 리팩터링하는 것은 지루하고 오류가 발생하기 쉬운 작업이다(각 객체간 의존성이 높기 때문)
의존성 주입 프레임워크의 등장
- 클래스의 인스턴스가 필요할 때, Service Locator를 호출하면 됨.
Unit Test
👉 req/res 객체들과 require의 호출없이 해당 service 레이어의 함수만으로 유닛 테스트를 실행할 수 있습니다.
스케줄링 및 반복작업
node.js의 task manager는 agenda.js를 이용해서 가능함
설정 및 시크릿 파일 with configuration manager(dotenv)
API Key와 데이터베이스 연결과 관련된 설정을 저장하는 가장 좋은 방식은 dotenv를 사용하는 것이다. 👉 dotenv는 .env파일을 로드하여 안에 있는 값들을 node.js의 process.env 객체에 대입한다. 👉 추가적으로, config/index.jx 파일에서 npm 패키지 dotenv가 .env파일을 로드하고, 객체를 사용하여 변수를 자정한다.
잘 이해가 안가네?
- Service에서 model.create하면 이게 data line 계층 아닌가..??
- 의존성 주입은 잘 모르겟음. 더 공부해야겠다
적용하면 좋을 사항
- dotenv를 이용해 env파일안에 데이터를 로드해서 사용하는 방식
- layer를 나누어 service layer계층으로 현재 API들을 빼내서 관리하는 것 👉 이렇게 바꾸면 나중에 테스트 코드를 수월하게 작성할 수 있을 것
- 이전에 isNew/isUp과 관련했던 이슈를 agenda.js를 이용해서 쉽게 구현할 수 있었을 듯 (하지만 이 역시 어떻게 체크할지 핸들링하는 이슈가 있었겟지?)
- 다른 코드는 함수화 해서 이벤트로 관리하는 게 좋을듯 (이런 작업을 쓰는게 거의 없을듯)
참고자료
견고한 node.js 설계하기 : hopsprings