4. 8percent - 거래내역 조회 API (은행계좌 관리 API)

문승준·2021년 11월 17일
0
post-thumbnail

과제 프로젝트 소개

과제 안내 & 레포지토리 링크

API 문서 링크

내가 구현한 부분

✔️ 거래내역 조회 API

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

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

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

뱅킹 시스템의 기본적인 API를 만드는 과제였고, 나는 위의 계좌별 거래내역을 조회하는 API 개발을 맡았다. 추가적으로 거래내역이 1억건이 넘어가는 경우를 고려해보라는 내용이 있었다. Django를 사용해 API를 만들고 각종 Loadtest 방법에 대해 알아보기로 했다.


개발 과정

1일차 - 모델링과 초기세팅

  • 회원정보, 계좌, 입출금내역, 거래종류를 나타내는 4개의 테이블을 작성했다. transactions 테이블이 너무 커질 수 있으니 입금과 출금 테이블을 나누자는 의견도 있었다. 하지만 전체 내역을 보여줄때마다 두 테이블을 조인하고 시간순으로 다시 정렬을 하는 과정이 추가로 필요하고 대부분의 거래내역 조회는 전체 조회일 거라는 생각에 하나의 테이블로 관리하기로 했다.

  • 과제내용에 계좌 잔액을 별도로 관리하라는 부분이 있었는데, 입출금 거래 후 계좌잔액과 실제 계좌 잔액의 일치성을 보장하라는 것으로 이해했다. 보통 계좌내역을 조회하면 해당 거래 후의 잔액이 각각 표시되기 때문에 balance_after_transaction 컬럼을 따로 추가해주었다.

  • 입금과 출금을 구별하기위해 정규화된 테이블 transaction_types을 만들었다. transaction_types에는 2가지 거래 종류 (입금, 출금)만 다루기로 했다. 따라서 models.py를 작성할때 아래처럼 Enum class를 활용해보기로 했다.

  • 간과한 부분

한명의 유저가 여러개의 계좌를 가질 수 있는 상황으로 가정했다. 거래 종류 테이블을 나눴듯이 계좌의 type을 나눌 수 있는 테이블을 만들지 않았다. 따라서 유저의 계좌(account) 내역을 보여줄때 어떤 계좌인지 구분을 할 수 없었다.

만약 account_types 테이블을 만들어 구분했다면 django에서 filter로 type을 지정할 수 있었을 것이다. 우선은 이 부분을 인지한채로 DB에 유저당 하나의 계좌만 생성했고 쿼리셋 get 메소드로 계좌를 불러왔다.

최소한의 기능만 구현하더라도, 경우의 수를 생각해보고 필요한 모델링은 모두 해놔야한다고 느꼈다.

추가로, account balance를 positive integer field로 했는데 21억 정도까지만 가능하다는 것을 뒤늦게 알았다. positive big integer field로 했어야한다.

2일차 - 거래내역 조회 로직

  • 조건에 따른 필터링을 하기 위해 request.GET.get()으로 쿼리 파라미터를 받아왔다. 필수 파라미터로 정한 기간 정보는 시작일과 종료일을 받아와서 datetime 객체로 변환한다음 필터로 적용했다.

    테스트를 해보던 중 단 하루치만 검색하는 상황에서 조회가 안되는 문제가 발생했다. 파라미터로 년-월-일 만 받아오는데 DB의 데이터엔 시-분-초 까지 포함되어 있는 것이 문제였다. 결국 아래의 마지막 코드에서 처럼 종료일에 하루를 더해주는 방법으로 해결했다.

  • 로직을 작성하고보니 6개의 쿼리 파라미터를 받는 것이 너무 많은 것은 아닌지 고민이됐다. HTTP GET이 아닌 POST가 더 나은 것은 아닐지 고민을 해봤다.

    실제 은행 사이트에 접속해 내 계좌를 조회하면서 개발자도구로 네트워크 탭을 확인해보려했지만, 브라우저 캐싱 혹은 암호화 때문인지는 모르겠지만 정확한 확인이 어려웠다.

    결국 파라미터가 여러개여도 (데이터를 변경하지 않는) 단순 데이터 조회는 GET을 활용하는 것이 맞다는 결론을 내렸다. url 길이 제한에 영향을 받을 정도는 전혀 아니고, 정렬이나 필터링에는 쿼리 파라미터를 사용하는 것이 기본이라고 생각했다.

  • 추후 filter_prefixes와 filter_set을 만들어서 적용해보려고 한다.

