1. 프로젝트 진행 상황 및 계획
🥇 이메일 전송 기능 중복 조회 방지하기 (완료)
🥈 이메일 전송 기능 1차 리팩토링(refactoring)하기 (진행 중, 2025.02.20 완료 목표)
🥉 실시간 알림 기능 구현 방법 및 각 방법의 장단점 공부하기 (진행 중, 2025.02.23 완료 목표)
4️⃣ API 명세서 수정 및 검토하기 (진행 전, 2025.02.23 완료 목표)
5️⃣ 리드미(README) 틀 완성하기 (진행 전, 2025.02.23 완료 목표)
6️⃣ MVP(최소 기능 제품) 버전 테스트 코드 작성하기 (진행 전, 2025.02.23 완료 목표)
2. 시간 때문에 하루를 날렸다고?
(1) 깃허브 링크
나는 한국에 있는데 데이터베이스에는 자꾸 UTC로 저장되어 골머리를 앓았다. LocalDateTime을 쓸 때는 이런 일이 없었는데 ZonedDateTime을 쓰니 자꾸 UTC로 시간이 기록되어서 엄청 심각한 오류인 줄 알았다. 나중에 공식 문서를 읽고 나서야 문제가 아니라는 점을 알 수 있었다.
(1) OffsetDateTime 파헤치기 ▼
(1) 특징
- UTC/Greenwich까지 발생하는 오프셋(시간 차이) 포함
- 즉, Instant에 UTC 오프셋을 추가로 저장
- 로컬 날짜-시간 확인 가능
- ISO-8601 달력 시스템의 날짜-시간을 표현
- 날짜-시간을 나노초(nanosecond) 단위로 저장
- 불변(immutable)하며, 스레드 안전(thread-safe)을 보장함
- 예시) 2007년 10월 2일 13:45:30.123456789 +02:00
(2) 다른 시간 관련 클래스와 비교
- Instant
:가장 단순한 형태로, UTC 기준으로 '순간'만 저장
- ZonedDateTime
:OffsetDateTime에 시간대(Time Zone) 정보를 추가로 저장
(3) 언제 사용하면 좋을까?
- 날짜-시간을 더 정밀하게 모델링할 때
- 데이터베이스 또는 네트워크 프로토콜에서 사용할 때
(4) 유의 사항
- 값 기반 클래스(Value-Based Class)에 해당함
- 'equals()'로 비교해야 함
- 서로 다른 인스턴스라도 값이 같으면 동일하다고 판단함
@jdk.internal.ValueBased
public final class OffsetDateTime
(2) ZonedDateTime 파헤치기 ▼
(1) 특징
- ISO-8601 달력 시스템에서 시간대(Time Zone) 포함
- 나노초(nanosecond) 정밀도로 날짜 및 시간 정보 저장
- 예시) '2007-12-03T10:15:30+01:00 Europe/Paris'
- LocalDateTime(로컬 시간)과 Instant(UTC 기준 시간) 사이의 변환을 지원
- ZoneId(시간대)를 기반으로 UTC 오프셋(ZoneOffset) 계산
- 서머타임(Daylight Saving Time, DST) 같은 시간 변경 고려
(2) 내부 구성
- LocalDateTime: 로컬 날짜 및 시간 정보
- ZoneId: 시간대
- DST 같은 동적 규칙 포함
- 예시) Europe/Paris
- ZoneOffset
- UTC 기준 고정 시간 차이
- DST 고려 안 함
- 예시) +01:00
(3) 언제 사용하면 좋을까?
- 시간대(Time Zone)를 고려해야 할 때
- 서머타임 같은 복잡한 규칙 포함
- 로컬 시간(LocalDateTime)과 UTC(Instant)를 자유롭게 변환하고 싶을 때
- 데이터베이스, API 통신 시 시간대 정보를 포함해야 할 때
(4) 유의 사항
- 값 기반(Value-Based) 클래스에 해당함
- '==' 대신 항상 'equals()' 메서드를 사용해야 함
- 불변(immutable)하며, 스레드 안전(thread-safe) 보장
@jdk.internal.ValueBased
public final class ZonedDateTime
처음에는 가뜩이나 해야 할 일도 산더미인데 '시간 때문에 시간이 묶였다'고 생각했다가 이 또한 좋은 경험으로 받아들였다. '이렇게 또 하나 새로 배웠으니 좋지, 뭐'라는 마음 가짐으로 남은 프로젝트 일정을 소화해야 오랫동안 건강하게 개발할 수 있을 듯했다.
3. 최종은 피날레(finale)일 뿐, 끝이 아니다.
알림 기능 하나만 맡았을 뿐인데, 이런저런 생각할 거리며 시도해 볼까 말까 고민되는 일은 뻥튀기됐다.
'한 회사가 채용 공고를 여러 개 올리면 어떻게 처리해야 하지?'
'맞춤 채용 공고 알림을 받을 이메일 주소도 검증해야 하지 않나?'
'쿼리(query) 문을 작성할 때 어떻게 타고 들어가야 더 빨리 값을 조회할 수 있을까?'
'지금은 겹치는 기술 키워드로 채용 공고 알림을 보내는데, 만약 학력이나 경력 같은 조건을 추가해야 한다면?'
'이메일이 발송된 뒤 수신자가 채용 공고 URL을 클릭해 들어갔을 때, 그 기록을 남길 수 있다면 알림 기능의 효율성을 나중에 평가할 수 있지 않을까? 리다이렉트(redirect) 기능을 사용해서 URL을 눌렀을 때 우리 사이트를 한 번 거친다면 언제 주로 확인하는지, 얼마나 많이 누르는지 분석할 수 있지 않을까?'
처음에는 발표회 전까지 무조건 모든 작업을 끝내야 한다는 압박감을 느꼈는데, 성능 개선을 그 이후에 하지 말라는 법은 없었다. 정답이 없는 분야에서 프로젝트가 끝났다고 해서 더는 건들면 안 된다고 생각하다니. 물론 이것저것 다 해보면 좋겠지만, 아쉬운 부분은 개선점으로 남겨두고 앞으로도 계속 공부하면서 서비스를 다듬어 가면 되었다. 이렇게 마음먹으니 다른 사람 눈에는 '멍때리는 모습'처럼 보였을 고민하는 시간이 낭비로 느껴지지 않았다.
최종은 글자 그대로 마지막 막, 그뿐이었다.
연극은 그다음 날에도, 언제든 열면 되었다.
프로젝트를 진행하다가 조바심이 기웃댈 때마다 이 두 마디를 되새겨야겠다.
'끝을 보는 용기' 카테고리의 다른 글
Day 137 - 취하여(취업을 위하여) 프로젝트 36%, 더미 데이터(Dummy Data) 장인이 되어가다 (0) | 2025.02.20 |
---|---|
Day 136 - 취하여(취업을 위하여) 프로젝트 32%, 숨 참고 알림으로 딥 다이브(Deep Dive), 수신함 터뜨리기는 덤 (0) | 2025.02.19 |
Day 134 - 취하여(취업을 위하여) 프로젝트 24%, 이메일 전송하기에 성공하다 (0) | 2025.02.17 |
Day 133 - 취하여(취업을 위하여) 프로젝트 23%, 감은 잡았으니 남은 일은 실천뿐 (0) | 2025.02.16 |
Day 132 - 취하여(취업을 위하여) 프로젝트 22%, 갈 길이 구만리지만 그럴싸한 틀을 잡다 (0) | 2025.02.15 |