본문 바로가기

전체 글

구독 테이블 설계 관련 - 사용자 구독 플랜 정보 조회 방식 개선 사용자 구독 플랜 정보 조회 방식 개선기존에는 구독 플랜 정보를 조회하려면 subscription -> subscriptionPrice -> subscriptionPlan 테이블을 순차적으로 조인해서 planType 컬럼의 정보를 알아내야 했다. 이는 내가 설계한 구조이기 때문에, 처음 이 구조를 접하는 다른 개발자 입장에서는사용자의 구독 플랜을 알고 싶을 때 어느 테이블을 조회해야할 지 바로 파악하기 어렵다는 문제가 있다.(ex. 이 사람이 Basic 플랜 유저인 지 알려면 어느 테이블을 뒤져야하죠?! 라고 나에게 매번 물어봐야 한다.)  이러한 문제를 해결하기 위해, 팀원들과 상의한 결과user 테이블에 planType 컬럼을 추가하여사용자가 구독 중인 플랜이 Free, Basic, Premium 중.. 더보기
구독 테이블 설계 (+ 무료체험) 요즘 구독 테이블 설계를 하고 있다.이미 만들어져있는 구독 서비스를 유지보수 해본 적은 있지만 구독 테이블을 직접 설계하는건 처음이다.이 과정에서 동료와 의견 차이가 있어서 그 과정을 기록하고자 한다.총 2가지 논제가 있었다. 주제 1) 구독 테이블 설계 - 한 줄로 관리할 것인가, 매 월 새로운 행을 추가할 것인가?구독 시스템을 설계하는 과정에서 동료 개발자와 구독 테이블 관리 방식에 대해 의견 차이가 있었다. 📌 나의 주장 - 한 개의 row 를 유지하며 갱신하는 방식- 유저가 특정 플랜을 구독하면 subscription 테이블에 한 개의 row 가 INSERT 됨- 매달 결제가 이루어질 때 currentPeriodStart, currentPeriodEnd 를 업데이트하여 현재 구독 기간을 관리- .. 더보기
검색 기능 구현을 위해 mysql full text search 이용하기 검색 기능 구현을 위해 mysql full text search 를 이용하는 과정에서내가 왜 ngram parser 를 선택했는 지 그 근거를 정리하고자 한다.  1. parser 종류mysql full text search 에서는 대표적으로 built-in mysql parser 와 ngram parser 를 제공한다.공식 문서에는 다음과 같이 말하고 있다.- mysql 에서 기본적으로 제공하는 built-in parser 는 공백을 통해 단어의 시작과 끝을 결정함ex) "hello world" -> hello 와 world 를 각각 단어로 인지 - 그러나 한국어는 공백으로 단어의 시작과 끝을 판단할 수 없어서 built-in parser 를 이용하는게 의미가 없음- 이를 해결하기 위해 ngram pa.. 더보기
API 설계 고민: 휴지통 검색 기능 1. 개요내가 했던 고민을 말하기 전에 개발 중인 앱의 컨셉을 먼저 설명하겠다.이 앱에는 휴지통 개념이 존재하고 이 휴지통에는 [폴더] 와 [파일] 이 존재할 수 있다.우리 앱 화면을 캡쳐할 수는 없어서 비슷한 구조인 구글 드라이브 캡쳐를 참고용으로 가져와봤다. 휴지통에 있는 파일이든 폴더든 더블 클릭하는 순간 "복원 하시겠습니까?" 알럿이 뜬다.   현재 우리 앱의 휴지통이 동작하는 방식도 구글 드라이브와 비슷하게 아래와 같다. 1. 폴더 구조- a > b > c 형태의 중첩된(Nested) 폴더 구조를 가짐. 2. 폴더 삭제- 상위 폴더 a가 삭제되면 b와 c를 포함한 모든 하위 폴더가 함께 휴지통으로 이동. 3. 복원 동작- a 폴더를 복원하면, 포함된 모든 하위 폴더(b, c)가 함께 복원됨.- .. 더보기
DB 설계 고민: 폴더 기능 구현하기 (Tree Structure) 폴더 기능을 구현할 일이 생겼다.폴더 안의 폴더가 있을 수 있는 트리 구조이다. 트리 구조를 DB 에 저장하기 위한 대표적인 4가지 패턴이 있다.- Adjacency list- Nested set- Path enumeration- Closure table 진행 중인 프로젝트에서 TypeORM 을 사용하고 있는데,TypeORM 에서는 트리 구조에 대한 4가지 패턴을 라이브러리 단에서 전부 지원하고 있으므로어떤 패턴을 선택해야할 지 결정해야 했다. 조사를 하면서 tree 구조에 대해 아주 잘 설명되어 있는 이 PPT 가 굉장히 큰 도움이 됐다.각 특징을 간략하게 정리해보면 다음과 같다. 1. Adjacency listparentId 컬럼만 들고 있으면 되는 방식이다.자신의 직계 부모나 직계 자식은 쉽게 조회.. 더보기
오랜만에 사용한 EXPLAIN (쿼리 실행 속도) 서비스 출시 하는 데에 급급해서 솔직히 "쿼리 퀄리티" 는 안 따진지 오래다.그렇다고 개판으로 짜진 않지만, 경력을 쌓으며 자연스레 알게 되는 기초적인 쿼리 개념들만 적용하면서 개발을 해왔다.기초적인 것이라 함은- 검색 쿼리를 날릴 때 해당 컬럼에 index 걸면 좋다던가..- like %검색어%  는 풀스캔을 타니까 지양해야 한다던가..- select * 은 하면 안 되고, 필요한 것만 지정해서 select 해야 한다던가..- order by 사용하는 컬럼에 index 를 추가한다던가 사실 내가 잘못하는 거일 수도 있는데..  실무에서 생각보다 쿼리 EXPLAIN 을 쓸 일이 거의 없었다.예전에는 평균 동접자 3000명 정도의 서비스를 고도화 한 적 있었는데그때는 레거시 코드로 인한 쿼리 이슈가 꽤 많.. 더보기
TypeGraphQL 을 잘못 쓰고 있는 걸 깨달았을 때 (aka. @ObjectType 생성자 금지 조항) 배경한동안 Nest.js 프레임워크를 사용하며 API 응답 클래스를 세팅할 때, 클래스의 생성자 쪽에서 데이터 세팅 작업을 했다클래스 생김새는 다음과 같다export class NeighborItemsResponse { @Exclude() private readonly _previous: NeighborItemResponse | null; @Exclude() private readonly _next: NeighborItemResponse | null; constructor( previous: NeighborItemResponse | null, next: NeighborItemResponse | null, ) { this._previous = previous; this._nex.. 더보기
API 설계 고민: Partial Update 한 화면에서 여러 속성을 수정할 수 있는 UI 가 있을 때, API 구조를 어떻게 짜야할 지 고민이었다.이른바 partial update 가 가능한 화면  GitHub 의 이슈 등록 화면이 내가 고민했던 UI 구조와 비슷해서 가져와봤다. 이슈 화면에는 제목, 내용, Assignees, Labels 등 수정 가능한 속성들이 참 많다.  Partial Update 에 대한 API 설계 방식.. 크게 2가지 중 고민이 되었다.1. 하나의 API 로 퉁치기- PATCH /issues/{id}하나의 API 로 제목도 수정할 수 있고 Assignees 도 수정할 수 있는 구조다.그렇게 하려면 서버에서는 api input 필드를 전부 옵셔널로 설정하고  클라이언트는 수정된 속성만 서버로 전송해야 할 것이다.  2. .. 더보기