문제 인식회원가입 완료 후 JWT 토큰을 응답으로 제공하는 기존 로직은 회원가입 직후 자동 로그인이 되어야 할 경우에는 편리하지만, 더 자연스러운 흐름은 로그인 요청 시 토큰을 발행하는 방식이라고 생각합니다. 문제 정의회원가입 성공 여부보다는 인증 정보(JWT)를 제공하게 되어, 가입 절차가 끝난 후 직접 로그인을 요청하는 흐름과는 어색해졌습니다. 회원가입의 순수한 결과를 응답하고, 토큰 발급은 로그인 시점에 맡기는 구조로 변경하려고 합니다. 해결 방안의사결정 과정A 선택지: 회원가입 응답에 JWT를 포함하여 반환장점: 회원가입 직후 바로 인증할 수 있으므로 편리성 제공단점: 회원가입과 로그인의 책임이 분리되지 않으며, 보안 측면에서 회원가입 후 자동 로그인 로직이 불필요한 경우 JWT 발행이 오히려 어..
문제 상황: 3N+1 문제와 성능 저하개발 중에 다음과 같은 문제가 발생했습니다. 하나의 게시물 목록을 조회하는 코드에서, 3N+1 문제가 발생하면서 다수의 추가적인 쿼리가 나가고 있었습니다.@Transactional(readOnly = true)public PostsReadPageRespDto readPosts(final int page, final int limit) { final Page posts = postRepository.findAll( PageRequest.of(page, limit, Sort.by(Sort.Direction.DESC, "lastModifiedAt"))); final Page postsResponse = posts.map( post -> ..
날씨 API 구현처음, 날씨 API를 통해 오늘의 날씨 정보를 가져오는 기능을 구현하기 위해 코드를 작성했습니다. 메서드는 두 가지 주요 기능을 가지고 있었습니다. public WeatherResponse getWeather(final String date) { final WeatherResponse[] responses = webClient.get() .uri("/f-api/weather.json") .retrieve() .bodyToMono(WeatherResponse[].class) .block(); // 날씨 정보 가져오기 return ..
문제 설명JPA를 사용하여 스케줄을 업데이트하는 메서드에서 다음과 같은 코드가 있었습니다.public ScheduleUpdateResponse update(final ScheduleUpdateRequest request, final Long scheduleId) { final Schedule schedule = scheduleRepository.findById(scheduleId) .orElseThrow(() -> new ScheduleApplicationException(SCHEDULE_NOT_FOUND)); schedule.update(request.title(), request.title()); return ScheduleUpdateR..
서비스 단의 @Transactional 관리와 코드 리팩토링최근 프로젝트에서 일정 관리 서비스를 구현하며 @Transactional을 사용한 코드 개선을 진행했습니다. 처음에는 전체 클래스에 @Transactional을 적용했지만, DB 로직이 단순한 메서드도 많아 필요하지 않은 경우가 많다는 것을 깨달았습니다. 특히 findById 메서드는 단순히 ID로 조회하는 작업이었기 때문에 트랜잭션이 필요하지 않았습니다. 이러한 점을 인지하고, @Transactional을 적절히 사용하는 습관을 기르기로 했습니다. 수정된 코드리팩토링 한 코드는 다음과 같습니다.@Service@RequiredArgsConstructorpublic class ScheduleService { // ...... @Trans..
Field 'name' doesn't have a default value 오류과제를 진행하던 중 name 필드에 값이 없다는 오류 메시지를 마주쳤습니다. Writer 테이블이 생성되기 전 name 필드를 통해 사용자 정보를 구별하고자 했으나, 동명이인 문제로 Writer 테이블을 만들게 되었습니다. 그러나 기존에 JPA를 사용하면서 Entity에서 삭제만 시켜두면 적용되었던 것에 익숙해져서 그런지 Schedule.sql에서 name을 삭제하지 않아 NOT NULL 제약으로 인해 오류가 발생했습니다. 이를 통해 데이터베이스 구조 변경 시 관련 필드와 로직을 함께 검토해야 한다는 교훈을 얻었습니다. scheduleRepository에서 Writer 객체 사용다음으로, scheduleRepository에서 ..
import java.util.*;class Solution { public String solution(String number, int k) { StringBuilder sb = new StringBuilder(); int idx = 0; int next = 0; for (int i = 0; i 아이디어주어진 숫자에서 k개의 숫자를 제거하고 남길 수 있는 가장 큰 숫자를 구하려면, 가장 큰 숫자를 앞쪽에 배치하는 방식으로 해결할 수 있습니다. 이를 위해, 숫자를 왼쪽에서부터 탐색하며 남길 자릿수에 맞춰 매번 남은 범위 내에서 가장 큰 숫자를 선택하는 전략을 사용합니다. 처음엔 조합으로 모든 경우의 수를 내고 정렬로 뽑으려했지만 많은 시간이 걸려..
비슷한 추상화 수준으로 작성된 흐름 이란?흐름에 대한 모든 설명이 비슷한 수준을 가져야 한다는 말이다.흐름을 설명하는 중간에 갑자기 너무 구체적인 내용이 있으면, 전체흐름을 이해하기 어렵다. 브라우저에 “www.naver.com”을 입력했을 때의 흐름을 설명해 보자.www.naver.com이라는 도메인이름을 DNS서버에 보내 IP주소를 조회한다.IP 주소를 이용해 HTTP 요청을 보낸다.네이버 서버는 HTTP 요청을 받아서 처리하고, HTML 문서를 포함한 HTTP 응답을 돌려준다.HTTP 응답을 받은 브라우저는 HTML 문서를 파싱해 화면에 보여준다.HTML 문서를 보여주는데 추가로 필요하 CSS, JS, Image 정보가 있다면 다운로드해 모든 정보를 랜더링 한다.2번 설명에서 갑자기 “HTTP 요청..
나중에 쓸 변수를 미리 선언하지 말자.CASE - 불변하지 않은 전역변수 & 인스턴스 변수모든 메서드를 읽을 때 기억해야 할 Context가 된다.해당 변수가 충분히 설명적이지 않을 경우 어떻게 초기화되는지까지 같이 봐야 한다.특정 메서드를 작성하다가 그 변수를 수정할 경우 모든 메서드에 그 변경이 전파될 수 있다.가변변수라면, 해당 변수를 변경하는 모든 메서드를 같이 고려해야 한다.( 놓친 부분이 있다면 내 예상과 다르게 코드가 동작할 확률이 높다.) Action Item가능한 사용하는 곳과 가까운 변수를 생성한다.가능한 변수(Context)의 Scope를 작게 제한하자. 메서드메서드 크기가 커지는 것에서 Bad Smell을 맡아보자메서드 크기가 커진다는 것은 하는 일이 많아지는 거다. (아닌 경우도 ..
소프트 딜리트(Soft Delete)란?소프트 딜리트는 데이터베이스에서 레코드를 물리적으로 삭제하지 않고, 삭제된 것처럼 처리하는 방법입니다. 데이터를 실제로는 삭제하지 않고, 상태를 비활성화하여 다른 사용자들이 보지 못하게 하지만, 데이터는 여전히 데이터베이스에 남아 있습니다. 보통 삭제 플래그나 상태 값을 변경하는 방식으로 구현합니다. 소프트 딜리트 구현 방법제가 구현한 소프트 딜리트는 데이터베이스 테이블에 Status 필드를 추가하여 처리했습니다. 상태 값으로 데이터의 활성, 비활성, 비공개 여부를 관리할 수 있습니다. 소프트 딜리트 코드소프트 딜리트는 상태 값 INACTIVE를 사용해 게시글이 삭제된 것처럼 보이도록 설정할 수 있습니다.public enum ArticleStatus { ACT..