Skip to content

[J123] 이태훈

LeeTH916 edited this page Nov 27, 2023 · 8 revisions

1주차 회고

성장 목표

  • BE 개발의 전반적인 프로세스와 협업 방식에 대해 경험해보기
  • 적절한 DB를 선정하고 DB 쿼리 최적화해보기
  • 테스팅에 대해 많은 경험 해보기

이번 주 기술적 고민거리

  • api 설계
    • login 부분에 대한 api 설계시, 일반 로그인과 소셜로그인의 엔드포인트를 구분해야 할지에 대해 고민 -> 관리와 코드 재사용성 측면에서 하나로 하는게 좋을 것 같다고 판단하여 하나로 통합
    • 유저 팔로우, 언팔로우 같은 작업에 대해 엔드포인트를 어떻게 설정할 지 고민 -> 엔드포인트의 이름을 서로 다르게 하는 방법을 생각하다가, RESTful한 api 설계를 위해 엔드포인트는 같게 하고 메서드를 분리하는 방향으로 결정
  • DB 선택
    • 주제가 맛집 공유 플랫폼이기 때문에 지도에 대한 위치 데이터를 저장하는 측면에서 NoSQL을 사용해야 하는지에 대해 고민 -> 내부적으로는 한번 사용해보고 싶다라는 의견도 있었지만, 우선 가장 중요한 RDB를 많이 공부하고 사용하는 형태로 구현해보고 추후에 발전시켜나가는 방향으로 변경
  • 웹 서버 사용 여부
    • 단순히 사용해보고 싶다라는 생각으로 어떤 웹 서버를 사용할 지에 대해 고민을 해 보았는데, 멘토링을 통해 웹 서버의 필요성을 느꼈을 때 선정해보는 방향으로 결정

2주차 회고

진행한 내용

  1. ncloud 세팅 및 서버 배포
  2. typeORM 및 postgres DB 연동
  3. 회원가입 기능 구현
  4. base response 설정
  5. swagger를 통해 api 문서화
  6. naver 소셜 로그인
  7. jwt를 이용해 인증

고민 및 해결과정

  1. ncloud 세팅
    1. 처음에 vpc를 선택하고 subnet을 설정한 후에 메인 서버와 DB서버를 생성했다. 이때 메인 서버에서 DB 서버에 접속이 가능하게 하기 위해 세팅을 하는 과정에서 응답이 없는 오류가 발생했다. 문제가 발생했던 부분은 acg를 새로 생성하는 부분이였는데, acg를 새로 생성하고 그걸 할당해주는 과정에서 메인 서버의 ACG에 아웃바운드 규칙을 설정하지 않아서 DB서버로 접속을 할 수 없던 것이였다. 해당 부분에 아웃바운드 규칙을 추가해준 후에 메인 서버에서 DB서버로 접속을 성공했다.
  2. 데이터베이스
    1. 데이터베이스는 postgres를 선택했다. 이유는 사용자에 따라 많은 음식점들의 정보를 가져오는 우리의 서비스 특성상 대규모 처리에 조금 더 강점을 가지는 postgres가 적절하다고 판단했다. 또한 추후 주변 음식점 검색을 위해 거리 계산이 필요할 것 같은데 이 부분에 postgres의 extension인 postGIS를 사용할 수 있지 않을까 라고 생각했다.
    2. 메인 서버에서 postgres에 접속하는 과정에서도 오류가 발생했다. 개발을 할때는 같은 pc에 postgres를 설치하고 진행했기 때문에 이 오류를 발견하지 못했는데, 메인 서버에서 실행하려고 하니 DB서버에 있는 postgres에 접속을 하지 못하는 문제가 발생했다. 문제가 발생한 이유는 postgres의 원격 접속 설정을 바꿔주지 않았기 때문이였다. postgresql.conf와 pg_hba.conf 파일에 원격접속을 허용해주도록 하는 세팅을 추가해 준 후 진행하니 문제가 해결됐다.
  3. base response
    1. 안드로이드 분야와 협업을 진행하면서, 서버측에서 주는 성공응답과 에러응답 형식이 통일되어 있어야 안드로이드 개발자가 조금 더 쉽게 응답을 사용할 수 있을 것 같다고 생각을 했다. 그래서 어떤 방법이 있을지 고민하고 찾아보다가 interceptor와 filter를 사용하면 좋을 것 같다고 판단했고, base response를 만들고 성공 응답에 대해서 global로 등록된 interceptor를 통과하도록 했고 에러응답은 globalFilter를 사용하여 동일한 형식으로 응답을 할 수 있는 구조를 만들었다.
  4. 소셜 로그인
    1. 웹 oauth는 구현을 해봤지만 안드로이드에서 oauth는 처음해봤기에, 익숙한 웹 oauth 형태로 구현을 하다보니 문제가 발생했다. 이전에 passport 모듈을 사용하지 않고 oauth를 구현해봤기 때문에 이번에는 passport 모듈을 사용해보고 싶어서 naver 용 passport-naver를 통해 진행을 했는데, 유저의 정보를 가져오지 못하고 에러페이지만 나오는 문제가 발생했다. 찾아보니 안드로이드에서 oauth를 할때는 이미 sdk를 통해 accessToken을 받아오기 때문에 서버에서는 프로필 정보를 가져오는 api를 해당 토큰과 함께 요청하기만 하면 된다고 해서, axios를 통해 naver에 api 요청을 하는 방식으로 문제를 해결했다.

