Stay Hungry Stay Foolish
728x90

전체 글 498

[리팩토링] 실행 계획과 데이터 분포 분석을 통한 조회 성능 개선

REFACTORING실행 계획과 데이터 분포 분석을 통한 조회 성능 개선목차1. 작업 배경2. 단일 인덱스 적용과 1차 검증3. 실제 조회 패턴 분석4. 복합 인덱스 설계5. 데이터 분포를 고려한 검증6. EXPLAIN ANALYZE 결과7. 최종 인덱스 구성과 배운 점1. 작업 배경리팩토링 과정에서 주요 조회 쿼리의 실행 계획을 점검했다. 당시 posts에는 일부 인덱스가 존재했지만, 조회 조건으로 사용되는 reading_status와 completed_date에는 적절한 인덱스가 적용되지 않은 상태였다.처음에는 자주 조회되는 컬럼에 단일 인덱스를 추가하고 적용 전후의 EXPLAIN 결과를 비교했다. 이후 Repository 코드를 다시 분석하면서 실제 통계 쿼리는 컬럼을 각각 조회하는 것이 아니라 u..

[트러블슈팅] H2 예약어 컬럼명으로 인한 테이블 생성 실패 및 InitData 오류

TROUBLESHOOTINGH2 예약어 컬럼명으로 인한 테이블 생성 실패 및 InitData 오류목차1. 발생 배경2. 문제3. 원인 파악 과정4. 해결5. 참고6. 배운 점1. 발생 배경리팩토링 단계에서 로컬 환경 통합 테스트를 위해 InitData를 작성했다. InitData는 애플리케이션 실행 시 테스트용 데이터를 DB에 자동으로 insert해주는 클래스다. H2 인메모리 DB를 사용하는 로컬 환경에서는 애플리케이션을 실행할 때마다 데이터가 초기화된다. 매번 수동으로 테스트 데이터를 넣는 번거로움을 줄이기 위해 InitData를 작성했는데, 이후 애플리케이션 실행 시 monthly_goals 테이블을 찾지 못한다는 오류가 발생했다.처음에는 InitData 실행 시점이 테이블 생성보다 빨라서 생긴 문..

[프로젝트] POSTMAN에서 JWT 토큰 자동 저장 및 요청에 자동 적용하는 방법

PROJECTPostman에서 JWT 토큰 자동 저장 및 적용 설정목차1. 개요2. 배경 지식3. 설정 방법4. Refresh Token 처리5. 참고1. 개요로그인 API 호출 시 응답으로 내려오는 accessToken을 Postman 환경변수에 자동으로 저장하고, 이후 인증이 필요한 모든 API 요청에 자동으로 Bearer Token을 붙이는 설정 방법이다.이 설정을 해두면 매번 로그인 응답에서 토큰을 복사한 뒤, 다른 요청의 Authorization 헤더에 직접 붙여넣는 과정을 반복하지 않아도 된다.2. 배경 지식JWT & AccessToken이란?JWT(JSON Web Token)는 서버가 로그인한 사용자에게 발급하는 인증 토큰이다. 이 중 AccessToken은 실제 API 요청 시 로그인된 사..

[트러블슈팅] 로컬 환경 이메일 발송 스킵 조건 오류 해결

TROUBLESHOOTING로컬 환경에서 이메일 발송 스킵 미적용으로 인한 500 오류목차1. 발생 배경2. 문제3. 원인 파악 과정4. 해결5. 참고6. 배운 점1. 발생 배경이메일 인증 기능을 구현한 뒤 Postman으로 /auth/email/send API를 처음 테스트하는 과정에서 500 오류가 발생했다. 로컬 환경에서는 실제 Gmail SMTP로 이메일을 발송하지 않고, 인증 코드를 콘솔 로그로 확인하도록 처리하려고 했다. 하지만 의도와 달리 로컬 테스트 중 실제 Gmail SMTP 인증이 시도되면서 오류가 발생했다.이번 문제의 핵심은 이메일 발송 로직 자체보다, 현재 실행 중인 Spring Profile과 이메일 발송 스킵 조건이 맞지 않았다는 점이다.2. 문제이메일 인증 코드 발송 API를 ..

