인트로
이전 글(1편)에서는 이번 시리즈의 주제와 글을 쓰게 된 배경을 소개했다.
[그리고 시큐리티를 곁들인] #1 : 시리즈 소개 - 소셜로그인과 JWT 기반 인증/인가, 그리고 Spring Security를 곁들인
시프링 시큐리티에 대한 경험과 이번 시리즈에 대한 소개 글입니다.
0woodev.tistory.com
이번 게시글은 시리즈 2편으로, 요구사항과 그에 따른 프로젝트 설계, 그리고 유저 도메인 ERD 설계를 다루고자 한다.
프로젝트 설계
I'm Game 프로젝트는 서버 - 클라이언트 구조로 설계하고자 한다.
프론트엔드는 Typescript 와 React, Recoil 그리고 Styled Component 를 주로 사용한다.
백엔드는 Java 17, Spring Boot 3, Spring Security 6.x, OAuth2, JPA(Spring Data JPA), PostgreSQL, JUnit5, Mockito 을 쓰려고 한다.
기술 스택 선정 이유
Java 와 Spring Boot
Java 와 Spring Boot 3 을 선택한 이유는 해당 기술스택의 전문가가 되고 싶어서다. 다른 언어와 프레임워크 대신 선택한 이유가 무엇이냐 묻는다면, 이 내용에 대해서는 다른 포스트에 깊게 적어보려고 한다. 다만, 최근 사용했던 언어들의 이론적인 장점과 별개로 개인적으로 Java 의 강타입 언어의 장점을 많이 느꼈거 Spring Boot 의 다양한 자료와 성숙도가 필자가 이 기술스택으로 커리어를 쌓아나가고 싶은 이유이다.
RDB 와 PostgreSQL
NoSQL 과 RDB 중 RDB 를 선택한 이유에는 서비스하는 메인 기능에 대해서 다양한 조회방식이 현재 예상되고 있으며, 이미 1차 MVP 를 만들고 사용자들을 만나본 후 방향성을 다시 조정한 후 시작한 프로젝트였기에 조금 더 기능 변경( = 칼럼 추가를 의미하는 것이 아닌, 조회 방식의 변경을 의미합니다 )에 있어 확장성이 큰 RDB 를 선택했다.
이유가 이상하다고 생각이 드실 수 있는데, 필자가 사용해본 DynamoDB 는 상대적으로 키-값 데이터베이스로 Partition Key 와 Sort Key, GSI 에 대한 설계가 다소 까다롭기에, 추후 기능이 어느정도 정착이 된 후 마이그레이션을 하면 좋을 것 같다고 생각한다.
RDB 중 PostgreSQL 는 Json 필드의 강력한 기능을 제공한다. 또한 데이터베이스 차원에서 sequence 를 지원하기에 Bulk Insert 구현이 간편하다. 이전 프로젝트에서 MySQL 과 Spring Boot 를 사용했을 때, Bulk Insert 가 잘 안되었던 경험이 있었기에, PostgreSQL 을 선택했다.
JPA 와 Spring Data JPA
JPA 를 선택한 이유는 비즈니스 로직에 더 집중하고, 객체 지향적인 코드에 집중하기 위함이다. MyBatis 같은 매퍼 방식을 사용하게 된다면, SQL 에 대한 강력한 권한을 가지는 것은 맞지만, 칼럼이 추가, 삭제 될때마다 Mapper 클래스를 전부 수정하고, 쿼리도 수정해야하는 상황이 온다. 그렇기에 JPA 를 좀 더 선호한다. Spring Data JPA 는 JPA 를 진짜 편하게 사용할 수 있게 해준다. (다만, 기본적인 부분에서 말이다). 코드를 작성하다보면, 가끔은 복잡한 쿼리가 필요한 순간들이 온다. 이럴 때에는 JPQL 이나, QueryDSL, Spring JDBC 까지 사용할 수 있다.
JUnit5 와 Mockito
1편에서 소개했던 2022년에 했던 BUFF 프로젝트에서는 Mockito 라이브러리 없이 직접 구현하여 TDD 방식으로 개발을 진행해왔었다. 주로 Service 레이어 같은 경우, Spy 방식을 사용했고, Repository 는 Fake 방식으로 직접 구현했다. 그렇기에 Mockito 의 문법이나 이런 부분을 몰라도 쉽게 구현할 수 있다는 장점이 있었으나, 직접 구현한다는 것은 결국 유지보수할 코드의 양이 늘어난다는 얘기랑 같다. 단순히 새로운 기능을 만드는데 있어서 TDD 를 적용하는 것은 시간 소모가 크지 않았다. 하지만, 대규모로 리팩토링을 하는 순간, 그동안 작성해두었던 모든 테스트코드들이 먹통이 된다. 즉, 모든 Fake 클래스, Spy 클래스 또한 다 수정해야만 했었다.
물론, Mockito 를 쓴다고해서 리팩토링할 때, 수정하지 않아도 된다는 말은 아니다. 다만, 리팩토링의 규모에 따라 수정해야할 코드의 양에서 차이가 있을거라는 얘기이다.
Mockito 를 적극 사용해보면서, 과연 어떤 것이 더 좋을지 몸소 느껴보고 싶기에 이번 프로젝트에서는 Mockito 를 도입하기로 했다.
다른 포스트에서 "테스트코드, 넌 어디까지 해봤니?" 라는 제목으로 글을 작성하려고 한다. 투비컨티뉴
요구사항 분석
I'm Game 은 글로벌 서비스를 목표로 하기 있기에, 유저의 가입, 로그인에 관련해서는 소셜로그인과 ID/PW 방식을 모두 사용할 수 있도록 하려고 한다.
I'm Game 프로젝트의 유저 도메인에 대한 요구사항은 다음과 같았다.
1. 여러 계정을 가질 수 있다
2. 여러 소셜로그인방식으로 한 계정을 이용할 수 있다
3. 성별, 나이를 입력해야 서비스를 이용할 수 있다
4. 로그인 방식에는 ID/PW 와 소셜 방식 두가지가 있으며, 두 방식 모두 가능하다.
요구사항에 대해 설계하기 전에 도메인부터 정의해보자.
용어 | 정의 |
유저 | 서비스를 이용하는 한 계정 |
사용자 | 유저의 실 소유주 ( = 사람 ) |
Credential | 유저에 연동되어 있는 소셜로그인 방식 ( ex - 카카오, 구글 .. ) |
Profile | 유저의 상세 정보 ( ex - 성별, 나이, 닉네임 ) |
Password | 유저의 비밀번호 |
위 도메인으로 요구사항을 다시 적어보면 다음과 같이 해석할 수 있다.
1. 사용자는 여러 유저가 될 수 있다
2. 유저는 여러 개의 Credential 을 가질 수 있다
3. 유저는 Profile 이 없거나 1개 가질 수 있으며, 1개가 있어야 서비스를 이용할 수 있다
4. 유저는 Password 를 없거나 1개 가질 수 있다
유저 도메인 ERD 설계
우선, null 필드를 많이 만들지 않으려고 했다. nullable 한 필드가 있는 경우, 검색하는데 있어 성능적인 저하도 있다고 알고 있다. 이 부분에 대해서 설계할 당시에는 기억에 잘 남았지만, 지금 글을 적는 이순간에는 정확하게 기억이 나지 않기에, 다른 포스트에서 한번 정리해보겠다.
1. 한 유저가 여러 Credentials 를 가질 수 있어야 한다 (테이블을 분리하는 것이 더 나을 거라 판단했다. 제 2 정규화)
- `user` 1 - N `user_credentials`
2. 한 유저가 소셜 로그인으로 회원가입을 하는 경우, password 는 생성되지 않는다. (nullable 한 필드가 되기에 필드로 분리, 보안에 관련된 정보이므로, 다른 테이블로 분리)
- `user` 1 - 0, 1 `user_passwords`
3. 한 유저의 정보가 입력이 되어야 서비스를 이용가능하다. 유저 생성시점과 프로필정보 입력 시점이 다르다. (같은 테이블에 둔다면, nullable 한 필드로 두어야 하므로 분리)
- `user` 1 - 0, 1 `user_profiles`
4. 소셜로그인과 ID/PW 방식 혼용이 가능하다. -> user_passwords 테이블과 user_credentials 테이블에 데이터가 있다면, 가능하다.
시큐리티 시리즈 3번 포스트로 넘어가보자.
[그리고 시큐리티를 곁들인] #3 : ID/PW 방식의 회원가입과 로그인과 JWT 토큰 발급
TO BE CONTINUE
0woodev.tistory.com
'백엔드' 카테고리의 다른 글
[그리고 시큐리티를 곁들인] #6 : 백엔드 전담의 소셜로그인 구현, Spring Security, OAuth2 를 이용한 (0) | 2024.10.01 |
---|---|
[그리고 시큐리티를 곁들인] #5 : 소셜로그인 방식에 대한 삽질기 (0) | 2024.09.16 |
[그리고 시큐리티를 곁들인] #4 : Spring Security 를 이용한 JWT 인증/인가 (0) | 2024.08.13 |
[그리고 시큐리티를 곁들인] #3 : ID/PW 방식의 회원가입과 로그인과 JWT 토큰 발급 (0) | 2024.08.12 |
[그리고 시큐리티를 곁들인] #1 : 시리즈 소개 - 소셜로그인과 JWT 기반 인증/인가, 그리고 Spring Security를 곁들인 (2) | 2024.08.11 |