3주차 회고

진행한 내용

1. refresh token 발급 및 이를 통한 access token 재발급
2. 로깅
3. 테스트
4. 음식점 정보를 받아와 저장
5. 음식점 검색 시 자동완성 기능
6. 홈 화면에서 필터 클릭 시 해당 유저의 맛집 리스트 응답 기능

고민 및 해결 과정

1. refresh token 발급 및 이를 통한 access token 재발급
    1. access token이 만료되었을 때 refresh token을 전달받아야 하는데 이때 authorization 헤더를 써야할 지, 아니면 body를 통해 전달받아야 할지 고민했다. 이때 authorization 헤더에 대해 찾아보니 이 헤더는 access token을 전달할 때 사용하는 것이 일반적이라는 내용을 확인 했고, 결론적으로 body를 통해 refresh token을 전달받고 이를 통해 access token을 재발급 절차를 진행하기로 결정했다.
2. 로깅
    1. 로그를 추후에 확인하기 위해서는 파일로 저장하는 것이 편리할 것 같다고 판단하여 nestjs의 default logger가 아닌 winston을 사용하여 custom logger를 만들어 사용했고, 모든 동작에 대해 공통적으로 로깅을 하는 것이 좋을 것 같다고 판단하여 interceptor를 이용하여 공통된 로그를 저장하도록 설정했다.
    2. 로깅을 할 때 어떤 정보를 표시해야 할지에 대해 고민을 했다. 처음에는 특정유저에게 요청이 오면 그 유저의 닉네임, 요청사항 등 자세한 내용을 모두 로깅을 해놔야 할 지 고민했지만, 조금 과한 것 같다는 생각이 들었고 단순하게 timestamp, 메서드, 엔드포인트, 응답 메세지, 지연시간 정도만 표시하는 것을 기본 형태로 해서 구현을 했다. 이 부분에 대해 멘토분께 질문한 결과 유저에 대해 너무 많은 정보를 로그에 남겨놓는 것은 보안 상 좋은 것은 아닌것 같고 조금 더 디버깅하기 편한 것을 원한다면 요청에 대한 body 부분을 추가하면 좋을 것 같다는 피드백을 받아 해당 부분을 추가해 볼 계획이다.
3. 테스트
    1. DB를 테스트 할 때 테스트 DB를 따로 구축할 필요 없이 간단하게 InMemoryDB를 통해 단위 테스트를 진행하기 위해 선택했다. 이 과정에서 DB 연결을 할 때 공식 문서에 나와있는 방법과는 약간 상이해서 많은 에러를 겪었지만 결국 datasoure를 하나 만들고 초기화 및 동기화를 해준 후 테스트 모듈에 overideProvider를 통해 추가하여 연결에 성공했다.
