Code Monkey home page Code Monkey logo

hello-world's Introduction

🌐 Hello World!

  • Share Your Passion Through Languages

image (사진 출처: https://cudoo.com/blog/why-language-exchange-platforms-are-perfect-for-language-practice/)

🗺️ 개요

언어 학습을 하면서 과거에 여러 언어 교환 플랫폼을 사용해 본 경험이 있습니다. 당시에는 무심결하게 넘어갔지만 개발 공부를 시작하면서 다시금 떠오른 생각이 도대체 어떻게 전 세계에서 들어오는 수많은 트래픽을 견디면서 장애없이 서비스를 지속할 수 있을까? 에 대한 부분이었습니다. 또한 여러 사용자로부터 발생하는 수많은 데이터는 어떻게 보관하고 있는지에 대한 부분도 궁금했습니다. 본 프로젝트는 이러한 궁금증과 언어 학습에 대한 개인적인 애정으로부터 시작하게 되었고, 전 세계 곳곳에 거주하고 있는 여러 언어 학습자들을 연결해주고 있는 다양한 언어교환 플랫폼을 모티브로 하고 있습니다.

🗺️ 중점과제

1. 기능구현에만 집중하지 않기

  • 빠르게 구현하는 것보다 더 중요한 것이 작성하는 코드나 사용하는 기술을 정확하게 알고 사용하는 것이라고 생각합니다.

  • 때문에 새로운 기술을 적용할 때 해당 기술에 대한 학습도 함께 진행하여 기초를 튼튼히 세워 적재적소에 필요한 기능을 배치하고, 필요하면 응용도 할 수 있는 능력을 키우고자 합니다.

  • 작성하는 코드에 대해서는 예시를 보고 단순히 copy&paste하는 것이 아니라 깊이 생각하고 이해함으로써 완전히 내것으로 만들 수 있도록 노력할 필요가 있습니다.

2. 항상 대용량 트래픽을 염두에 두기

  • 프로젝트의 최종 목표는 대용량 트래픽 속에서도 빠르고 안정적인 서비스를 만드는 법을 배우는 것입니다.

  • 따라서, 항상 다수의 트래픽을 기본 전제로 하여 섬세하게 설계해 나가고자 합니다.

3. 유연하고 확장성이 좋은 코드 작성

  • 기술이 발달할 수록 비즈니스 환경도 빠르게 변화합니다. 이러한 변화 속에서 살아남기 위해서는 유연하고 확장성이 좋은 깔끔한 코드를 작성하는 것을 목표로 해야 합니다.

  • 이를 달성하도록 도와주는 것이 바로 객체지향 패러다임입니다.

  • 이러한 이유로 본 프로젝트에서는 객체지향에 충실한 코드를 작성해보는 것을 최우선 순위 중 하나로 두었습니다.

4. 테스트 코드 작성에 충실하기

  • 올바른 기능 구현을 위해 구조를 적절히 설계하고 이를 뒷받침 해줄 깔끔한 코드를 작성하는 것은 중요합니다. 그러나 이보다 더 중요한 것이 구현한 기능을 제대로 테스트 하는 것입니다.

  • 실제로 어플리케이션 서버를 구동해서 구현한 기능을 테스트 할 수 있지만 이 방법은 명확한 한계가 존재합니다.

예시
1. 해당 어플리케이션이 의존하는 서비스(ex. DB) 들이 사전에 구동 중이어야 함
2. 테스트 내용을 변경하기 위해서는 값을 변경한 뒤 컴파일, 빌드 등의 과정을 다시 거쳐야 하므로 시간 소요도 많이되고 번거로움
3. 가장 큰 문제는 `눈에 보이는 부분`만 확인이 가능하다는 점 
  • 테스트 코드를 활용하면 여러 조건 하의 다양한 시나리오에서 실패, 성공을 확실하게 확인할 수 있습니다.

  • 또한, 테스트 코드는 구현한 기능이 의도대로 동작한다는 것을 일정 수준 이상 보장해 주는 역할을 합니다.

  • 특히, 단위 테스트의 경우 다른 의존성을 Stub으로 대체하기 때문에 해당 컴포넌트들로 부터 발생한 문제의 전이로 인한 실패를 미연에 방지할 수 있고, 본 기능만 테스트 하므로 실행속도가 매우 빨라 언제든지 테스트를 부담 없이 실행해볼 수 있다는 장점이 있습니다.

  • 그래서, 작성한 비즈니스 로직에 대한 단위테스트를 최대한 꼼꼼히 작성함으로써 테스트 커버리지를 높여 기능의 명확한 동작을 보장하고, 차후에 코드를 리팩토링하거나 CI를 도입하는데 있어서도 이러한 테스트 코드를 바탕으로 신속하고 정확하게 문제가 없음을 보증할 수 있도록 하는 것을 목표로 합니다.

🗺️ 사용기술

🗺️ 프로젝트 전체 구성도

image

🗺️ DB ERD

image

🗺️ 기능정의

🗺️ 테크니컬 이슈와 해결과정

hello-world's People

Contributors

msugo1 avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar

Forkers

chrisloarryn

hello-world's Issues

[#8] 이메일을 활용한 비밀번호 찾기 구현

📖 구현 항목

🔖 유저 아이디 및 비밀번호 확인

  • 이메일 전송에 앞서 전달받은 요청 정보를 활용해 DB에서 사용자 존재유무이메일 일치 확인
  • 사용자가 존재하지 않거나 이메일이 일치하지 않는 경우에는 예외 발생

🔖 임시비밀번호 및 메일 내용을 담을 객체를 만들 클래스 작성

  • 위의 검증과정을 통과하면 UUID를 이용해 사용자에게 전달해줄 임시 비밀번호를 생성
  • 발급한 임시비밀번호를 포함해 메일의 제목과 내용을 담을 수 있을 객체를 생성하기 위한 클래스 생성

🔖 메일 발송기능

  • 위에서 담은 내용을 이메일로 만들어 발송해 줄 EmailService 클래스 작성

🔖 위의 기능을 테스트하기 위한 테스트 작성

[#23] MySQL Replication 설계

📖 구현이 필요한 항목

🔖 RDBMS의 부하 분산을 줄여주기 위한 설계 구현

  • Master-Slave 구조를 설정하여 CRUD의 CUD를 주로 Master 서버에서 처리하고, 이를 Slave로 동기화 하는 방식으로 만들기
    (데이터의 정합성이 중요한 읽기 데이터의 경우는 마스터에서 바로 읽을 수 있도록 해보기)

  • Slave에서는 CRUD의 R을 주로 담당하는 구조로 만들기

[#38] 조건에 맞는 사용자를 검색할 수 있는 기능 구현

📘 개요

  • Hello-World 서비스를 사용하는 사용자들이 등록된 다른 사용자들을 자신이 원하는 조건에 맞게 검색함으로써 더욱 적절한 언어교환 상대를 찾을 수 있도록 지원합니다.

📖 구현 항목

조건에 맞는 사용자들의 프로필을 불러올 수 있도록 커서 방식의 페이징을 활용한 사용자 프로필 찾기 기능 구현하기

(이때, 전체 사용자들 프로필 조회에서 사용했던 부분을 재사용할 수 있다.)

  • 다른 사용자들의 정보를 현재 사용자가 원하는 조건에 맞게 가져올 수 있도록 하는 기능 구현하기

📖 테스트

  • Validator 내용에 대한 단위 테스트 작성하기

  • 조건이 여러개가 부여되는 만큼 직접 통합테스트를 작성해서 동작 여부 확인하기

  • 포스트맨을 활용해 전반적인 동작 테스트

[#41] Firebase Cloud Messaging을 활용한 Push 알람 구현

📖 개요

  • 친구 추가/수락, 추천글 남김 등의 행동이 발생하면 대상 사용자가 이를 확인할 수 있도록 촉진하는 매개체가 필요

  • Push 알림을 통해 이러한 부분을 해결 가능

📖 구현내용

  • Firebase Cloud Messaging 설정 추가

  • 클라이언트가 FCM 서버로부터 전달 받은 토큰을 서버에 보관할 수 있도록 로그인 메소드 수정 및 DB 설계

  • 토큰을 저장, 갱신하고 얻어올 수 있는 기능 구현하기

  • 등록된 토큰을 통해 토큰을 등록한 사용자에게 푸시 알림을 전송할 수 있도록 FCM 서버에 요청하는 기능 구현하기

[#31] 프로세스 자동화를 위해 프로젝트와 CI 연동하기

📘 개요

  • CI란 지속적 통합(Continuous Integration)의 줄임말로써 빌드 -> 테스트 -> 통합으로 이어지는 과정을 자동화 함으로써 개발자들이 더 빠른 주기로 작업/업데이트한 내용을 통합 Branch에 통합하고 빌드하는 개발 방식을 의미한다.

  • CI가 등장하기 전에는 위의 지난한 과정을 모두 수동으로 일일이 거쳐야 했다.

  • CI를 도입하면 이러한 단계를 자동화하여 생산성을 증대시킬 뿐만 아니라 작업 내용을 통합하기 전에 빌드 테스트가 먼저 실시되어 내용을 검증하므로 통합된 코드에 대한 안정성신뢰성이 올라가게 된다.

📖 항목

  • CI를 적용하기 전 CI와 CI의 발전과도 연관이 있는 agile 방법론에 대해서 학습하기

  • Azure 클라우드를 통해 Jenkins 설치하기

  • JenkinsGitHubWebhook을 통해 연결하여 PR시 Jenkins가 해당 사실을 인지할 수 있도록 설정하기

  • CI 파이프라인을 구축해서 Poll -> Build -> Test 과정의 자동화를 실현하기

📖 테스트

  • 적용한 CI가 잘 작동하는지 테스트하기

[#9] 회원탈퇴 기능 구현

📖 구현이 필요한 항목

🔖 회원탈퇴 기능 로직 구현

  • 해당 서비스 이용을 중지하려는 회원들에게 제공할 회원탈퇴 기능 구현
  • 물리삭제가 아닌 논리삭제를 이용
  • 회원 탈퇴 로직을 처리하기 전 비밀번호를 재확인하고 DB에 저장된 비밀번호와 일치하지 않을 경우 예외 던지기

🔖 위의 로직을 테스트하기 위한 테스트 작성

[#13] 친구 추가 기능 구현하기

📖 구현이 필요한 항목

🔖 친구추가 기능 로직 구현하기

  • 사용자가 친구 추가할 수 있는 기능 구현하기

🔖 위의 로직을 테스트하기 위한 테스트 작성하기

  • (성공 케이스)

  • (실패 케이스)

[#19] 로그인 확인 기능 추가

📖 결정이 필요한 항목

🔖 Filter vs Interceptor vs AOP

  • 각각에 대해 조사하기

  • 각각의 특성을 고려하여 최선의 결정 내리기

(셋 중에 무엇을 선택했는가?) Interceptor

  • 블로그에 의사 결정 프로세스에 대한 글 작성

📖 구현이 필요한 항목

  • 사전 로그인 체크 기능 구현

[#42] 특정 사용자에게 메시지 보내기 기능 구현

📖 개요

  • 사용자 간의 지속적인 언어교환을 더욱 편리하고 효율적으로 도모할 수 있도록 하는 메신저 기능이 필요

📖 구현내용

  • 서버 측에서 클라이언트로부터 WebSocket 연결 요청을 받아 처리할 수 있도록 하는 설정 추가하기

  • 메시지 전송 요청을 매핑하여 해당 메시지는 DB에 저장하고, 대상 사용자에게는 알림을 보낼 수 있도록 하는 기능 구현하기

  • 위의 로직을 테스트 할 단위 테스트 작성하기

[#39] 개발 환경에 따라 properties 파일을 분리하기

📖 구현이 필요한 항목

🔖 환경에 따라 properties 파일 분리하기

  • 실제 서비스 운영 환경을 위한 properties 파일 작성하기

  • 개발 중에 사용할 로컬 환경을 위한 properties 파일 작성하기

  • 테스트시 사용 될 테스트 환경을 위한 properties 파일 작성하기

  • 필요한 설정/테스트 파일에 @Profile, @ActiveProfile 적용하기

[#34] 특정 사용자의 프로필을 조회할 수 있는 기능 구현하기

📘 개요

  • 서비스를 이용하는 사용자가 자신에게 맞는 다른 사용자를 찾기 위해서 각 사용자들의 프로필 정보를 조회하고 정보를 수집함으로써 언어교환 파트너를 찾는데 도움을 주기 위한 기능

📖 구현 항목

  • users 테이블의 구조를 변경해서 국가/도시 정보의 경우는 정수 값만 저장하고 이름을 가져올 때는 외부 테이블을 매핑 하도록 변경

  • DB에 저장된 정보를 Join을 통해 결합해서 가져온 뒤 비즈니스 계층에서 추가 로직 처리를 통해 해당 사용자의 프로필을 구성하는 객체를 만들 수 있는 기능 구현

  • 프로필 정보에 담을 추천 글을 가져올 수 있는 기능 구현

  • 불필요한 DB 커넥션이나 조인 비용을 줄이기 위해서 거의 변하지 않는 정보들을 캐싱한 뒤 캐싱된 맵을 이용해서 국가/도시/언어 이름을 가져오도록 만들기

[#14] Code 리팩토링 (UserService 기준)

📖 구현이 필요한 항목

🔖 UserService 리팩토링 주요 내용

  • 불필요한 중복이나 코드를 지저분하게 만드는 if 문을 최대한 제거

  • 리턴/본문 내용이 필요 없는 컨트롤러 메소드들의 ResponseEntity<Void>를 리턴타입을 제거하고 @ResponseStatus로 대체

[#5] 유저 정보 업데이트 기능 구현

📖 구현 항목

🔖 유저 정보 변경 기능관련 로직 구현

  • 회원이 요청한 정보에 맞게 현재 정보를 변경하는 기능 구현 (변경 불가능 한 정보 제외 ex. ID, Password, Email 등)

🔖 유저 프로필 사진 추가/변경 기능관련 로직 구현

  • 회원이 업로드 요청한 프로필 사진을 추가/변경하는 기능 구현
  • 업로드 한 파일을 저장소에 저장하는 기능 구현.
  1. 파일이 한 곳에만 저장되는 것을 막기 위해 유저의 ID를 반영한 디렉토리 생성
  2. 파일 이름의 중복으로 기존 데이터가 변형되는 것을 막기 위해 UUID를 활용해 랜덤한 숫자형태로 파일이름 변경
  3. 파일 저장에 실패하면 제대로 된 업로드의 반영이 불가능하므로 예외 발생 - FileNotUploadedException
  • 불필요한 파일이 지속적으로 쌓이는 과정에서 저장소의 용량 낭비를 막기 위해 기존 프로필 사진 파일이 있다면 지우고 새로 요청 받은 파일을 저장하는 기능 구현
  1. 기존의 파일 삭제가 제대로 이루어지지 않은 경우 예외 발생 - FileNotDeletedException

🔖 위의 로직을 테스트하기 위한 테스트 작성

[#2] 회원가입 기능 구현

📖 구현 항목

  • 회원가입 요청
  • 회원가입 요청 시 전달 받은 데이터의 유효성 검증
  • 중복ID 검사 기능
  • BCrypt를 활용한 비밀번호 암호화
  • 이상 없는 데이터 DB에 저장

[#7] 향후 서버의 Scale out을 고려해 세션 저장소로 Redis 추가하기

📖 구현 항목

🔖 세션 저장소로 Redis 추가

  • 현재 개발 중인 서비스는 서비스의 특성과 확장 시 장단점을 고려했을 때 Scale Out이 더 적합함
  • Scale Out은 트래픽이 세션이 저장되어있지 않는 서버로 보내질 시 데이터 불일치가 발생한다는 문제가 있음
  • 이를 해결하기 위해 여러 방법 중에서 세부적인 trade-off을 고려해 세션 저장소를 추가하기로 했으며 Redis가 가장 적합한 후보로 선정됨

🔖 Redis용 Session 활성화

[#30] 친구에 대한 추천글을 남길 수 있는 기능 추가

📘 개요

  • 사용자가 각 친구에게 추천글을 남길 수 있도록 함으로써 다른 사용자가 언어 교환 파트너를 찾는데 있어 도움이 되도록 하기 위함

  • 추천글 등록 시 알람까지 함께 보내는 로직이 필요

📖 구현이 필요한 항목

  • 사용자가 추천글을 남기기 위해서 기준을 충족하는 지 검사하기 위한 친구기간 구하기 메소드 추가하기

  • 위의 메소드를 포함하고 다른 예외 검증 기능들도 가진 추천글 남기기 기능 구현하기

📖 테스트 작성

  • 성공 케이스에 대한 테스트 작성하기

  • 실패 케이스에 대한 테스트 작성하기

[#36] 특정 사용자에 대한 전체 추천글 보기 기능 구현

📘 개요

  • 특정 사용자의 프로필을 조회할 때 DB의 부하를 줄이기 위해서 해당 사용자에게 등록된 추천글은 최신 것부터 일부만 추려서 로드합니다.

  • 그래서 혹시나 프로필을 조회하는 사용자들이 나머지 추천글도 보고자 한다면 프로필 내부에 링크를 두어 새로운 URL로 연결해주어 전체 추천글 목록을 확인할 수 있도록 합니다.

📖 구현 항목

  • 추천 글을 가져오기 전 해당 사용자가 존재하는지 여부를 판별하는 코드 작성

  • cursor 방식 페이징을 활용해 해당 사용자에 대한 추천글을 불러오는 로직 및 쿼리 작성

📖 테스트

  • 위의 로직을 테스트 할 테스트 코드 작성

  • 포스트맨을 활용해 전반적인 동작 테스트

[#6] ExceptionHandler를 이용한 공통 예외처리 구현 및 비즈니스 로직의 위치 변경

📖 구현 항목

🔖 예외 관리에 Enum을 도입 ~~

  • 비슷한 종류의 예외가 발생시 새롭게 Exception 관련 클래스를 추가해서 RuntimeException을 상속 받고 메소드를 오버라이딩 하는 등의 번거로운 작업 대신 상수만 추가해서 특정 예외관련 1개의 클래스만 가지고 통합적인 예외 처리를 하기 위한 것이 목적
  • 먼저, UserFile에 대한 예외관리 Enum 작성

🔖 공통된 예외 관리를 위해 ExceptionHandler 적용

  • 성격이 비슷한 에러를 한번에 묶어 처리하고, 에러 코드 및 로깅을 한번에 하기 위함
  • try / catch 문을 최소화 해서 코드의 가독성과 유지보수성을 높이기 위함

🔖 UserController에 있던 비즈니스 로직을 LoginService로 이동

  • 기존
    : UserController에서 로그인을 할 때 컨트롤러가 UserService에서 유저 객체를 받아와 LoginService로 전달

  • 문제점
    : 유저정보를 받아오는 부분은 비즈니스 로직에 해당한다.

  • 목표
    : 유저정보를 받아오는 로직을 LoginService로 이관해서 UserController -> LoginService -> UserService의 의존관계를 형성하는 것

[#27] 사용자가 받은 알람 목록을 불러올 수 있는 기능 구현

📘 개요

  • 사용자가 지금까지 받은 알람 목록을 한꺼번에 확인할 수 있도록 받은 알람 목록을 불러오는 기능 구현이 필요

  • 페이징을 사용해서 한번에 모두 불러오는 것이 아니라 각 페이지 만큼 요청을 나눠서 처리하는 것이 목표

📖 구현이 필요한 항목

  • 사용자가 받은 알람 목록을 불러올 수 있는 기능 구현하기

[#3] 로그인/로그아웃 기능 구현

📖 구현 항목

세션을 활용한 로그인 기능 구현

  • 로그인 인증 관련 로직 구현
  1. 이미 로그인 한 유저가 재 로그인 시도 시 (예외 발생)
  2. 존재하지 않는 ID로 로그인 시도 시 (예외 발생)
  3. 잘못된 비밀번호로 로그인 시도 시 (예외 발생)
  4. 올바른 유저 정보를 활용해 로그인 시 (정상적인 처리 - 로그인 정보를 세션에 저장)

로그아웃 기능 구현

[#28] 사용자의 개별 알람 읽기 기능 추가

📘 개요

  • 사용자가 받은 알람 목록 중에서 개별 알람에 대한 읽기요청을 처리하는 작업이 필요

📖 구현이 필요한 항목

  • 사용자의 개별 알람을 읽어올 수 있는 기능 구현하기

  • 읽은 알람은 읽음 상태를 'Y'로 변경할 수 있는 기능 구현하기

📖 테스트 작성

  • 성공 케이스에 대한 테스트 작성하기

  • 실패 케이스에 대한 테스트 작성하기

[#35] Redis 캐시 저장소 추가 및 사용자 프로필 캐싱 기능 구현

📖 개요

  • 사용자의 프로필을 조회는 많은 부하가 가해지는 연산이다
  1. 해당 사용자의 프로필 정보를 DB에서 가져오기 (이때, 사용자의 언어정보를 얻기 위해서 users 테이블과 speak 테이블의 JOIN 연산이 활용된다.)
  • 쿼리 튜닝로컬 캐시를 이용해 국가/도시/언어 이름은 애플리케이션 단에서 매칭시키도록 구조를 변경 해 DB에 가해지는 부하를 어느 정도 감소 시켰으나 여전히 JOIN연산는 DB에 부담이다.
  1. 해당 사용자에 대한 추천글도 프로필에 담기 위해서 DB로의 연결이 한 번 더 필요하다.

  2. 이후 애플리케이션 단에서 국가/도시/언어 이름 매칭 작업 및 위의 정보를 활용해 유저 프로필 정보를 담은 객체 생성 작업이 실행된다.

  • 유저 프로필 정보는 자주 변경될 확률이 낮다.

  • 이러한 근거를 바탕으로 캐싱을 적용해주는 것이 성능 향상에 큰 도움이 된다는 결론에 이르게 되었다.

📖 결정이 필요한 항목

🔖 로컬 캐싱 vs 글로벌 캐싱

  • 각각에 대해 조사하기

  • trade-off를 고려하여 현재 서비스에 맞는 결정 내리기

선택: Redis

📖 구현이 필요한 항목

🔖 Redis Cache Configuration

  • Redis를 활용한 캐시 설정파일 추가하기

  • 사용자 프로필 조회 시 사용자의 아이디를 key 값으로 한 캐시 값을 Redis 저장소에 저장하고, 일치하는 캐시가 있으면 이를 불러오도록 설정

  • 사용자 프로필에 반영되는 정보가 수정될 경우 이를 반영하기 위해 캐시가 Evict 되어 최신 정보를 반영할 수 있도록 설정

[#4] 사용자 비밀번호 변경기능 구현

📖 구현 항목

🔖 비밀번호 변경 기능관련 로직 구현

  • 회원의 현재 비밀번호를 먼저 확인받고 다음의 로직으로 넘어갑니다.
  • 입력한 현재 비밀번호가 일치하지 않으면 예외를 발생시킵니다.
  • 새로 입력한 비밀번호현재 비밀번호일치하면 예외를 발생시킵니다.
  • 새로 입력한 비밀번호와 입력값을 다시 확인하기 위한 값불일치 하면 예외를 발생시킵니다.
  • 위의 검증과정을 모두 통과하면 DAO를 통해 DB에서 현재 회원의 비밀번호를 업데이트 합니다.

🔖 위의 로직을 테스트하기 위한 테스트 작성

[#40] Jasypt를 활용한 암호화 적용하기

📖 개요

  • 민감한 설정 값들이 외부로 노출될 가능성이 있어 적절한 암호화가 필요

📖 구현내용

  • Jasypt 라이브러리 및 bean configuration 추가

  • 민감한 설정값들 암호화 하기

  • 테스트 구동

[#17] 친구추가 요청 거절 기능 구현

📖 구현이 필요한 항목

🔖 친구추가 요청 거절 기능 구현하기

  • 받은 친구 추가 요청 거절에 대한 로직을 처리하는 메소드 추가

🔖 위의 로직을 테스트할 테스트 작성

  • 성공 케이스 테스트 작성

  • 실패 케이스 테스트 작성

[#16] 친구추가 요청 수락 기능 구현

📖 구현이 필요한 항목

🔖 친구추가 요청 수락 기능 구현하기

  • 받은 친구 추가 요청을 수락할 수 있는 메소드 추가

🔖 위의 로직을 테스트할 테스트 작성

  • 성공 케이스 테스트 작성

  • 실패 케이스 테스트 작성

[#43] 메시지 실시간 처리성능 향상을 위한 카프카 도입

📖 개요

  • 메신저 기능을 추가했으나, 실시간 처리가 중요한 로직 내부에 개별 메시지마다 DB로의 접근과 블로킹 IO가 발생한다는 문제점이 있었음

  • 위의 문제점을 해결하기 위해서 다양한 방법 중 성능과 안정성이 검증된 메시지 큐인 카프카를 사용하기로 결정하였고, 이를 도입하여 DB 연결 및 블로킹 IO의 발생을 최소화 해서 대용량 트래픽에도 안정적으로 실시간 처리를 해낼 수 있도록 하는 것을 목표로 삼음

📖 내용

  • 카프카에 대해 학습하기 (카프카, 데이터 플랫폼의 최강자)

  • Google Cloud Platform에 Zookeeper 지노드 및 카프카 브로커를 위한 VM서버를 추가하고 설치하기

  • 여러 개의 서버에 지노드/브로커 클러스터링 구성하기

  • 카프카 토픽 또한 클러스터링 구성에 대한 설정을 추가하여 안정성 높이기

  • 프로젝트에 카프카 프로듀서/컨슈머 설정 추가하기

  • 프로듀서/컨슈머를 통해 들어온 메시지를 모아서 카프카 서버로 보내고, 이를 다시 컨슈머를 활용해 배치형태로 불러와 DB에 한 번에 저장하는 구조 구현하기

[#44] 사용자의 채팅함 목록 불러오기 기능 구현

📖 개요

  • 사용자가 다른 사용자들과 주고 받은 메시지를 확인하기 위해서 이를 불러올 기능이 필요함

  • 각 사용자와의 채팅내용을 보여주기 전에 각 채팅내용을 담고 있는 채팅함 목록을 먼저 보여줄 필요가 있음

📖 요구사항

  1. 메신저 앱과 같이 채팅함 이름으로는 상대방의 아이디를 사용한다.

  2. 해당 채팅함에는 자신 혹은 상대방 중에 누가 보냈는지에 상관 없이 가장 최신의 메시지를 1개 뽑아서 보여준다.

  3. 표시한 메시지는 보낸 시간을 표시한다.

  4. 채팅함 목록은 가장 최신 메시지를 받은 채팅함 부터 표시한다.

📖 내용

  • Controller, Service, Mapper의 각 계층에 필요한 메소드 작성하기

  • 요구사항을 만족하는 쿼리를 실행계획을 고려하여 작성하기

[#45] 메시지 함에 저장되어 있는 채팅 메시지를 읽어오는 기능 구현

📖 개요

  • 사용자가 다른 사용자들과 주고 받은 메시지를 확인하기 위해서 언제든지 이를 불러올 수 있어야 함

  • 각각의 채팅함 내부에 저장되어 있는 메시지를 불러오는 기능 필요

📖 요구사항

  1. 채팅함 id를 전달 받으면, 해당 채팅함에 있는 메시지를 불러온다.

  2. 모든 메시지를 한 번에 불러오는 것은 데이터가 많아질수록 엄청난 부하를 가하게 되므로, 커서 방식으로 적절히 나눈다.

  3. 기존에 읽지 않은 메시지가 있을 경우 읽지 않음을 읽음으로 표시 한다.

📖 내용

  • Controller, Service, Mapper의 각 계층에 필요한 메소드 작성하기

  • 요구사항을 만족하는 쿼리를 실행계획을 고려하여 작성하기

[#10] 사용자의 언어 추가 기능 구현하기

📖 구현이 필요한 항목

🔖 DB 관계도 작성하기

  • 사용자와 언어에 대한 DB 관계도 작성하기

🔖 언어추가 기능 로직 구현하기

  • 사용자의 모국어를 추가할 수 있는 기능 구현하기

  • 사용자가 학습할 수 있는를 추가할 수 있는 기능 구현하기

  • 사용자가 학습 중인 언어의 레벨을 추가할 수 있는 기능 구현하기

🔖 위의 로직을 테스트하기 위한 테스트 작성하기

  • (성공 케이스)

  • (실패 케이스)

[#37] 전체 사용자 프로필 불러오기 기능 구현

📘 개요

  • Hello-World 서비스를 사용하는 사용자들이 등록된 다른 사용자들의 프로필 사진 및 정보를 살펴보면서, 더 알아보고 싶은 사용자가 있는 경우 클릭하여 개별 사용자들의 프로필을 조회할 수 있도록 해주는 페이지를 구현합니다.

  • 특정한 커서가 지정되어 있지 않은 첫 페이지(메인 페이지)의 경우에는 캐싱 기능을 활용해 캐시 저장소에 미리 저장해두어 데이터를 로드하도록 설정해줌으로써 서버로 가해지는 부하를 줄일 수 있도록 하는 것이 목표입니다.

📖 구현 항목

모든 사용자의 프로필을 불러올 수 있도록 커서 방식의 페이징을 활용한 프로필 조회 기능 구현하기

(이때, 해당 기능의 경우는 개인 프로필 조회와 다르게 간단한 정보만을 가지고 프로필을 리스트 형식으로 나열하는 것이 목표이므로 필요한 정보만 가져온다.)

  • 사용자들의 정보 중에서 필요한 정보만을 추려서 가져올 수 있도록 하는 쿼리 작성

(ex. 아이디, 프로필 사진, 추천글 갯수 등)

  • 메인 페이지의 경우는 조건부의 형식으로 캐싱을 설정해주기

📖 테스트

  • 포스트맨을 활용해 전반적인 동작 테스트

[#46] UserController과 관련 domain 코틀린 변경

📖 개요

  • Java 언어의 한계점을 인지하고 이를 손쉽게 보완하는데 초점을 맞추고 있는 Kotlin으로 전환

  • Java와 Kotlin은 JVM을 기반으로 하여 상호 간의 호환이 잘 되므로 부분씩 전환하기가 용이

📖 내용

  • UserController와 관련 도메인 클래스들 코틀린으로 변환

  • 깨진 테스트 코드들 고쳐주기

[#32] 친구에게 남긴 추천글을 수정할 수 있는 기능 구현

📘 개요

  • Hello-World 서비스에서는 추천글 사용의 오남용을 막기위해 단 1회만 추천글 작성을 허용하며, 작성한 추천글은 삭제하거나 수정할 수 없습니다.

  • 다만 오타나 내용 추가 등의의 이유로 수정이 필요할 경우 48시간 동안 수정을 허용합니다.

📖 항목

  • 48시간 이내에 작성된 추천글을 수정할 수 있도록 하는 기능 구현하기

📖 테스트

  • 위의 로직을 테스트할 수 있는 단위 테스트 작성하기

[#22] 사용자 및 친구 차단 기능 구현

📖 구현이 필요한 항목

🔖 사용자 및 친구 차단 기능 구현하기

  • 부적절한 사용자 혹은 친구를 차단할 수 있는 기능 구현하기

🔖 위의 로직을 테스트할 테스트 작성

  • 성공 케이스 테스트 작성

  • 실패 케이스 테스트 작성

[#29] 사용자 알람 삭제 기능 추가

📘 개요

  • 사용자가 받은 알람을 선택적으로 삭제할 수 있도록 받은 알람 삭제 기능을 추가하는 작업이 필요

  • 친구 요청 등 철회 시 보냈던 요청 삭제와 함께 발송했던 알람 내역까지 삭제하는 작업이 필요

📖 구현이 필요한 항목

  • 사용자가 선택적으로 알람을 삭제할 수 있도록 하는 기능 구현하기

  • 요청 철회 시 보냈던 알람도 삭제할 수 있도록 해주는 기능 구현하기

📖 테스트 작성

  • 성공 케이스에 대한 테스트 작성하기

  • 실패 케이스에 대한 테스트 작성하기

[#24] 사용자 차단 해제 기능 추가

📖 구현이 필요한 항목

🔖 사용자 차단 해제 기능 구현하기

  • 이미 차단된 사용자를 차단 해제할 수 있는 기능 구현하기

🔖 위의 로직을 테스트할 테스트 작성

  • 성공 케이스 테스트 작성

  • 실패 케이스 테스트 작성

[#15] 친구추가 요청 철회 기능 구현

📖 구현이 필요한 항목

🔖 친구추가 요청 철회 기능 구현하기

  • 보낸 친구 추가 요청을 철회할 수 있는 메소드 추가

🔖 위의 로직을 테스트할 테스트 작성

  • 성공 케이스 테스트 작성

  • 실패 케이스 테스트 작성

[#18] 친구삭제 기능 구현

📖 구현이 필요한 항목

🔖 친구삭제 기능 구현하기

  • 친구 삭제 요청 비즈니스 로직을 처리하는 메소드 추가

🔖 위의 로직을 테스트할 테스트 작성

  • 성공 케이스 테스트 작성

  • 실패 케이스 테스트 작성

[#33] 페이징 방식 변경하기

📘 개요

기존의 페이징 방식은 offset 방식이었습니다.

  • offset 방식은 구현하기 더 단순하지만 다음의 문제점이 존재합니다.
  1. 페이지 요청사이에 데이터 변화가 있는 경우 중복 데이터가 발생하거나 데이터의 생략현상이 발생할 수 있습니다.

  2. offset 방식을 사용하면 기본적으로 위치를 찾기 위해 앞에서 읽었던 행을 다시 읽어야 하므로 저장된 데이터가 많아질수록 성능적인 이슈가 발생합니다.

특히 두 번째 문제로 페이징 방식을 cursor 방식으로 변경하기로 결정하였습니다.

  • Hello-World 서비스는 대용량 트래픽이 들어오는 것을 가정하고 프로젝트를 진행하므로, 그에 맞게 데이터의 수도 당연히 많을 것입니다.

  • cursor 방식을 사용하면 읽은 데이터의 바로 다음부터 limit 까지만 데이터를 불러오면 되고, 이때 기준을 인덱스를 PK와 같은 인덱스를 사용한 칼럼으로 지정한다면 인덱스를 100% 활용할 수 있어 성능이 더 뛰어납니다.

  • 페이스북, 인스타그램 등의 다양한 SNS 서비스들 또한 이러한 이유로 cursor 방식을 활용해 페이징을 구현했습니다.

📖 항목

  • 기존 offset 방식을 cursor 방식의 페이징으로 변경하기

📖 테스트

  • 포스트맨을 활용해 테스트

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.