현재 구조상 만약 각 파라미터가 선택적으로 들어온다면 if문으로 걸러가며 필터에 추가할 것이다. 이렇게 분기가 많아지면 디버깅도 어렵고 좋은 구조가 아니라고 들었다. 딕셔너리 컴프리헨션을 활용해 filter_set을 만들면 그런 문제를 해결할 수 있을 것이라 생각한다.


느낀점과 개선점

로드 테스트

  • Loadtest를 담당한 팀원분들이 db_uploader를 작성해 5천만개의 테스트 데이터를 만들고 Postman으로 확인해보았다. 데이터가 많은 만큼 조회 성능에 차이가 있을거라 생각했지만 로컬환경이라서 그런건지 성능면에서 큰 차이가 없었다.

    models.py의 account 컬럼에 Index를 추가해보기도 하며 여러 시도를 해보았으나 의미있는 성능 차이를 느끼기 어려웠다. Indexing과 Partitioning에 대한 의견도 나누었는데 무조건 적용할게 아니라 상황에 따라 단점도 생길 수 있다는 것을 알수 있었다.

  • 내가 맡은 부분은 아니었지만 추후 로드 테스트 상황에 대비해 몇가지 툴과 사용법을 찾아보았다.

    locust를 이용하면 유저의 행동을 파이썬 코드로 작성해놓고 동시 접속자수를 늘려가며 테스트를 해볼 수 있었다. 간단하게 계좌를 조회하는 API로 많은 요청을 보내봤는데 문제는 테스트 결과를 보고도 정확한 분석을 하지 못했다는 점이었다.

    아직은 성능에 대한 기준이 없어서 판단이 어렵지만 계속해서 이런 테스트를 시도하고 익숙해져서 데이터베이스와 네트워크 성능을 고려한 코드를 작성해야겠다.

페이지네이션

  • 지금까지 offset, limit 값을 이용해 기본적인 페이지네이션을 구현했다. 또한, DB에 무리가 가는 경우가 없어야 한다는 생각에 limit 값의 한계를 정해두었고 그 이상을 요청하면 적절한 에러를 반환하도록 했다.

    Django가 제공하는 paginator를 사용했던 적이 있는데, 보다 원리를 파악하는 형태로 만들어보라는 조언을 듣고 offset, limit을 사용했었다. 이제는 클라이언트 입장에서 명확한 파라미터 값을 정할 수 있도록 page와 perPage 값을 활용하는 방법도 고민해봐야겠다.

    새로운 것을 배우는 것도 중요하지만 이미 알고있는 부분을 더 개선하는 것도 필요하다고 생각한다.

  • 다른 팀이 적용했던 Cursor-based pagination에 대해서 간략하게 알아보았다.

    • Offset 기반 페이지네이션의 문제점

      1. 다른 페이지를 요청하는 사이에 데이터가 추가되면 중복으로 노출된다.

      2. 테이블의 row와 offset 값이 커질수록 쿼리 퍼포먼스가 떨어진다.

    • Cursor 기반 페이지네이션의 개념

      1. 클라이언트가 가져간 마지막 row의 다음 row부터 n개의 요청에 응답한다.

      2. 반드시 정렬 기준이 되는 필드 중 적어도 하나는 고유값이어야 한다. -> 대부분 timestamp로 한다.

  • 프로젝트를 마치며

평소 핀테크에 관심이 많아서 관련 프로젝트를 해보고 싶었는데 좋은 기회가 되어서 즐겁게 개발했다. 실제 유저 스토리를 생각해보고 transaction을 고려해보는 과정이 재밌으면서도 더 많은 고민거리가 생겨났다. 특히 이번 과제의 키포인트인 거래내역이 1억건이 넘는 상황에 대해 팀원들과 많은 의견을 나눴던 것이 기억에 남는다.

앞으로 더 공부해야할 부분

  • DB - Index 활용법과 장단점
  • DB - Partitioning 활용법과 장단점
  • Django, Python - 쿼리 파라미터가 많은 경우 효율적인 View 로직
  • Test - DB 부하 테스트를 위한 Seeding
  • Test - 네트워크 부하 테스트를 위한 Locust 결과 분석

profile
개발자가 될 팔자

0개의 댓글