게시글 관련 기능에서 날짜를 "yyyy/MM/dd HH:mm:ss" 형식으로 반환하기 위해 TimeFormatter 클래스를 작성했었다.
하지만 코드 점검 과정에서 몇 가지 개선할 점을 발견하여 리팩토링을 진행했다.
기존 코드
TimeFormatter
package com.example.withpeace.util;
import org.springframework.stereotype.Component;
import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
@Component
public class TimeFormatter {
public static String timeFormat(LocalDateTime time) {
DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy/MM/dd HH:mm:ss");
return time.format(formatter);
}
}
PostService
PostDetailResponseDto postDetailResponseDto =
PostDetailResponseDto.builder()
.postId(postId)
.userId(post.getWriter().getId())
.nickname(post.getWriter().getNickname())
.profileImageUrl(post.getWriter().getProfileImage())
.title(post.getTitle())
.content(post.getContent())
.type(post.getType())
.createDate(TimeFormatter.timeFormat(post.getCreateDate())) // 날짜 포맷 적용
.postImageUrls(postImageUrls)
.comments(comments)
.build();
문제점 분석
1. 불필요한 `@Component`가 사용되었다.
`@Component`는 스프링 빈으로 등록하기 위해 사용하는데, 이 클래스는 단순히 유틸리티 메서드만 제공하고 있기 때문에 빈으로 등록할 필요가 없다.
2. 매번 `DateTimeFormatter` 인스턴스 생성
`DateTimeFormatter.ofPattern("yyyy/MM/dd HH:mm:ss")`가 호출될 때마다 새로운 인스턴스가 생성된다.
→ 객체 생성 비용이 증가한다. (성능 저하)
→ `DateTimeFormatter`는 불변(immutable)하고 스레드-세이프(Thread-safe)하기 때문에 재사용이 가능하다.
리팩토링 방향
- `@Component` 제거 → 불필요한 스프링 빈 등록 제거로 메모리 효율성 확보.
- `DateTimeFormatter` 상수화 → `static final`로 선언하여 객체 생성 비용 절감.
- `@UtilityClass` 적용 → Lombok의 `@UtilityClass`를 활용해 유틸리티 클래스임을 명시.
`@UtilityClass` 기능
- 클래스에 `final` 키워드를 자동으로 추가한다. (상속 방지)
- 모든 메서드와 필드를 `static`으로 자동 변환한다.
- `private` 생성자를 자동으로 생성한다. (인스턴스화 방지)
리팩토링 적용 코드
TimeFormatter
package com.example.withpeace.util;
import lombok.experimental.UtilityClass;
import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
@UtilityClass
public class TimeFormatter {
private static final DateTimeFormatter FORMATTER = DateTimeFormatter.ofPattern("yyyy/MM/dd HH:mm:ss");
public String format(LocalDateTime time) {
return time.format(FORMATTER);
}
}
PostService
PostDetailResponseDto postDetailResponseDto =
PostDetailResponseDto.builder()
.postId(postId)
.userId(post.getWriter().getId())
.nickname(post.getWriter().getNickname())
.profileImageUrl(post.getWriter().getProfileImage())
.title(post.getTitle())
.content(post.getContent())
.type(post.getType())
.createDate(TimeFormatter.format(post.getCreateDate())) // 변경된 부분
.postImageUrls(postImageUrls)
.comments(comments)
.build();
성능 측정 (Prometheus 기준)
게시글 리스트 조회 API(/api/v1/posts)의 평균 응답 시간을 비교했다.
쿼리
rate(http_server_requests_seconds_sum{uri="/api/v1/posts", outcome="SUCCESS"}[5m])
/
rate(http_server_requests_seconds_count{uri="/api/v1/posts", outcome="SUCCESS"}[5m])
구분 | 평균 응답 시간 |
기존 | 0.0221초 (22.1ms) |
리팩토링 후 |
효과
- 불필요한 빈 등록 제거 → 메모리 최적화
- Formatter 재사용 → 객체 생성 비용 감소
- 코드 간결성 향상
반응형
'Projects > 청하-청년을 위한 커뮤니티 서비스' 카테고리의 다른 글
[청하] 게시글 리스트 조회 성능 최적화: N+1 문제 해결 & 인덱스 최적화 (0) | 2025.02.04 |
---|---|
[청하] 39. 홈화면 리뉴얼: 맞춤 정책, 핫한 정책, 커뮤니티 미리보기 설계 (0) | 2024.10.27 |
[청하] 38. Docker 환경에서 Spring Boot 모니터링 시스템 구축 (with. Prometheus, Grafana) (2) | 2024.10.27 |
[청하] 37. 로컬 환경에서 Spring Boot 모니터링 시스템 구축 (with. Prometheus, Grafana) (0) | 2024.10.27 |
[청하] 36. 게시글 조회수 기능 구현 (0) | 2024.10.25 |
댓글