-
Notifications
You must be signed in to change notification settings - Fork 0
[✨feat] InternshipWorkingPeriod 구현 #57
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Conversation
- 근무 기간이 1개월 미만인 경우를 처리하는 INVALID_WORKING_PERIOD 코드 추가
- 근무 기간을 월 단위로 표현하는 값 객체 `InternshipWorkingPeriod` 구현 - 1개월 미만일 경우 예외 발생 - 한글 기간 문자열 변환 메서드(toKoreanPeriod) 제공 - equals, hashCode, toString 오버라이드
- from 메서드 테스트: 유효한 개월 수 입력 시 객체 생성 확인 - 잘못된 개월 수 입력(0 이하) 시 예외 발생 여부 검증 - toKoreanPeriod 메서드 테스트: "N개월" 형식의 문자열 반환 검증
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Pull Request Overview
This PR introduces a value object for internship working periods, adds validation and formatting logic, and defines a new error code for invalid inputs.
- Implement
InternshipWorkingPeriod
VO with positive-month validation and Korean-format output. - Define
InternshipErrorCode.INVALID_WORKING_PERIOD
for validation failures. - Add unit tests for
from
andtoKoreanPeriod
.
Reviewed Changes
Copilot reviewed 3 out of 3 changed files in this pull request and generated 1 comment.
File | Description |
---|---|
src/main/kotlin/com/terning/server/kotlin/domain/internshipAnnouncement/InternshipWorkingPeriod.kt | Introduce VO, validation, formatting, and override equals /hashCode /toString . |
src/main/kotlin/com/terning/server/kotlin/domain/internshipAnnouncement/InternshipErrorCode.kt | Add INVALID_WORKING_PERIOD error code with message. |
src/test/kotlin/com/terning/server/kotlin/domain/internshipAnnouncement/InternshipWorkingPeriodTest.kt | Add tests for valid/invalid creation and toKoreanPeriod . |
Comments suppressed due to low confidence (1)
src/main/kotlin/com/terning/server/kotlin/domain/internshipAnnouncement/InternshipWorkingPeriod.kt:31
- The overridden
toString
method isn’t covered by existing tests; consider adding a unit test to verify that it returns the expected "N개월" string.
override fun toString(): String = toKoreanPeriod()
companion object { | ||
fun from(months: Int): InternshipWorkingPeriod { | ||
return InternshipWorkingPeriod(months) | ||
} | ||
|
||
private fun validatePositive(months: Int) { | ||
if (months <= 0) { | ||
throw InternshipException(InternshipErrorCode.INVALID_WORKING_PERIOD) | ||
} | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The validatePositive
function is declared private inside the companion object, making it inaccessible from the init block. Consider moving validation logic into a private class-level function or changing its visibility so the init block can call it directly.
companion object { | |
fun from(months: Int): InternshipWorkingPeriod { | |
return InternshipWorkingPeriod(months) | |
} | |
private fun validatePositive(months: Int) { | |
if (months <= 0) { | |
throw InternshipException(InternshipErrorCode.INVALID_WORKING_PERIOD) | |
} | |
} | |
private fun validatePositive(months: Int) { | |
if (months <= 0) { | |
throw InternshipException(InternshipErrorCode.INVALID_WORKING_PERIOD) | |
} | |
} | |
companion object { | |
fun from(months: Int): InternshipWorkingPeriod { | |
validatePositive(months) | |
return InternshipWorkingPeriod(months) | |
} |
Copilot uses AI. Check for mistakes.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
해당 제안은 Kotlin 동작 방식에 대한 오해로 보입니다. 🙌
validatePositive 함수는 companion object 내부에 private으로 선언되어 있지만, Kotlin에서는 클래스 본문(예: init 블록)에서 직접 호출할 수 있습니다. 실제로 현재 구조는 잘 동작하고 있으며, 유효성 검증 로직을 생성자 외부로 분리해 책임을 명확히 한 구조입니다.
따라서 해당 함수의 위치를 클래스 레벨로 옮기지 않아도 되고, 변경 없이 유지하는 것이 더 적절하다고 판단했습니다. 😊
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
해당 사안에 대해 저도 companion object 안에 private 함수를 두는 것과, 클래스 레벨에서 private 함수를 두는 것과의 차이에 대해 고민을 해보았는데요!
저는 인스턴스가 생성될 때 init 영역이 실행되고, companion object는 인스턴스 생성 없이도 접근이 가능한 영역임을 고려했을 때
validatePositive
함수는 클래스 레벨에서 private 함수로 두는 것이 더 적절하지 않은가 하는 생각이 들었어요!
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
덧붙이자면, 어차피 외부에서 바로 해당 함수를 접근하지 못하기 때문에 companion object가 꼭 필요 없겠다는 생각이 들기도 하네요..!
companion object 내부 안에서 로직이 복잡해졌을 때 추가적으로 private 함수를 두는 것이 좋다는 입장입니다!
이에 대해 장순님은 어떻게 생각하시는지 궁금해요🙂
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
네, 말씀해주신 부분들을 저도 쭉 읽어보면서 고민해보았는데요!
현재 구조처럼 validatePositive
를 companion object
안에 두고 사용하는 방식이
Kotlin의 스코프 규칙 안에서도 잘 작동하고, 생성 책임과 유효성 검증 책임이 한 영역에 모여 있어서
응집도 면에서도 괜찮은 구조라는 생각이 들었습니다.
성능적인 측면에서도, companion object는 클래스 로딩 시점에 한 번만 메모리에 올라오기 때문에
자주 인스턴스화되는 VO에서 클래스 전체 스코프에 유틸성 메서드를 선언하는 것보다
static한 영역에 고정시켜 두는 것이 GC나 메모리 측면에서도 더 유리한 선택이 아닐까 하는 생각도 들었습니다.
물론, 유효성 검사가 다른 메서드들과도 공유되는 등 범용적으로 쓰이게 된다면
클래스 레벨로 끌어올리는 것도 고민해볼 수 있을 것 같지만,
지금처럼 생성 시점에만 사용되고 있다면 이 구조가 유지되는 게 더 자연스럽고 효율적일 것 같습니다!
혹시라도 제가 놓친 시나리오가 있다면 편하게 더 이야기해주셔도 좋습니다 🙂
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
companion object에 대해 한 번 생각하니 고민이 계속 깊어지는 순간이네요..😂
덕분에 저도 여태껏 작성해본 코드들을 되돌아본 것 같아요!
수고하셨습니다~!!
private fun validatePositive(months: Int) { | ||
if (months <= 0) { | ||
throw InternshipException(InternshipErrorCode.INVALID_WORKING_PERIOD) | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
여기두 상수화 부탁합니당..!!
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
앗! 빠뜨렸네요 😅
말씀해주신 대로 상수로 분리해서 의미를 더 명확히 드러낼 수 있도록 정리해보겠습니다!
꼼꼼하게 봐주셔서 감사합니다 🙇♂️✨
fun `create instance when valid months given`() { | ||
// given | ||
val months = 3 | ||
|
||
// when | ||
val period = InternshipWorkingPeriod.from(months) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
단순 궁금증에 여쭤봅니다!
아래 테스트 코드들에서는 그냥 정수를 넣어주고 있는데 해당 테스트 코드 케이스에서는 month
라고 변수화를 해주고 있어서 혹시 장순님의 기준이 있는 건지 궁금했어요..!
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
좋은 질문 감사합니다! 🙏
사실 이 부분은 명확한 기준이 있다기보다는,
"해당 값에 의미를 부여하고 싶을 때는 변수로 선언하고, 그렇지 않을 경우에는 인라인으로 작성하는 편"인데요,
이 테스트에서는 "유효한 month를 넘겼을 때"라는 케이스 자체가 핵심이라
months라는 이름으로 문맥을 명확히 드러내고 싶어서 변수화했던 것 같아요!
반대로 다른 테스트들에서는 특별한 의미 없이 단순히 값을 넘기기만 해서 인라인으로 처리했던 것 같습니다 😅
일관성 측면에서는 통일하는 게 더 좋을 것 같기도 해서,
이번 기회에 기준을 한 번 더 다듬어보는 계기로 삼아보겠습니다! 질문 감사합니다 🙇♂️✨
companion object { | ||
fun from(months: Int): InternshipWorkingPeriod { | ||
return InternshipWorkingPeriod(months) | ||
} | ||
|
||
private fun validatePositive(months: Int) { | ||
if (months <= 0) { | ||
throw InternshipException(InternshipErrorCode.INVALID_WORKING_PERIOD) | ||
} | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
해당 사안에 대해 저도 companion object 안에 private 함수를 두는 것과, 클래스 레벨에서 private 함수를 두는 것과의 차이에 대해 고민을 해보았는데요!
저는 인스턴스가 생성될 때 init 영역이 실행되고, companion object는 인스턴스 생성 없이도 접근이 가능한 영역임을 고려했을 때
validatePositive
함수는 클래스 레벨에서 private 함수로 두는 것이 더 적절하지 않은가 하는 생각이 들었어요!
📄 Work Description
InternshipWorkingPeriod
를 구현했습니다.InternshipException
을 발생시키도록 했습니다.toKoreanPeriod
메서드를 제공하여 "N개월" 형식으로 반환합니다.InternshipErrorCode.INVALID_WORKING_PERIOD
항목을 새롭게 정의했습니다.💭 Thoughts
equals
,hashCode
,toString
을 오버라이드하여 VO 특성을 보장하며, 출력 포맷은 명확히 분리된 메서드로 관리했습니다.✅ Testing Result
🗂 Related Issue