구조적 고민(feat. nestjs)

김명일·2022년 5월 22일
0

스타트업 개발일지

목록 보기
8/10

고민의 시작

서비스에 필요한 기능들이 생기면서 점점 코드 양이 늘어나게 되었고, 코드들을 적절하게 나눠야한다는 생각이 들었다.

회사내의 백엔드 서버 구조는 컨트롤러, 서비스, 모델, validation, util, 미들웨어 정도로 나누어져있었다. 따로 repository도 없었고, orm을 사용하지 않았고 데이터베이스에서 가져온 데이터를 맵핑하지도 않고 사용했다. 즉, 단순한 데이터 조회부터, 수정, 데이터조작에 관련된 모든 부분들이 service에 합쳐져 담겨있었다.
(예를 들어, 가게 조회, 가게 조회 controller에서 호출하는 조회서비스, 가게가 열려 있는지 확인하는 함수 들이 모두 한곳에 있던 것이다.)

그러다보니 점점 service안에는 많은 함수들이 생겨났고, 같은 함수가 여러개 있는 경우도 있고, 수정 시, 어떤 부분을 수정했을 때, 어디까지 영향이 미치는지 명확하게 확인하기 힘들었다.

당시에 repository나 다른 프레임워크에 대해 몰랐고, 함부로 추가해도 괜찮을지 걱정되고 어떻게 해결해야할지 막막했었다.

어떻게 해결해야 할까 고민하면서 여러가지 키워드나 지식들을 배울 수 있었던 것 같다. DTO, VO, orm, repository패턴과 data mapper패턴 그리고 express만 사용해봤던 나에게 routing controller, nestjs는 새로운 경험이었다.

당시 spring에 대해 조금씩 공부하고 있었는데, 이 부분이 nestjs를 이해하고 공부하는데 도움이 되었던 것 같다.

많은 고민 끝에 js에서 ts로, 쿼리빌더에서 orm으로, express에서 nestjs로 변경하기로 결심했다. 하지만 전부 한번에 변경하긴 힘들기 때문에, 환경만 구성하고 기존 코드들을 천천히 ts, orm, nestjs 환경으로 천천히 변경해 나가기로 했다.


js > js + ts

js에서 js + ts를 함께 사용할 수 있는 환경으로 우선 변경해주었다.(jest를 통한 테스트 환경도 ts를 사용하도록 했다.) 우선 새롭게 작성하는 코드들이나 수정이 필요한 코드들 부터 typescript를 적용해 나갔다. 그 밖에 typescript에서 자주 사용되는 class-transformer, class-validator 등에 대해 공부하게 되었다.

knex > typeorm

orm도 많은 고민을 하게 했던 것 같다. 주로 nodejs쪽에서는 typeorm, sequilze, prisma가 있고, typescript에는 typeorm을 사람들이 주로 사용하는 것 같았다.

  1. 단순 서칭으로 typeorm으로 결정
    마침 JPA를 공부하며 orm에 대해 이해하고 있었기 때문에, typeorm의 불편한 점들이 느껴졌다. 1차 캐시가 없다는 점과 트랜잭션 사용이 spring에서 만큼 편하지 않다는 것이었다. typeorm-transactional-cls-hooked라는 패키지가 트랜잭션 사용을 스프링 처럼 쉽게 도와줬지만,
    1. typeorm에서 이에 대한 언급이 없음
    2. 테스트 코드 작성에 번거로움
    3. typeorm 버전이 0.2에서 0.3으로 올라가면서 사용할 수 없게 되어 사용하지 않았다.
  2. mikro-orm
    JPA를 공부하고 있다보니, 비슷한 orm을 사용하고 싶어졌다. 그러던중 mikro-orm에 대해 알게되었었다. 많은 사용자가 있는 것 같진 않았지만, JPA 처럼 영속성 컨텍스트가 있어 1차 캐시를 지원하며, em.flush 호출시, 한번에 변경사항들의 쿼리가 나가는 JPA와 비슷한 방식이었다. 마음에 들어 몇가지 테스트를 해보았을 때, 문제점이 발견되어 이슈에 등록하니 빠르게 수정해주었다. 빠른 수정과 기능들은 좋았지만, 사용자가 많지 않기 때문에 아직 숨겨진 버그들이 있지 않을까 하는 마음에 다시 typeorm으로 돌아오게 되었다.

expressjs > nestjs

express에서 다른 프레임워크로 넘어가야지 생각했던 이유는 express가 너무 자유롭다보니 모든걸 다해야했기 때문이다. 또한 당시에 DI에 대해 공부하며 DI의 유용성을 알게되니 DI 패턴을 사용하고 싶었다.

그래서 미뤄왔던 nestjs에 대한 공부를 시작했고, 한번 사용해보니 앞으로 express는 대신 nest를 주로 사용할 것 같았다. 지원되는 기능들도 많고, 구조를 강제함으로서 깔끔한 구조를 유지할 수 있도록 도와주었다.

중간에 routing controller로 결정하고 수정을 진행했던 적이 있었는데, 아무래도 마이너한 기술이다보니 추후 다른 개발자가 왔을 때, 새롭게 공부해야하지만 그렇게 좋은 프레임워크도 아닌 것 같아 차라리 nestjs를 사용하기로 했다.

code build

typescript를 추가하게 되면서 당연히 배포과정 및 실행 스크립트가 변경되게 되었다. 기존에 code pipelinecode deploy를 통해 브랜치에 변경이 생기면 자동으로 배포가 되었었다. 하지만 typescript환경으로 변경하게 되면서 빌드하는 시간이 필요했고, code buildcode pipelinecode deploy 사이에 추가했고, 아래와 같은 프로세스로 자동 배포 되었다.

  1. code pipeline에서 브랜치 변경 감지
  2. code build에서 빌드 후 설정한 파일들을 code deploy에 전달
  3. code deploy에서 적절한 스크립트 실행을 통해 서버 실행

결과

결과적으로 환경구성 후, 조금씩 nestjs환경으로 변경해 나갔다. 전체를 수정한 건 아니지만, 확실히 서비스와 레퍼지토리, 엔티티가 분리되면서 어디에 어떤 코드가 있는지 확실하게 확인할 수 있게된 것 같았다. (예를 들어, 가게조회는 레퍼지토리로, 가게조회 컨트롤러에서 호출하는 서비스는 서비스로, 가게가 열려있는지는 엔티티로 로직이 이동하게 되면서 응집도가 올라간 것 같다)

나에게 있어서는 개발적으로 의미있는 경험이 되었다고 생각이 들었다. dto나 vo 그리고 구조를 어떻게 할 것 인가 등 고민하게 되는 부분이 많았고 앞으로 객체지향이나 DDD, 수정에 용이한 코드, 응집도와 결합도 등 공부할 방향이 생긴것 같았다.

하지만 너무 과한 변경을 했다고 생각이 들었다. 시간적으로 많이 큰 비용이 드는지 알지 못했고, 아직은 굳이 nest로 변경하지 않고, 레퍼지토리와 dto를 추가하여 해결하는 것이 더 좋았을 것이라고 생각한다. 앞으로는 필요한 것이 무엇인지 명확하게 고민하고 걸맞는 해결을 위해 더 고민해야겠다고 느꼈다.

profile
주니어 백엔드 🐶🦶🏻📏

0개의 댓글