본문 바로가기

Development Log

[TypeScript/NestJS/TypeORM 0.3] Service와 Repository는 분리하는 것이 맞을까?

팀프로젝트로 진행했던 1차 기업과제 초기 회의에서 Service와 Repository를 분리하는 것이 깔끔하다는 의견이 다수였기 때문에 스켈레톤 프로젝트를 만들 때 의견을 반영하여 분리하여 기본 구조를 만들었었다. 여기서 문제점이 발생했고..

팀원들의 PR을 확인하는데 DB에 연결하기 위한 Repository 주입 방식이 다양하게 4가지 정도 나왔다.. 그래서 이걸 발견하고 '아.. 어떡하지.. 하나의 프로젝트인데 이건 통일성을 맞춰야될 것 같은데?'라고 생각해서 팀 미팅을 진행하는 시간에 얘기를 해봐야겠다고 생각했다. 팀 미팅 때 얘기 하기 위해서 관련 내용을 총 4가지 방법으로 검색하여 회의록에 작성해 놨다. 말로 설명하는 것보단 글과 참고 사이트를 팀원들이 직접 확인하는 것이 이해가 빠를 것이라고 생각했기 때문이다. 정리했던 방법은 아래 4가지 방법이었다.

 

1.  서비스에서 Repository 연결하는 방법 (= NestJS 공식문서 권장 방법)

사실 이 방법은 개인 프로젝트 당시 사용했고, 팀 프로젝트에서 나랑 다른 팀원이 사용하고 있던 방법이었다. 전 회사에서는 Repository를 분리했고 @EntityRepository를 사용했었는데 typeorm 0.3에서는 사라진 데코레이터이기 때문에 사용할 수 없어서 1번 방법에 대해 검색을 많이 했다. 왜 Repository로 나눠서 사용하는 방법을 권장하지 않고 아예 데코레이터까지 사라지게 했을까.. 에 대한 의문점이 많이 들었는데 여러 글들을 봤었고 그중에서 무분별한 Repository 분리와 과한 추상화가 가장 나한텐 와닿았던 것 같다. 그래서 난 팀원들에게 아래 의견을 말했었다.

 

Repository를 따로 분리한다면 간단한 코드조차 한 단계 거쳐서 작성해야 된다는 점과 프로젝트의 단위가 크지 않다면 굳이 나누지 않아도 된다고 생각했었습니다. 또한, NestJS의 공식문서에서 명시하는 Repository Pattern으로 따라서 사용해보고 싶었습니다.

 

++ 관련 참고 사이트

https://velog.io/@kisuk623/TypeORM%EC%9D%80-%EC%99%9C-Custom-Repository%EB%A5%BC-%EB%B9%84%ED%99%9C%EC%84%B1%ED%99%94%ED%96%88%EC%9D%84%EA%B9%8C

 

TypeORM은 왜 Custom Repository를 비활성화했을까?

TypeORM은 nodeJs환경에서 사용할 수 있는 ORM 중 하나다. TypeORM을 제외하고 많이 사용되는 ORM에는 Sequelize, Prisma가 있다.

velog.io

 

https://docs.nestjs.com/techniques/database#multiple-databases

 

Documentation | NestJS - A progressive Node.js framework