[트러블슈팅] JavaMailSender 빈 등록 오류 (로컬 환경)

TROUBLESHOOTINGJavaMailSender 빈 등록 오류 해결 과정목차1. 발생 배경2. 문제3. 원인4. 해결5. 참고6. 배운 점1. 발생 배경이메일 인증 기능을 구현한 뒤 애플리케이션을 실행하는 과정에서 JavaMailSender 관련 빈 등록 오류가 발생했다.이메일 인증 기능에서는 인증 코드를 사용자 이메일로 발송해야 하므로 Spring의 JavaMailSender를 사용하고 있었다. 하지만 로컬 환경에서 메일 관련 설정이 누락되어 애플리케이션 컨텍스트가 정상적으로 로드되지 않았다.이번 문제는 코드 로직 자체의 문제라기보다, 로컬 환경 설정 파일에 메일 관련 설정이 빠져 있어 Spring Boot가 필요한 빈을 생성하지 못한 것이 원인이었다.2. 문제애플리케이션 실행 시 AuthServ..

[설계의사결정] 리마인더 알림 구현 방식 선택 과정

PROJECT독서 리마인더 알림 구현 방식 선택 과정목차1. 배경2. 알림 구현 방식 비교3. WebSocket을 선택하지 않은 이유4. 결정 — @Scheduled + SSE1. 배경독서 리마인더 알림 기능을 처음 구현해보는 상황에서 어떤 방식으로 구현할지 고민이 있었다. 알림 구현 방법이 여러 가지 있다는 것은 알고 있었지만, SSE 외에는 익숙하지 않은 방식들이었다. 리마인더 알림은 사용자가 설정한 시간에 맞춰 서버가 알림을 보내주는 기능이다. 따라서 단순히 데이터를 조회하는 API와 달리, 서버가 특정 시점에 사용자를 확인하고 알림을 전달하는 구조가 필요했다.핵심 기준은 구현 난이도, 현재 서비스 규모, 그리고 알림 방향이었다. Booktine의 리마인더는 클라이언트가 서버로 실시간 메시지를 보내..

[설계의사결정] 페이지네이션 방식 선택 과정

PROJECT페이지네이션 방식 선택 과정목차 1. 배경 2. 방식 비교 - 오프셋 기반 페이지네이션 - 커서 기반 페이지네이션 3. 결정 4. Page vs Slice 선택 과정 1. 배경페이지네이션이란?페이지네이션(Page Pagination)은 많은 데이터를 한 번에 조회하지 않고, 일정 개수씩 나누어 조회하는 방식이다. 데이터 양이 많아질수록 한 번에 모든 데이터를 가져오는 것은 성능 저하로 이어질 수 있기 때문에, 사용자에게는 필요한 만큼만 데이터를 보여주고 서버 부하를 줄이기 위해 사용된다. 게시물, 메모, 추천 도서 목록이 전체 조회 방식으로 구현되어 있었다. 초기 데이터가 적을 때는 문제가 없지만, 데이터가 계속 쌓이면 한 번에 많은 데이터를 조회하게 되어 응답 속도와 서버 부하 측..

[프로젝트] 공통 응답 포맷 설계

PROJECT공통 응답 포맷 설계목차1. 배경2. 공통 응답 포맷을 사용하는 이유3. 설계 결정4. 정리01. 배경프로젝트 초기 세팅 단계에서 공통 응답 포맷을 설계했다. 수업에서 공통 응답 포맷을 사용하는 방식을 접했고, 직접 적용해보니 일관성 있는 API 응답 구조가 개발 전반에 도움이 된다고 느껴서 이 프로젝트에도 동일하게 적용했다.02. 공통 응답 포맷을 사용하는 이유API 응답 형식이 엔드포인트마다 다르면 아래와 같은 문제가 생긴다.// 어떤 API는 이렇게 반환하고{ "id": 1, "title": "클린코드" }// 어떤 API는 이렇게 반환하고{ "result": "success", "post": { "id": 1 } }// 에러는 또 이렇게 반환한다{ "error": "Not Found"..

