발단
진행하고 있는 사이드프로젝트에서 Nest.js로 개발을 하게 되면서 느슨했던 express의 구조에 긴장감을 줄 수 있게 되었다.
nest g res 명령어를 입력하면 api를 만들 수 있도록 기본적인 구조가 형성이 되는데, controller, service, dto, entity의 구조로 생성된다.
그런데, entity에서 데이터를 가져올 때 repository를 주입하는데 명령어로 입력했을 때 repository를 만들어주지는 않는다. 사실상 repository라는 개념은 nest에서 기본적으로 당연하듯 제공하지는 않는 것 같다. 그렇다면 왜 필요하고, 다른 것들은 기본적으로 만들어주는데 repository를 왜 만들어주지 않는지 내가 이해한대로 적어보고, 고민해보려 한다.
먼저 repository가 무슨 기능인지를 이해한대로 써내려보겠다.
Repository란?
Repository를 다루기 전에 먼저 앞서 설명한대로 repository를 만들어주지 않기 때문에 nest에서 기본적으로 제공해주는 개념부터 생각해보자면, repository는 service와 관련되어 있다.
nest는 typeORM을 기본적으로 제공하고 있고, entity에서 db와 접근한다. orm마다 수많은 메서드가 있지만, 기본적으로 CRUD라고 생각해보면, entity에 orm을 통해서 생성, 조회, 변경, 삭제에 대해 요청할 수 있다. mvc패턴 즉, model, view, controller단으로 구분했을 때 우리는 db에 접근하는 로직을 model로 익히 알고 있다. 그리고 nest에서는 명령어를 통해 service라는 네이밍으로 model로직을 작성하게끔 하고 있다. 그래서 service단에서 db에 관련된 로직을 구현하여 원하는대로 데이터에 대한 작업을 수행할 수 있다.
그렇다면 service와 연관된건 알겠는데, repository가 무슨 역할을 하고 있을까?
service에서 분리된 개념으로, 로직의 구분을 정해주면 좋겠다. service에서도 entity를 통해 바로 DB에서 접근할 수 있는데, 여러 동작을 수행하게 될 경우 service에서는 여러 중복된 로직들이 발생한다.
예를 들어, 특정 테이블을 가져와서 데이터를 가공하는 로직이 여러 개 있다고 했을 때, 테이블을 가져오는 과정 자체는 동일하기 때문에 중복해서 여러 번 사용하게 된다. 그러나 새롭게 가져오는 로직을 계속해서 작성한다면 코드가 점점 길어지기에 가독성이 떨어지기 시작한다. 그래서 service에서는 데이터를 가져와서 가공하는 등의 로직들을 수행하고, repository에서는 단순히 접근만 하도록 한다.
아래는 내가 구현중인 api의 일부다.
async getMatchingByUserId(id: string, gender: boolean, phase: number) {
try {
const matchingData = await this.matchingRepository.getMatchingByUserId(
id,
gender,
phase,
);
return matchingData;
} catch (err) {
throw err;
}
}
async getFeedback(userId: string, gender: boolean, phase: number) {
try {
const matchingData = await this.matchingRepository.getMatchingByUserId(
userId,
gender,
phase,
);
let feedbackData;
gender === false
? (feedbackData = matchingData.mFeedback)
: (feedbackData = matchingData.fFeedback);
return feedbackData;
} catch (err) {
throw err;
}
}
matchingData에는 여러 정보들이 있는데, matchingData전부를 가져와야 하는 상황이 있고, feedback을 가져와야 하는 상황이 있는데, feedback의 내용은 matchingData에 속한 데이터다.
결론부터 설명하자면, repository의 로직은 재사용하도록 하고, service에서 db에서 가져온 데이터를 통한 작업을 수행하는 것이다. 사실상 repository는 없어도 service에서 전부 구현하면 되기 때문에 nest의 명령어를 입력했을 때 기본적으로 repository가 제공되지 않는 것이라고 생각한다.
물론 그렇게 치면 하나의 파일 안에 패턴없이 다 넣을 수도 있겠지만, service에서 전부 구현해도 된다는 뜻은 api에 따라 단순히 가져오기만 하면 되는 로직도 있을 수 있는데, 그 땐 repository가 필수적이지는 않을 수 있다. 예를 들어 약관을 가져오는 api라고 한다면 별도의 데이터가공은 필요하지 않기 때문에 service에서 가상의 Repository를 주입하여 가져오면 그만이다.
코멘트
Repository를 생성함으로 인해 service에서는 db에 접근하는 로직은 입력값만 넣어주고, 필요한 작업만 수행할 수 있게 되었다. db자체의 에러는 repository에서, 로직때문에 생기는 에러는 service에서 처리하려고 한다. 확실히 이렇게 구분하니, 같이 프로젝트를 진행중인 팀원들과의 협업에 용이한 장점이 큰 것 같다.
정리하면
- dto에서 data의 타입을 safe하게 전달하고,
- 클라이언트 로직은 controller,
- 서버에서 처리하는 api마다 다른 커스텀하는 로직들은 service,
- db 자체에 관한 로직은 repository에서 처리하되,
api마다 다른 로직 없이 단순한 db접근 로직의 경우 service에서 자체로 처리하거나, 구조통일을 원할 경우 repository를 생성할 수 있겠지만, 개인적인 생각으로는 구조 통일보다는 불필요한 싱크홀을 줄이는 것이 낫지 않을까 하는 생각이 든다.
'개발 > library, framework' 카테고리의 다른 글
[Draft.js] Unknown DraftEntity key: null 해결방법 (0) | 2024.01.08 |
---|---|
[React] Recoil 로 변경하기 어려운 상태 관리 방법 (0) | 2024.01.04 |
[Nest | swagger] Authorization Bearer 로 적용해야 하는데 Basic으로 적용되는 경우 (0) | 2023.11.20 |
[nest | socket.io] 연결 성공한 이후 클라이언트 요청 응답오지 않는 경우 (0) | 2023.11.14 |
[NEST | Prisma] 의도치 않은 DB 연결 (0) | 2023.11.05 |