Skip to content
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

2단계 - 수강신청(도메인 모델) #15

Merged
merged 29 commits into from May 22, 2023
Merged

Conversation

dkswnkk
Copy link

@dkswnkk dkswnkk commented May 18, 2023

안녕하세요 멘토님!!, 2단계도 잘 부탁드립니다!!☺️

이번 2단계 미션은 요구사항이 그렇게까지 구체적이지 않아서 어디까지 설계해야 하나..라는 고민이 많이 들었네요

일단 2단계에서 요구하는 아래 사항들은 전부 구현했습니다.

  • 과정(Course)은 기수 단위로 여러 개의 강의(Session)를 가질 수 있다.
  • 강의는 시작일과 종료일을 가진다.
  • 강의는 강의 커버 이미지 정보를 가진다.
  • 강의는 무료 강의와 유료 강의로 나뉜다.
  • 강의 상태는 준비중, 모집중, 종료 3가지 상태를 가진다.
  • 강의 수강신청은 강의 상태가 모집중일 때만 가능하다.
  • 강의는 강의 최대 수강 인원을 초과할 수 없다.

추가로 각 엔티티들의 컬럼들을 nullable = false하게 주고싶은데, 현재 JPA를 사용하는것이 아니고, 다음 단계에서 DDL로 정의하는 것 같아 null값을 검증하는 로직들은 추가하지 않았습니다!

Copy link

@nokchax nokchax left a comment

Choose a reason for hiding this comment

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

안녕하세요, 주형님!
두번째 단계 잘 진행해 주셨네요 :)
몇가지 코멘트 남겼는데 확인 부탁드립니다. 🙇


- DB 테이블 설계 없이 도메인 모델부터 구현한다.
- 도메인 모델은 TDD로 구현한다.
Copy link

Choose a reason for hiding this comment

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

커밋이력을 보니 TDD 방식이 아닌 구현후 테스트를 추가해 주셨더라구요,
진행하시면서 TDD도 시도해 보시는건 어떨까요?

Copy link
Author

Choose a reason for hiding this comment

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

이 부분은 제가 수시로 commit을 한 게 아니라 push 직전에 전부 커밋 하다 보니 순서가 어긋나서 그런 것 같습니다 ㅎㅎ..
혼란의 여지가 없도록 하겠습니당


import nextstep.courses.domain.enums.ImageType;

