Skip to content

Another-Glass/Assignment4_Team

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

41 Commits
 
 
 
 
 
 
 
 

Repository files navigation

원티드 백엔드 프리온보딩 4차 과제 - 8퍼센트

👨‍💻 원티드 프리온보딩 어나더글라스 팀입니다.

6명의 안경잡이 개발자들의 시선과 관점이 담긴 과제입니다.

무던히 포기하지 않고 견디고 견뎠던 그 시간들이 변함없는 단 하나의 해답임을 믿습니다.

PRs Welcome Hits issues






🎤 소개

이 레포지토리는 원티드 프리온보딩 백엔드 코스 4차 과제를 위해 만들어졌습니다.

  • 일정 : 2021년 11월 11일(목) 오후 6시 ~ 11월 13일(토) 오전 10시


🧑🏻‍💻 팀원 소개

팀장 박상수 팀원 김성연 팀원 최준호
blog: Plus Ultra
github: epitone
blog: sudocorp
github: SibaDoge1
blog: raejun92.log
github: raejun92
sprint4 sprint4 sprint4
유저 & 계좌생성 API, DB / Test 입출금 API, DB / DevOps 거래내역 API, DB
프로젝트 회고 프로젝트 회고 프로젝트 회고


팀원 어유선 팀원 김현길 팀원 이동훈
blog: Makkiato
github: Makkiato
blog: gusrlf14
github: hyunghilkim
blog: dongjay00.log
github: dongjay00
sprint4 sprint4 sprint4
거래내역 API, DB 입출금 API, DB 유저 & 계좌생성 API, DB / Test
프로젝트 회고 프로젝트 회고 프로젝트 회고



📕 과제 내용

[필수 포함 사항]

  • READ.ME 작성
    • 프로젝트 빌드, 자세한 실행 방법 명시
    • 구현 방법과 이유에 대한 간략한 설명
    • 완료된 시스템이 배포된 서버의 주소
    • Swagger나 Postman을 통한 API 테스트할때 필요한 상세 방법
    • 해당 과제를 진행하면서 회고 내용 블로그 포스팅
  • Swagger나 Postman을 이용하여 API 테스트 가능하도록 구현

[개발 요구사항]

✔️ API 목록

  • 거래내역 조회 API
  • 입금 API
  • 출금 API
[고려 사항 및 상세설명] **✔️ 주요 고려 사항은 다음과 같습니다.**
  • 계좌의 잔액을 별도로 관리해야 하며, 계좌의 잔액과 거래내역의 잔액의 무결성의 보장
  • DB를 설계 할때 각 칼럼의 타입과 제약

✔️ 구현하지 않아도 되는 부분은 다음과 같습니다.


  • 문제와 관련되지 않은 부가적인 정보. 예를 들어 사용자 테이블의 이메일, 주소, 성별 등
  • 프론트앤드 관련 부분

✔️ 제약사항은 다음과 같습니다.


  • (8퍼센트가 직접 로컬에서 실행하여 테스트를 원하는 경우를 위해) 테스트의 편의성을 위해 mysql, postgresql 대신 sqllite를 사용해 주세요.

✔️ 상세설명

1) 거래내역 조회 API

  • 아래와 같은 조회 화면에서 사용되는 API를 고려하시면 됩니다.

거래내역 API는 다음을 만족해야 합니다.

  • 계좌의 소유주만 요청 할 수 있어야 합니다.
  • 거래일시에 대한 필터링이 가능해야 합니다.
  • 출금, 입금만 선택해서 필터링을 할 수 있어야 합니다.
  • Pagination이 필요 합니다.
  • 다음 사항이 응답에 포함되어야 합니다.
    • 거래일시
    • 거래금액
    • 잔액
    • 거래종류 (출금/입금)
    • 적요

2) 입금 API

입금 API는 다음을 만족해야 합니다.

  • 계좌의 소유주만 요청 할 수 있어야 합니다.

3) 출금 API

출금 API는 다음을 만족해야 합니다.

  • 계좌의 소유주만 요청 할 수 있어야 합니다.
  • 계좌의 잔액내에서만 출금 할 수 있어야 합니다. 잔액을 넘어선 출금 요청에 대해서는 적절한 에러처리가 되어야 합니다.

4) 가산점

다음의 경우 가산점이 있습니다.

  • Unit test의 구현
  • Functional Test 의 구현 (입금, 조회, 출금에 대한 시나리오 테스트)
  • 거래내역이 1억건을 넘어갈 때에 대한 고려
    • 이를 고려하여 어떤 설계를 추가하셨는지를 README에 남겨 주세요.


📕 모델링


8퍼센트ERD