[설계의사결정] 이미지 업로드 정책 결정 과정

PROJECT이미지 업로드 정책 결정 과정목차1. 배경2. 이미지 저장 방식 비교3. 결정 내용4. 정리01. 배경독서 습관 관리 프로젝트를 진행하면서 이미지를 저장하는 방식에 고민이 많았다. 이미지를 저장하는 방법은 크게 세 가지가 있었다. 어떤 방식이 더 좋은 선택인지 판단하기가 쉽지 않았고, 특히 AWS S3를 추천받았지만 실제로 사용하려면 AWS 계정에서 키를 별도로 발급받아야 하는 번거로움이 있어서 어떻게 처리할지 고민이 많았다.02. 이미지 저장 방식 비교방식 1. 외부 URL 그대로 저장외부 서비스(알라딘 등)가 제공하는 이미지 URL을 DB에 그대로 저장하는 방식이다..coverImageUrl(picked.cover()) // 알라딘 CDN URL 그대로 저장장점단점• 구현이 단순하고 빠름..

[Database] 캐싱(Caching)

TECHNICAL NOTE캐싱(Caching) 정리📋 목차1. 캐싱이란 무엇인가?2. 핵심 용어 정리3. 캐싱 전략과 Spring Boot 적용4. 로컬 캐시 vs 분산 캐시 / 주의사항5. 핵심 요약 (Conclusion)01. 캐싱이란 무엇인가?"자주 쓰는 데이터를 빠른 저장소에 미리 올려두는 것"매일 아침 같은 뉴스를 DB에서 조회한다고 가정해보면, 요청마다 DB까지 왕복하면 응답 시간이 늘어나고 DB에 부하가 쌓인다. 첫 조회 결과를 어딘가 가까운 곳에 저장해두고, 다음 요청부터는 거기서 꺼내 쓰는 것이 바로 캐싱이다.반복적인 DB 조회를 줄여 응답 속도를 높인다.DB 서버에 걸리는 부하를 감소시킨다.REST API를 개발하다 보면 아래와 같은 흐름이 반복된다.클라이언트 → Controller ..

[Algorithm] 정렬 알고리즘 심화 분석: O(n²)부터 Timsort까지

ALGORITHM NOTE정렬 알고리즘 심화 분석: O(n²)부터 Timsort까지목차1. O(n²) 정렬 3종 비교 (버블/선택/삽입)2. 퀵 정렬(Quick Sort): 성능 원리와 최악의 조건3. 병합 정렬(Merge Sort)과 안정 정렬(Stable Sort)4. Java Arrays.sort()와 Timsort의 비밀5. 추가 개념: Swap Flag 및 용어 정리01. 버블 / 선택 / 삽입 - O(n²)의 성능 차이셋 다 시간 복잡도는 O(n^2)이지만, 실제 동작 방식에 따라 성능 차이가 발생합니다.선택 정렬 (Selection Sort): 매 라운드 최솟값을 찾아 맨 앞과 교환합니다. 비교 횟수는 항상 n(n-1)/2로 고정이며, 이미 정렬된 상태라도 성능이 개선되지 않아 실용성이 낮습..

[트러블슈팅] Spring Boot에서 동적 쿼리 개선하기: @Query에서 QueryDSL로

