Skip to content

[✨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

Merged
merged 6 commits into from
May 26, 2025
Merged

[✨feat] InternshipWorkingPeriod 구현 #57

merged 6 commits into from
May 26, 2025

Conversation

jsoonworld
Copy link
Member

📄 Work Description

  • 인턴십 공고의 근무 기간을 표현하는 VO InternshipWorkingPeriod를 구현했습니다.
  • 유효성 검증을 통해 0 이하의 개월 수 입력 시 InternshipException을 발생시키도록 했습니다.
  • 기간 정보를 사용자에게 보여주기 위해 toKoreanPeriod 메서드를 제공하여 "N개월" 형식으로 반환합니다.
  • 예외 처리를 위해 InternshipErrorCode.INVALID_WORKING_PERIOD 항목을 새롭게 정의했습니다.

💭 Thoughts

  • 단순히 개월 수를 Int로 관리하면 유효하지 않은 값이 혼입될 가능성이 있어 VO로 추상화했습니다.
  • equals, hashCode, toString을 오버라이드하여 VO 특성을 보장하며, 출력 포맷은 명확히 분리된 메서드로 관리했습니다.
  • 앞으로 기간과 관련된 도메인 규칙(예: 최대 개월 수 제한 등)이 생기더라도 이 VO를 중심으로 확장할 수 있는 구조입니다.

✅ Testing Result

스크린샷 2025-05-19 오후 11 28 37


🗂 Related Issue

- 근무 기간이 1개월 미만인 경우를 처리하는 INVALID_WORKING_PERIOD 코드 추가
- 근무 기간을 월 단위로 표현하는 값 객체 `InternshipWorkingPeriod` 구현
- 1개월 미만일 경우 예외 발생
- 한글 기간 문자열 변환 메서드(toKoreanPeriod) 제공
- equals, hashCode, toString 오버라이드
- from 메서드 테스트: 유효한 개월 수 입력 시 객체 생성 확인
- 잘못된 개월 수 입력(0 이하) 시 예외 발생 여부 검증
- toKoreanPeriod 메서드 테스트: "N개월" 형식의 문자열 반환 검증
Copy link

@Copilot Copilot AI left a 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 and toKoreanPeriod.

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()

Comment on lines 13 to 22
companion object {
fun from(months: Int): InternshipWorkingPeriod {
return InternshipWorkingPeriod(months)
}

private fun validatePositive(months: Int) {
if (months <= 0) {
throw InternshipException(InternshipErrorCode.INVALID_WORKING_PERIOD)
}
}
Copy link
Preview

Copilot AI May 19, 2025

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.

Suggested change
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.

Copy link
Member Author

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 블록)에서 직접 호출할 수 있습니다. 실제로 현재 구조는 잘 동작하고 있으며, 유효성 검증 로직을 생성자 외부로 분리해 책임을 명확히 한 구조입니다.

따라서 해당 함수의 위치를 클래스 레벨로 옮기지 않아도 되고, 변경 없이 유지하는 것이 더 적절하다고 판단했습니다. 😊

Copy link
Member

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 함수로 두는 것이 더 적절하지 않은가 하는 생각이 들었어요!

Copy link
Member

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 함수를 두는 것이 좋다는 입장입니다!

이에 대해 장순님은 어떻게 생각하시는지 궁금해요🙂

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

네, 말씀해주신 부분들을 저도 쭉 읽어보면서 고민해보았는데요!

현재 구조처럼 validatePositivecompanion object 안에 두고 사용하는 방식이
Kotlin의 스코프 규칙 안에서도 잘 작동하고, 생성 책임과 유효성 검증 책임이 한 영역에 모여 있어서
응집도 면에서도 괜찮은 구조라는 생각이 들었습니다.

성능적인 측면에서도, companion object는 클래스 로딩 시점에 한 번만 메모리에 올라오기 때문에
자주 인스턴스화되는 VO에서 클래스 전체 스코프에 유틸성 메서드를 선언하는 것보다
static한 영역에 고정시켜 두는 것이 GC나 메모리 측면에서도 더 유리한 선택이 아닐까 하는 생각도 들었습니다.

물론, 유효성 검사가 다른 메서드들과도 공유되는 등 범용적으로 쓰이게 된다면
클래스 레벨로 끌어올리는 것도 고민해볼 수 있을 것 같지만,
지금처럼 생성 시점에만 사용되고 있다면 이 구조가 유지되는 게 더 자연스럽고 효율적일 것 같습니다!

혹시라도 제가 놓친 시나리오가 있다면 편하게 더 이야기해주셔도 좋습니다 🙂

Copy link
Member

@leeeyubin leeeyubin left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

companion object에 대해 한 번 생각하니 고민이 계속 깊어지는 순간이네요..😂
덕분에 저도 여태껏 작성해본 코드들을 되돌아본 것 같아요!
수고하셨습니다~!!

Comment on lines 18 to 21
private fun validatePositive(months: Int) {
if (months <= 0) {
throw InternshipException(InternshipErrorCode.INVALID_WORKING_PERIOD)
}
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

여기두 상수화 부탁합니당..!!

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

앗! 빠뜨렸네요 😅
말씀해주신 대로 상수로 분리해서 의미를 더 명확히 드러낼 수 있도록 정리해보겠습니다!
꼼꼼하게 봐주셔서 감사합니다 🙇‍♂️✨

Comment on lines +15 to +20
fun `create instance when valid months given`() {
// given
val months = 3

// when
val period = InternshipWorkingPeriod.from(months)
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

단순 궁금증에 여쭤봅니다!
아래 테스트 코드들에서는 그냥 정수를 넣어주고 있는데 해당 테스트 코드 케이스에서는 month라고 변수화를 해주고 있어서 혹시 장순님의 기준이 있는 건지 궁금했어요..!

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

좋은 질문 감사합니다! 🙏
사실 이 부분은 명확한 기준이 있다기보다는,
"해당 값에 의미를 부여하고 싶을 때는 변수로 선언하고, 그렇지 않을 경우에는 인라인으로 작성하는 편"인데요,

이 테스트에서는 "유효한 month를 넘겼을 때"라는 케이스 자체가 핵심이라
months라는 이름으로 문맥을 명확히 드러내고 싶어서 변수화했던 것 같아요!
반대로 다른 테스트들에서는 특별한 의미 없이 단순히 값을 넘기기만 해서 인라인으로 처리했던 것 같습니다 😅

일관성 측면에서는 통일하는 게 더 좋을 것 같기도 해서,
이번 기회에 기준을 한 번 더 다듬어보는 계기로 삼아보겠습니다! 질문 감사합니다 🙇‍♂️✨

Comment on lines 13 to 22
companion object {
fun from(months: Int): InternshipWorkingPeriod {
return InternshipWorkingPeriod(months)
}

private fun validatePositive(months: Int) {
if (months <= 0) {
throw InternshipException(InternshipErrorCode.INVALID_WORKING_PERIOD)
}
}
Copy link
Member

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 함수로 두는 것이 더 적절하지 않은가 하는 생각이 들었어요!

@jsoonworld jsoonworld merged commit 9ecd0cc into feat/#54 May 26, 2025
1 check passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging this pull request may close these issues.

2 participants