📕 작업 효율 개선 방안

  • Node.js, express, Sequelize, sqlLite, 회원가입 로그인 API, 거래내역 조회 API, 입금/출금API, 계좌생성 API를 구현하였습니다.
  • 인증, 인가를 위해 JWT와 쿠키를 활용했습니다.
  • 코드 컨벤션, 커밋 컨벤션, Git Flow를 지켜가며 작업했습니다.
  • Github Project, 마일스톤을 활용해서 백로그, 이슈 관리를 진행했습니다.
  • 계층 분리를 통해 코드의 가독성을 높였습니다.
  • 리팩토링을 통해 가독성을 높이고, 유지보수를 편하게 하기 위해 노력 했습니다.


💡 구현 기능

[ 회원가입, 로그인 ]

  • 인증방식은 JWT를 쿠키에 저장하는 방식으로 구현 하였습니다.

[ 입출금 API ]

  • 계좌 소유주만 요청 할 수 있게 구현 하였습니다.
  • 계좌의 잔액 내에서만 출금 할 수 있고, 잔액을 넘어선 출금 요청에 대해서는 적절한 에러처리를 하였습니다.

[ 거래내역 조회 API ]

  • 계좌의 소유주만 요청 할 수 있게 구현하였고, Pagination기능을 구현 하였습니다.
  • 거래 일시에 대한 필터링이 가능하게 구현 하였습니다.
  • 출금, 입금만 선택하여 필터링 될수 있게 구현 하였습니다.

[ 에러 핸들링 ]

  • 자바스크립트 자체 내장 Error 클래스를 상속 받아서, 커스텀 에러를 생성해서 관리했습니다.


➕ 협업을 위한 노력

  • 구성원들의 전체 의견을 반영하여 API 명세와 DB모델을 구축 하였습니다.
  • 긴밀하게 소통하여, 신속하게 문제를 인식하고, 신속하게 해결 하기 위해 노력 하였습니다.
  • 전체 작업을 도메인 단위로 분리하여 구성원 간의 병목현상을 줄였습니다.


🚥 거래내역이 1억건을 넘어갈 때에 대한 고려

1. subquery를 이용한 수동 execution plan

  • subquery를 이용해 시스템의 자동으로 생성되는 execution plan이 아닌 의도한 대로 최적의 탐색 방법이 나오도록 했습니다. 거래내역의 특성상 온전히 나의 거래내역만 보여주면 되고, cardinality 또한 의미있게 높을 뿐더러, FK index가 되어있어서 첫 where clause는 accountNumber에 할당 했습니다.
  • 다음은 입금,출금으로, 50%의 cardinality 기대값을 갖는 transactionType을 선정했습니다. 그리고 이전에 조회한 페이지에 이어서 연속한 페이지를 찾는 경우에는 이전의 탐색정보를 활용하여 높은 page 값에서의 overhead를 줄이고, 마지막으로 요청한 기간에 대해서 조건을 맞췄습니다.

2. pagination 기능 강화

  • 가장 간단하게 사용할 수 있는 pagination인 limit - offset의 경우, 결국 offset 만큼의 탐색을 진행해야 하기에 page 값이 높아질수록 overhead가 커지는 문제가 있습니다..
  • 그래서 이전 page의 마지막 row의 PK를 비롯한, 해당 사용자의 pagination context를 Cookie로 클라이언트에 전달했습니다.
  • 해당 context는 다음 조회 요청에 돌아와서, 새 요청과 비교하여 적용할 수 있는지를 판단합니다. 다만 Cookie에 광범위한 데이터를 기록할수는 없기에, 단순히 연속적으로 1페이지, 2페이지, 3페이지 순서대로 넘어가는 경우에만 효과를 받는 점은 아쉽다고 느끼는 부분입니다.

3. (미적용) Stored procedure와 Prepared statements를 이용한 network, compile overhead 감소

  • 실제로는 execution plan 이외에도, 어떻게 실행을 시작시킬지, 얼마만큼이 정확히 필요할지를 예측하는 것도 최적화에 있어서 중요하다고 생각합니다. 많은 DBMS에서 지원하는 기능인 Stored procedure와 Prepared statements를 사용하면 쿼리를 캐싱하는데 도움이 될거라 생각합니다.
  • 다만 이번 과제에서는 시간의 부족으로 이를 적용하지는 못했습니다.

4. (미적용) Table 분할 및 필요시 View를 이용한 통합

  • 아무리 index가 잘 되어있다고 해도, 전체 용량이 커지면 index도 커지고, 이는 INSERT와 DELETE 과정에서 추가적인 overhead가 계속 발생할 것임을 예상했습니다.
  • 이번과제에는 적용하지 못했지만 언젠가 1억건이 넘는 거래가 있다고 할때, 테이블을 분할하거나 분산저장시스템을 이용하는 것이 좋다고 생각합니다.


🛠 실행 방법

  • 레포지토리를 clone 받거나, 압축을 해제한 후 npm install을 통해 환경 셋팅을 진행합니다.
  • npm start를 통해 서버를 구동합니다.
  • src 폴더에 .env 파일을 설정해서, 환경변수를 설정합니다.
  • npm start로 서버를 구동시키고, npm test를 입력하면 단위 테스트가 가능합니다.
  • .env설정 노션 링크
    • 링크 접속불가 시 .env 파일 설정 방법
      PORT= '서버의 포트'
      JWT_SECERT= '원하는 시크릿코드'
      JWT_ALGO="HS256"
      ADMIN_USER="[email protected]"
      ADMIN_PASSWORD="1234"
      HOST="http://localhost:4000"
      IS_SQLLITE=true
      