TROUBLE SHOOTINGSpring Boot에서 동적 쿼리 개선하기 — @Query에서 QueryDSL로목차1. 들어가며2. 처음 구현 — @Query3. QueryDSL 도입4. 빈 등록 및 Repository 구조5. @Query vs QueryDSL 비교6. 트러블슈팅: Q클래스 생성 오류7. 마치며01. 들어가며Booktine 프로젝트에서 게시물 검색 기능을 구현하면서 동적 쿼리 처리 방식을 고민하게 됐다. 요구사항은 사용자가 키워드(제목, 저자)와 독서 상태(읽는 중, 완독, 읽고 싶음)를 조건으로 게시물을 검색할 수 있어야 했다. 문제는 두 조건 모두 선택 사항이라는 것이다. 키워드만 입력할 수도 있고, 상태만 선택할 수도 있고, 아무 조건 없이 전체 조회를 할 수도 있다.이런 동적 쿼리..

[Architecture] Java to Kotlin 마이그레이션 하는 이유

TECHNICAL NOTEJava to Kotlin: 상세 분석 및 전환 가이드목차1. 마이그레이션의 본질: 테스트 코드의 기술적 역할2. 기술적 전환 동기: 안정성, 생산성, 현대화3. 의사결정 기준: 마이그레이션 실행 여부 판단4. 실전 체크리스트: 마이그레이션 시 주의할 점5. 핵심 요약 (Final Conclusion)01. 테스트 코드와 마이그레이션"마이그레이션 = 리팩토링 + 언어 변경"단순 변환기가 처리하지 못하는 비즈니스 로직의 미묘한 차이로 인해 사이드 이펙트 발생 가능성이 매우 높음.기능 검증: 테스트 코드는 언어 변경 후에도 기능이 동일하게 작동함을 입증하는 유일한 지표.안전한 리팩토링: Kotlin의 특성(불변성, 함수형)을 살린 리팩토링 과정에서 기존 로직이 유지되는지 실시간 확인..

☕ Backend/Kotlin 2026.04.28

[Java] 래퍼 클래스(Wrapper Class)

📦 자바 래퍼 클래스(Wrapper Class): 캐싱과 오토박싱 원리 총정리목차1. 자바 래퍼 클래스(Wrapper Class)란?2. 자바 래퍼 클래스 캐싱 (Wrapper Class Caching)3. 오토박싱(Autoboxing) & 언박싱(Unboxing)4. 주의 사항 및 성능 이슈 (== vs .equals)5. 추가 개념: 신택스 슈가 (Syntax Sugar)1. 자바 래퍼 클래스(Wrapper Class)란?자바에는 int, char, double과 같은 기본 타입(Primitive Type)이 있습니다. 하지만 객체 지향 프로그래밍을 하다 보면 이 기본 타입들을 '객체'로 다뤄야 할 때가 있습니다(예: 컬렉션 프레임워크인 ArrayList에 저장할 때). 이때 기본 타입의 데이터를 ..

☕ Backend/Java 2026.04.28

[TIL] 백준 서비스 종료 소식을 접하며

안녕, 나의 알고리즘 성지 '백준(BOJ)'대학 시절, 코딩테스트를 처음 시작하며 가장 먼저 발을 들인 곳은 백준(Baekjoon Online Judge) 사이트였다. 개발자나 IT 직군이라면 모르는 사람이 없을 정도로(모르는 사람도 꽤나 있는 듯하다..), 코테 준비의 1순위이자 상징과도 같은 곳이다. 그런데 갑작스러운 서비스 종료 소식을 접하니 마음이 참 착잡하다.2년 동안의 치열했던 기록들지난 2년은 백준과 함께 지지고 볶았던 시간이었다. 매일 사이트에 접속해 문제를 풀며 느꼈던 감정들이 아직도 선명하다.성취감의 반복: 어려운 문제에 막혀 스트레스를 받다가도, '맞았습니다!!'를 보기 위해 수십 번 제출 버튼을 누르던 간절함이 있었다.성실함의 증명: 깃허브 잔디를 채우기 위해 아무리 풀기 싫은 날에..

🚀 Growth/TIL 2026.04.17
728x90