-
2022년 11월 - 인프런 퇴근길 Node.js 밋업 회고🤔 개인 회고 2022. 12. 5.
인프런에서 첫번째 퇴근길 밋업으로 Node.js를 주제로 다룬다고하여 바로 신청을 했다.
다른 회사에서는 어떻게 Node.js를 사용하고 있을까? Node.js 개발자들은 어떤 고민들을 하면서 프로젝트를 진행했을까? 이런 궁금증과 기대를 품고 29일 저녁 퇴근하자마자 판교로 달려가 밋업을 듣고 온 후기를 남기려고 한다.
주니어 개발자의 Node.js 코드 변천사(feat.랠릿)
개인적으로 가장 인상깊었던 주제는 인프랩에서 랠릿이라는 서비스를 개발하면서 겪었던 코드 구조에 관한 내용이였다. express로 개발을 하면서 고민했던 점이 구조가 너무 자유로워서 어떤 것이 클린아키텍쳐 일까 찾아보면 찾는 레포마다 다 다르고, 개발하는 사람마다 다 다르다는 점이 막막했었는데 이번 강의를 듣고 Node.js를 사용하면서도 이렇게 구조에 대한 고민을 할수도 있다는 것을 처음 알게 되었다.
Mono Repo
인프랩에서는 프로젝트마다 기존 Multi Repo로 운영되는 프로젝트들을 Mono Repo로 만들어 구성하고 있다고 했다.
Mono Repo로 프로젝트를 관리하면 프로젝트마다 공통으로 사용하는 Util성 모듈이나 컴포넌트를 한곳에서 관리 할 수 있다는 장점이 있다고 한다.
하나의 프로젝트 안에 배포될 서비스 단위, 서비스에서 사용되는 모듈로 분리해 이들을 하나의 레포지토리에서 관리를 하는 형태로 구성했다고 했다.
Mono Repo tool 로는 lerna 를 사용하고 있다고 했다. 이 부분을 들으면서 회사에서 작업 했던 프로젝트가 생각이 났다. 외부 앱에서 사용하는 API 와 어드민에서 사용하는 API가 서로 분리되지 않은 하나의 앱으로 된 프로젝트가 있는데, 관리를 위해 별도 서비스로 분리를 하고 위와 같은 구조의 Mono Repo로 적용해 보고 싶다는 생각이 들었다.
Layered Architecture
인프랩에서는 Layered Architecture 구조로 코드를 작성하고 있다고 했다.
Presentation Layer(Controller 객체)
가장 바깥쪽에서 외부와 닿아있는 Presentation Layer에서는 외부에서들어온 요청을 그 다음 레이어인 서비스에서 처리할수 있도록 변환하는 작업을 수행한다. 그리고 서비스에서 응답을 반환하면 그 응답을 API 스펙에 맞게 변환하는 작업도 여기에서 한다고 한다.
그리고 안쪽 레이어에서 발생 되는 에러처리 또한 가장 바깥에 위치한 이 Presentation Layer에서 담당한다고 했다.
Business Layer(Service 객체, Entity 객체)
Presentation Layer에서 전달 받은 데이터를 가지고 비즈니스 로직을 여기서 수행한다. 로직을 수행하기 위해 Service 객체, Entity 객체를 만들어 수행을 하는데 Service 객체는 Transaction 이나 비즈니스 로직을 처리하고, Entity 객체는 데이터베이스에 저장되는 데이터를 담아두고, 핵심 비즈니스 로직을 처리하는 객체라고 한다. 해당 부분을 보면서 아직 DDD에 관한 개념이 없어서 이해가 안갔었다. 비즈니스 로직과 핵심 비즈니스 로직은 어떻게 다르고 왜 핵심 비즈니스 로직을 데이터베이스에 저장되는 데이터를 담는 객체에서 해야하는걸까? 해당 부분에 대해 더 공부를 해야 할 것 같다. ✍️
Repository Layer
Repository Layer에서는 RDBMS나 Redis와 같은 DB에서 붙어서 해당 DB를 컨트롤 하기 위한 로직(예를 들면 CRUD)을 처리한다고 했다. DB를 컨트롤 하기 위한 로직을 별도 Repository Layer로 분리를 한 이유는 RDBMS나 Redis를 나중에 MongoDB로 바꾼다고 해도 상위 레이어까지 변경해야 하는 일을 막기 위함이다.
DTO
각 레이어들 사이의 데이터 전달은 DTO 객체로 구성되어 전달 된다.
응답을 처리하는 DTO를 자세히 들어다보면,
DTO 안에서는 내부에서 사용될 때는 내부에서 사용되는 형태로, 외부(FE)에 데이터를 전달할 때는 외부 계층이 원하는 형태로 반환해 리턴하는 함수들로 작성되어있다. 주먹구구식으로 Object Literal을 그때 그때 만들어 쓰던 방식 과 비교 했을때 DTO를 만들어 쓰면 좋은 점은 Entity가 변경 되어도 일관된 API 인터페이스를 유지 할 수 있다. (만약 Entity 안에 특정 필드가 number => string으로 바뀐다고 해도, 그 변경사항은 DTO 선에서 끝나고 API인터페이스 자체 까지 수정할 필요가 없어진다. 원본 값을 유지하면서 다른 계층이 원하는 포맷으로 속성 제공을 가능하게 하기 때문!) 그리고 Validation이 필요한 데이터가 있으면 그 DTO에만 종속되서 Validation할 DTO만 가지고 하면 되기 때문에 비즈니스 로직과 Validation로직을 분리하기도 쉬워진다.
Active Record Pattern 에서 Data Mapper Pattern으로
Active Record Pattern은 Entity를 다루는 객체가 save()와 같은 함수를 제공하는 형태를 말한다고 한다. 처음 들었을 때는 Django의 queryset이 생각났다. 자기가 데이터도 가지고 있고, 쿼리 작업도 수행가능한 객체를 말하는 것 같은데 처음 듣는 내용이라 따로 이 부분도 공부를 해야겠다.✍️
Data Mapper Pattern은 Entity를 다루는 객체가 save()와 같은 쿼리 작업을 수행하는것이 아니라, Entity와 관련된 모든 쿼리 작업들을 모아놓은 Repository 클래스를 구성해 쿼리 작업을 수행하려면 반드시 Repository를 통해 DB에 접근 하도록 사용하는 형태를 말한다고한다.
Active Record Pattern은 Entity를 다루는 객체가 쿼리작업도 수행해야 하므로 특정 ORM이나 RDBMS에 종속적이게 된다. Data Mapper Pattern은 Service에 대해 unit test를 하고자 할 때 레포지토리에 대한 테스트 더블을 사용해 쉽게 Service 쪽 테스트 코드를 작성하는 것도 가능하다.
TEST
인프랩에서는 Layered Architecture 구조로 코드를 작성 할 뿐만 아니라, 각 Layer에 대한 테스트 코드 또한 작성 한다고 한다. 테스트의 경우 테스트 피라미드 방식을 적용해 테스트를 구성했다고 한다.
Testing Pyramid
인프랩에서는 랠릿 프로젝트를 진행하면서 기존 E2E 테스트 뿐이였던 테스트 코드를 위와 같은 테스트 피라미드의 형태로 수정했다고 했다.
E2E 테스트에서는 API 권한 만을 테스트하도록 가장 적은 양으로 구성을 하고, 두 모듈간의 통합 테스트를 수행하는 통합 테스트 단계 에서는 Service와 Repository 객체의 가능을 테스트하는 코드들로 구성되어있다고 한다. 테스트 DB와 연결을 위해 pg, pg-mem 라이브러리를 사용했다고 한다. 가장 많은 테스트를 수행해야 하는 Unit Tests 단계에서는 DTO와 Entity에 대한 테스트를 진행하고 있다고 한다. 아무래도 이 부분은 DB와 연결 할 필요가 없기 때문에 테스트코드 작성이 쉬워 빠르게 테스트를 돌리는것이 가능하다고 한다.
Test Double
각 테스트의 경우, 테스트 하기 어려운 메일을 보내는 함수라던지 외부 API를 쓰는 함수등을 테스트 할때 Test Double을 만들어 테스트를 진행했다고 한다. Test Double이란 영화 촬영 시 위험한 역할을 대신하는 스턴트 더블 처럼 테스트하려는 객체와 연관된 객체를 사용하기가 어렵고 모호할 때 대신해 줄 수 있는 객체를 말한다고 한다. 테스트 더블은 크게 Dummy, Fake, Stub, Spy, Mock으로 나뉜다고 하는데 뭔가 각각에 대해 들어는 봤지만, 정확히 서로서로 어떤 차이가 있는지 몰랐었는데 이부분도 다시 공부를 해야 겠다.✍️
인프랩 랠릿 프로젝트에서는 이러한 Test Double중에서 Stub과 Mock을 사용했는데, Stub의 경우 메일을 보내는 부분을 대신하는 Stub을 두어 메일 서비스 테스트를 진행했다고 한다.
Mock의 경우, ts-mockito 라이브러리를 사용해서 빠르게 특정 기능에만 집중해서 테스트 해야하는 부분에 다른 부분들은 Mock객체로 대체 해 사용했다고 한다. 이 부분에 대해서도 공부를 해야겠다. ✍️
AWS 인프라 테스트
이 부분이 신기했다. 테스트 하려는 기능이 S3나 SQS와 같은 다른 인프라와 붙어있을 경우, 테스트 만을 위한 인프라를 또 구성하기가 비용, 시간, 관리 측면에서 쉽지 않은데 localstack을 사용해 각 인프라를 에뮬레이팅 해서 테스트를 진행 했다고 한다. localstack에서는 AWS가 제공하는 서비스와 비슷하게 동작하는 환경을 doerker container로 제공을 해준다고 한다.😮
'🤔 개인 회고' 카테고리의 다른 글
23년 1월 회고 (0) 2023.02.06 [글또 8기] 삶의 지도 (0) 2023.01.29 AWSKRGU 서버리스 1월 소모임 후기 (1) 2023.01.22 12월 회고 및 2022년 회고 (0) 2023.01.01 2022년 11월 회고 (0) 2022.12.03