🗂 과제 확인 및 평가 API 명세서

  • Postman을 활용하여 API 작동 테스트를 진행했습니다.

  • 배포된 서버 주소 및 자세한 API 명세는 아래에서 확인 가능합니다.

  • 🗂 API Description Link

  • Run in Postman 을 클릭하여 웹브라우저 혹은 Postman 클라이언트에 콜렉션이 로드되면

    1. Variables 탭에서 서버 Host와 Port를 지정합니다. (기본값이 지정되어 있습니다.
    2. Variables 탭에서 테스트하는 동안 사용할 username과 password 그리고 newProjectName을 지정합니다. (기본값이 지정되어 있습니다.)
    3. 그후 우측 상단의 Run 버튼을 눌러 RUN ORDER 화면에 진입한 뒤 Run [Collection Name]을 클릭하면, 이상적인 상황에서의 테스트가 진행됩니다.
    1. 좌측의 Workspace 화면에서 해당 콜렉션과 그 요청에는 여러 이상적이지 않은 상황의 테스트에 대한 예시가 있습니다.
      **유의사항**
      *일부 요청의 경우 JWT를 필요로합니다. JWT는 로그인 과정에서 "Set-Cookie" 헤더를 통해 클라이언트가 스스로 관리하게끔 전달됩니다.
    


😎 컨벤션 설정



🛠 Dependencies




🌲 File Tree



📦src
 ┣ 📂bin
 ┃ ┗ 📜www.js
 ┃
 ┣ 📂configs
 ┃ ┣ 📜db.js
 ┃ ┣ 📜index.js
 ┃ ┗ 📜secretKey.js
 ┃
 ┣ 📂controllers
 ┃ ┣ 📜accountController.js
 ┃ ┣ 📜transactionController.js
 ┃ ┗ 📜userController.js
 ┃
 ┣ 📂globals
 ┃ ┣ 📜index.js
 ┃ ┣ 📜responseMessage.js
 ┃ ┣ 📜routes.js
 ┃ ┗ 📜statusCode.js
 ┃
 ┣ 📂libs
 ┃ ┣ 📜encryption.js
 ┃ ┗ 📜jwt.js
 ┃
 ┣ 📂middlewares
 ┃ ┗ 📜auth.js
 ┃
 ┣ 📂models
 ┃ ┣ 📜account.js
 ┃ ┣ 📜index.js
 ┃ ┣ 📜transaction.js
 ┃ ┗ 📜user.js
 ┃
 ┣ 📂routes
 ┃ ┣ 📜accountRouter.js
 ┃ ┣ 📜globalRouter.js
 ┃ ┣ 📜index.js
 ┃ ┗ 📜userRouter.js
 ┃
 ┣ 📂services
 ┃ ┣ 📜accountService.js
 ┃ ┣ 📜transactionService.js
 ┃ ┣ 📜transactionServicePrepared.js
 ┃ ┗ 📜userService.js
 ┣ 📂test
 ┃ ┣ 📂data
 ┃ ┃ ┗ 📂dto
 ┃ ┃   ┣ 📜postAccount.json
 ┃ ┃   ┣ 📜signup.json
 ┃ ┃   ┗ 📜token.json
 ┃ ┗ 📂unit
 ┃   ┗ 📂controllers
 ┃     ┣ 📂userController
 ┃     ┃ ┗ 📜postAccount.test.js
 ┃     ┣ 📂userController
 ┃     ┃ ┗ 📜getTransaction.test.js
 ┃     ┃ ┗ 📜postTransaction.test.js
 ┃     ┗ 📂userController
 ┃       ┣ 📜postToken.test.js
 ┃       ┗ 📜postUser.test.js
 ┃
 ┣ 📂utils
 ┃ ┣ 📂errors
 ┃ ┃ ┣ 📜commonError.js
 ┃ ┃ ┣ 📜errors.js
 ┃ ┃ ┣ 📜tokenError.js
 ┃ ┃ ┣ 📜transactionError.js
 ┃ ┃ ┗ 📜userError.js
 ┃ ┣ 📜index.js
 ┃ ┣ 📜logger.js
 ┃ ┗ 📜resFormatter.js
 ┣ 📜.env
 ┣ 📜.eslintrc.json
 ┣ 📜.gitignore
 ┣ 📜.prettierrc.json
 ┣ 📜app.js
 ┣ 📜database.db
 ┣ 📜package-lock.json
 ┗ 📜package.json

About

8퍼센트 기업 과제

Resources

Stars

Watchers

Forks

Releases

No releases published

Packages

No packages published