4. 음식점 정보를 받아와 저장
    1. 처음에는 네이버나 카카오 api를 사용할 계획을 세웠으나, 한번에 가져올 수 있는 양이 너무 적고 반복해서 api 요청을 하는것도 불가능했기 때문에 사용하기 부적절하다고 판단했다. 그래서 한번에 1000개씩 반복적으로 api 요청을 하여 모든 정보를 가져올 수 있는 서울시 공공 api를 선택했다
    2. 약 50만개의 데이터를 받아와야 하기 때문에 1000개씩 500번 정도의 api 요청을 해야하고 이 데이터를 DB에 매번 저장하는 과정에서 매우 오랜 시간(약 10분)이 걸렸다. 이 부분을 개선하기 위해 처음에는 worker 모듈을 사용하여 쓰레드를 생성하여 작업하고 저장하니 시간이 약 4분 정도로 단축됐다. 이후 조금 더 개선을 하기 위해 api를 비동기적으로 요청하고 해당 작업이 어느 정도 진행됐을 때마다 한번씩 DB에 bulk insert를 하는 방식을 시도했고 시간은 약 2분 정도로 단축됐다.
    3. 위치 정보는 postGIS 확장을 이용하여 저장을 시도했다. 이때 안드로이드쪽과 편하게 협업하기 위해서는 WGS좌표계로 저장할 필요가 있었는데, 서울시 공공 api에서 제공하는 위치 정보는 중부TM 좌표계였기 때문에 변환을 해야했다. proj4 라는 npm 모듈을 이용하여 변환을 시도했는데 위치 정보에 오차가 매우 큰 오류가 발생했고 더 정확한 보정된 중부원점 좌표계를 활용하여 WGS 좌표계로 변환하여 위치 정보를 저장했다.
5. 음식점 검색 시 자동완성 기능
    1. 검색 자동완성 기능의 구현에 대해 어느 정도 수준으로 구현을 해야할 지에 대해 고민을 했었는데, 주어진 시간과 우리의 서비스 특성을 고려했을 때 검색엔진 정도의 고수준은 적절하지 않다고 판단하고, 단순하게 DB에서 조회를 할 때 Like문을 이용하여 검색하는 단어가 포함되는 음식점을 응답하는 방식으로 결정했다.
    2. 검색된 음식점들을 거리순으로 정렬할 필요가 있었기 때문에 현위치를 기준으로 음식점들의 거리를 어떻게 계산 할지를 고민했다. 이때 하버사인 공식을 사용하여 직접 코드를 구현할지도 생각을 했지만, postGIS 확장을 이용하여 위치 정보를 저장한 경우 DB에서 내부적으로 거리를 계산할 수 있는 방법이 있다는 것을 알게 되었고 해당 방법을 통해 우선적으로 기능을 구현한 후 추후에 직접 거리를 계산하는 것과의 시간 차이를 분석해서 더 빠른 방식을 최종적으로 채택할 예정이다.
6. 홈 화면에서 필터 클릭 시 해당 유저의 맛집 리스트 응답 기능
    1. 내가 필터 요청을 한 유저의 맛집 리스트를 가져오는 작업은 단순했지만, 그 음식점을 내가 맛집 리스트에 등록했는지 여부도 표시해줘야 했기 때문에 쿼리가 조금 더 복잡해졌다. 이때 raw query를 쓰는것과 typeORM 문법을 사용하는 방법 중 고민하다가, typeORM을 사용했을 때 location 정보가 {x,y}의 객체로 잘 나오는 것을 확인했고 이런식으로 ORM을 사용할 때 얻는 이점을 잃을 수 있겠다고 판단하고 typeORM 문법을 이용하여 쿼리를 수행했다.
Clone this wiki locally