public class Image extends BaseEntity {
Copy link

Choose a reason for hiding this comment

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

image에 대해 어디까지 생각하시고 필드를 만들어 주셨는지 잘 모르겠지만, 필드에 대한 검증이 필요하지 않을까요?
예를 들어 사이즈에 대한 제한이라던지, 유효하지 않은 이미지 타입이 들어왔다 던지, uri가 유효한지 등 다양한 경우가 있을거 같네요

import java.util.ArrayList;
import java.util.List;

public class Session extends BaseEntity {
Copy link

Choose a reason for hiding this comment

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

필드가 많아 보이네요, 시작일과 종료일을 하나로 묶은 클래스를 추출하거나,
users와 maximumEnrollment 를 묶어 추출하는 것처럼 연관이 있는 필드를 묶어 처리하면
Session 클래스가 가진 책임을 나눌 수 있을것 같아요

}

private void checkSessionStatus() throws SessionEnrollmentException {
if (this.sessionStatus != SessionStatus.RECRUITING) {
Copy link

Choose a reason for hiding this comment

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

값을 비교하지 말고 함수를 통해 판단하는 게 어떨까요?

sessionStatus.canEnroll()

@@ -0,0 +1,7 @@
package nextstep.courses.exception;

public class InvalidSessionDateTimeException extends Exception {
Copy link

Choose a reason for hiding this comment

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

Exception을 상속하신 특별한 이유가 있을까요?

Copy link
Author

Choose a reason for hiding this comment

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

이 부분은 저도 고민을 좀 하다가 미션 기존 템플릿에 Exception을 상속하고 있길래 따라 맞춰서 작성했는데, 수정하도록 하겠습니다!


import static org.junit.jupiter.api.Assertions.*;

class SessionTest {
Copy link

Choose a reason for hiding this comment

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

전반적으로 예외가 발생하는 경우에 대한 테스트만 존재하네요, 성공했을 때의 테스트도 해야하지 않을까요?
예를 들어 수강 신청을 했을 때, 수강생이 늘어난 것을 테스트 하는것이 있겠네요

SessionType.FREE, SessionStatus.RECRUITING, 100));
}

@DisplayName("강의가 모집중이 아닌데 수강 등록을 하면 예외를 던진다.")
Copy link

Choose a reason for hiding this comment

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

모집중이 아닌 경우에는 ENDED 외에도 존재하지 않나요?

Copy link

@nokchax nokchax left a comment

Choose a reason for hiding this comment

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

안녕하세요, 주형님!
피드백 잘 적용해 주셨습니다 👍
몇가지 좀 더 개선할 부분이 있어
코멘트 남겨뒀는데, 확인 부탁드려요 🙇


public class Image extends BaseEntity {
private static final Long MAX_SIZE = 5L * 1024 * 1024; // 5MB
Copy link

Choose a reason for hiding this comment

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

👍

}

private void checkSessionStatus() throws SessionEnrollmentException {
if (this.sessionStatus != SessionStatus.RECRUITING) {
if (!SessionStatus.canEnroll(this.sessionStatus)) {
Copy link

Choose a reason for hiding this comment

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

객체에게 너의 상태가 수강 신청 가능하니? 라고 물어보면 될 것 같은데요
this.sessionStatus.canEnroll() 이면 충분하지 않을까요?

@@ -14,4 +16,9 @@ public enum ImageType {
public String getMimeType() {
return this.value;
}

public static boolean canUpload(ImageType type) {
Copy link

Choose a reason for hiding this comment

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

ImageType 에는 등록 가능한 확장자 밖에 없기 때문에 무의미한 함수로 보입니다.
이미지의 확장자를 string으로 받아서 확인을 해야 의미가 생기지 않을까요?

@@ -14,4 +16,9 @@ public enum SessionStatus {
public String getDescription() {
return this.description;
}

public static boolean canEnroll(SessionStatus sessionStatus) {
Copy link

Choose a reason for hiding this comment

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

위에도 남겼지만 스태틱 메서드보다는 인스턴스 메서드를 통해 확인하는 게 객체지향 다운 방식이라고 봐야해요
추가적으로 enum의 함수도 테스트해주세요~!

private static final User SAMPLE_USER = new User(1L, "dkswnkk", "pwd", "안주형", "dkswnkk.dev@gmail.com");


@DisplayName("강의 시작일이 종료일보다 늦으면 예외를 던진다.")
Copy link

Choose a reason for hiding this comment

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

SessionTime에 대한 테스트는 SessionTimeTest로 옮겨 코드를 나눠주세요

}

private static void validateType(String typeString) throws InvalidImageException {
if (!ImageType.isValidType(typeString)) {
Copy link
Author

Choose a reason for hiding this comment

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

요 부분은 인스턴스 메서드의 사용이 불가능한데, 아직 생성할 떄의 검증 로직 같은 경우는 static 메서드를 활용해도 될까요..?

"인스턴스 메서드를 통해 확인하는 게 객체지향 다운 방식이다."라고 피드백을 주셨는데, 현재 이 로직 부분에서는 상태를 아직 가지기 않았기 때문에 static으로 검증해도 된다고 생각했습니다.! 아니면 설계 자체를 잘못한걸까용..?

Copy link

Choose a reason for hiding this comment

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

validType(typeString);
image.type = ImageType.valueOf(typeString.toUpperCase());

검증에 대한 책임이 올바른 곳에 존재하지 않아서 이렇게 된 것 같아요.
이미지 타입에 관한 검증은 ImageType enum 내부에 존재해야하지 않을까요?
valid함수를 제거하고. 아래와 같이 ImageType내부에 새로운 정적 함수를 만들어. (일종의 생성자)

image.type = ImageType.of(typeString);

를 통해 검증에 대한 책임을 ImageType에 전가하면 해결 되겠네요.

Copy link

@nokchax nokchax left a comment

Choose a reason for hiding this comment

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

안녕하세요, 주형님!
피드백 빠르게 잘 적용해 주셨네요 👍
한가지만 더 수정했으면 해서 코멘트 남겼습니다.
확인 부탁드려요 🙇

public static boolean canEnroll(SessionStatus sessionStatus) {
return Objects.equals(RECRUITING, sessionStatus);
public boolean canEnroll() {
return Objects.equals(RECRUITING, this);
Copy link

Choose a reason for hiding this comment

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

this == RECRUITING

이면 충분 할 것 같네요

}

private static void validateType(String typeString) throws InvalidImageException {
if (!ImageType.isValidType(typeString)) {
Copy link

Choose a reason for hiding this comment

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

validType(typeString);
image.type = ImageType.valueOf(typeString.toUpperCase());

검증에 대한 책임이 올바른 곳에 존재하지 않아서 이렇게 된 것 같아요.
이미지 타입에 관한 검증은 ImageType enum 내부에 존재해야하지 않을까요?
valid함수를 제거하고. 아래와 같이 ImageType내부에 새로운 정적 함수를 만들어. (일종의 생성자)

image.type = ImageType.of(typeString);

를 통해 검증에 대한 책임을 ImageType에 전가하면 해결 되겠네요.

Comment on lines 16 to 17
@Test
@DisplayName("강의 상태가 모집중이 아닐때 false를 반환한다.")
Copy link

Choose a reason for hiding this comment

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

@ParameterizedTest 를 통해 상태값을 파라미터로 받아 한줄이라도 중복을 줄여보면 어떨까요?

Copy link

@nokchax nokchax left a comment

Choose a reason for hiding this comment

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

안녕하세요, 주형님! 리뷰가 늦었네요 🙇
피드백 잘 적용해 주셨습니다 👍
바로 머지하겠습니다. 다음 단계 진행해주세요 :)

Comment on lines +21 to +24
return Arrays.stream(values())
.filter(imageType -> imageType.getValue().equals(value.toLowerCase()))
.findFirst()
.orElseThrow(() -> new IllegalArgumentException("지원하지 않는 이미지 형식입니다."));
Copy link

Choose a reason for hiding this comment

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

👍

() -> assertFalse(SessionStatus.ENDED.canEnroll())
);
@ParameterizedTest
@EnumSource(value = SessionStatus.class, names = {"PREPARING", "ENDED"})
Copy link

Choose a reason for hiding this comment

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

👍

@nokchax nokchax merged commit 87b58fe into next-step:dkswnkk May 22, 2023
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

None yet

2 participants