Nest is a framework for building efficient, scalable Node.js server-side applications. It uses progressive JavaScript, is built with TypeScript and combines elements of OOP (Object Oriented Programming), FP (Functional Programming), and FRP (Functional Rea

docs.nestjs.com

 

2. 서비스에서 Repository 연결만, Repository 파일을 분리하여 사용

이 방법은 Service 파일에서 Repository로 넘어갈 수 있게 연결만 하고 Repository 파일에서는 1번 방법을 사용하는 것이었다. 사실 나도 처음에 이렇게 작성했다가 '해당 모듈에 providers 부분에 Repository 주입을 한다고?'라는 의문점이 생겨서 1번 방법으로 다시 수정했었다. 😅 ' providers에서 Repository를 주입하나?'라는 생각에 검색하던 중 "대부분의 기본 Nest Class인 services, repositories, factories, helpers 등은 provider로 취급될 수 있다. provider는 단순히 @Injectable() 데코레이터가 달린 클래스이다."라는 글을 발견하였고 크게 문제가 될 건 없어 보였다.

 

++ 관련 참고 사이트

https://stackoverflow.com/questions/74542474/how-to-create-custom-separate-file-repository-in-nestjs-9-with-typeorm-0-3-x

 

How to create custom (separate file) repository in NestJS 9 with TypeORM 0.3.x

This is not a duplicate Q. Please don't mark this as that. Following is not I want import { EntityRepository, Repository } from "typeorm"; import { Test } from "./test.model"; i...

stackoverflow.com

 

3. 서비스에서 데코레이터 사용 없이 Repository 주입 가능, 단 @CustomRepository 데코레이터를 생성해서 사용

이 방법은 TypeORM 0.3 버전에서 @EntityRepository가 사라졌다 보니 @CustomRepository 데코레이터 자체를 직접 만들어서 사용하는 방법인 것 같았다. 여러 가지 파일을 만들어야 해서 복잡해 보였지만 아주 정리가 잘된 글을 발견해서 파악하고 따라 하기에는 문제가 없어 보였다.

 

++ 관련 참고 사이트

https://gist.github.com/anchan828/9e569f076e7bc18daf21c652f7c3d012

 

This is an improvement to allow @nestjs/typeorm@8.1.x to handle CustomRepository. I won't explain it specifically, but it will h

This is an improvement to allow @nestjs/typeorm@8.1.x to handle CustomRepository. I won't explain it specifically, but it will help in some way. https://github.com/nestjs/typeorm/pull/1233 - RE...

gist.github.com

 

4. 서비스에서 Repository 연결만, Repository에서 DataSource로 디비 연결

이 방법은 TypeORM 공식문서에서 있었던 내용이었고 팀원 중 사전과제 때 이 방법으로 만들어서 제출했기 때문에 코드를 본 상태였다. 다만 초기 스켈레톤 프로젝트를 만들 당시 이 방법 말고 다른 방법으로 만들어보고 싶다는 팀원의 의견이 있었기 때문에 우선 적어놓기만 했었다.

 

++ 관련 참고 사이트

https://stackoverflow.com/questions/72549668/how-to-do-custom-repository-using-typeorm-mongodb-in-nestjs

 

How to do custom repository using TypeORM (MongoDB) in NestJS?

I have a question. With @EntityRepository decorator being marked as deprecated in typeorm@^0.3.6, what is now the recommended or TypeScript-friendly way to create a custom repository for an entity in

stackoverflow.com

 

 

위 내용들에 대해 간략하게 팀원들에게 설명을 했고 각자 생각할 시간을 5-10분 정도 가진 다음에 한 명씩 얘기해 보기로 했었다. 결론부터 말하자면 이때 정하지 못했다. 자신의 코드에서 결정되는 방법으로 변경하는 것에 대한 거부감은 없었지만 지금 당장 결론을 내리지 못했던 것 같다. 결론을 내리지 못한 건 Repository를 어떤 방법으로 사용할 것인가였고 일단 Service와 Repository를 분리까지는 결정을 냈었다.

 

이때 이 주제로 회의만 1시간 30분에서 2시간은 했던 것 같다. 뭔 얘기를 이렇게 많이 했지..? 😅 그래도 팀 프로젝트를 진행하면서 무언갈 정하기 위해 긴 토론을 하는 것에 대해서 긍정적인 생각이었고 팀 프로젝트라면 필수적인 거라고 생각했다. 결국 3일 뒤 일요일 아침 8시 30분에 만나서 다시 한번 생각해온걸를 회의록에 작성해 놓고 얘기하기로 했었다.

 

나는 처음에 1번을 얘기했지만, 팀원 3명의 의견은 Repository를 분리하자였기 때문에 2번, 3번, 4번의 방법 또는 다른 방법을 찾던 도중 1번의 방법으로 가고 싶다는 생각이 너무 커졌다. 그 이유도 위에서 말했던 이유와 동일하다. Service와 Repository를 분리해야 하는가?를 생각하면 납득할만한 이유를 찾지 못했다.. 😩 그래서 다음 회의 때 1번을 주장하고, 이에 대한 근거를 다시 말해보아야겠다고 생각했다.

 

근데 정말 우리 팀은 마음이 잘 맞았던 걸까? 회의 당일! Repository를 분리하자고 말했던 2명의 의견이 1번으로 바뀌었다. 그래서 결국 1번을 찬성하는 사람이 4명이 되었고 아래는 의견이 바뀐 2명의 팀원들의 생각이었다.

 

🙋 이미 잘 만들어진 ORM이 제공하는 것을 똑같이 복제할 뿐이다. TypeORM 0.3에서 Repository 패턴을 지양하고자 하는 목적으로 대대적인 업데이트가 있었고, 굳이 따라가지 않을 이유는 없다. 알고 보니 이미 몇 년 전부터 꽤나 있었던 논의였던 것 같다.

 

🙋🏻‍♂️ 처음에는 리포지토리를 나누어서 리포지토리 파일의 코드를 최소화하고, 코드의 재사용성을 높이는 방법을 추구하였는데, ORM이 아니라 TypeORM을 사용할 경우 리포지토리 파일에서 쿼리빌더를 사용하기에 처음 취지와는 다르게 코드를 작성하게 되었고, 굳이 리포지토리 파일을 나눌 필요성을 느끼지 못하여 서비스에서 리포지토리를 주입받는 게 오히려 더 깔끔할 것 같습니다.

 

 

최종 결론

우리 팀은 Service에서 Repository 분리하지 않고 Service에서 Repository를 주입받아서 사용하는 방법인 1번을 선택하게 되었다. 🎉 🎉 🎉 🎉 🎉

난 긴 시간 고민했고, 많은 글들을 봤었고, 최선의 방법으로 생각했고, 설득하기 위한 근거를 찾았던 것 같다. 분명 우리 팀원들도 나와 똑같지 않았을까라는 생각을 한다. 이렇게 결정하고 나니까 한결 마음이 편안해졌고 나름 하나의 프로젝트가 완성되어가고 있는 기분이었다. 분명 앞으로 팀프로젝트를 진행하면서 맞춰가야 할 부분이 많다고 생각한다. 그럴 때마다 서로 의견을 존중해 주면서 최선의 방법을 찾아내는 팀이 되고 싶다!