Skip to content

[1주차] 멀티 모듈 구조 사용 및 현재 상영 중인 영화 조회 API 개발#10

Open
sliverzero wants to merge 30 commits intohanghae-skillup:mainfrom
sliverzero:week1
Open

[1주차] 멀티 모듈 구조 사용 및 현재 상영 중인 영화 조회 API 개발#10
sliverzero wants to merge 30 commits intohanghae-skillup:mainfrom
sliverzero:week1

Conversation

@sliverzero
Copy link

@sliverzero sliverzero commented Jan 10, 2025

제목(title)

[1주차] 멀티 모듈 구조 사용 및 현재 상영 중인 영화 조회 API 개발

작업 내용

  1. 멀티 모듈 구조 사용

  2. 현재 상영 중인 영화 조회 API 개발

    조회 결과

    image

발생했던 문제와 해결 과정을 남겨 주세요.

  • 문제1
    docker-compose와 Main 클래스 실행 후 발생하는 오류
    image

  • 해결 방법1

    • 기존에 MySQL이 설치 되었을 경우 포트 번호를 다르게 설정해야 합니다.

    docker-compose.yml

    image

    application.yml

    image

이번 주차에서 고민되었던 지점이나, 어려웠던 점을 알려 주세요.

  • 멀티 모듈 구조를 사용할 때 계층별 모듈화, 도메인별 모듈화 중 어느 방식을 써야 할지 고민이 되었습니다.
    • 도메인별로 나눠서 module-movie는 영화만 관련된 로직을 처리하려는 의도로 진행했는데 괜찮은 접근 방식인지 궁금합니다.
  • 테이블 설계하는 방식이 고민이 되었습니다.
    • 영상물 등급의 경우 값이 추가될 가능성이 적다고 판단하여 ENUM으로 작성했습니다.
    • 장르의 경우 값이 추가될 가능성이 있다고 판단하여 따로 테이블을 생성했습니다.

리뷰 포인트

  • 하위 모듈로 적절히 모듈화 했는지 궁금합니다.
  • ScreeningRepositoryImpl에서 createQuery는 괜찮은 코드인지 궁금합니다.
  • ScreeningService에서 entity -> dto 변환 과정은 괜찮은 코드인지 궁금합니다.
    (JPA랑 dto 변환 등은 프로젝트에 처음 적용해 봐서 맞는 방향으로 진행했는지 궁금합니다..!)

기타 질문

  • 성능 테스트를 위한 데이터 500개 정도를 넣을 때 영화를 40개 정도 넣었고 각 영화가 상영관 2개에서 2시간 간격으로 7개 정도 상영한다고 가정하고 데이터를 넣었습니다.
    -> 영화마다 총 14번 상영되는 식으로 데이터를 넣었는데 이런 식으로 하는 게 맞는지 궁금합니다.
  • 찾아본 바로는 인텔리제이에서 .http 파일은 Ultimate 버전에서 지원한다고 알고 있습니다. 제가 인텔리제이 무료 버전을 쓰고 있는데 코드 작성할 때는 postman으로 테스트하고 결과가 잘 나왔다면 그걸로 .http 파일 추가하는 식으로 해도 될까요?
  • 프로젝트 경험이 거의 없어서 설계부터 코드 작성까지 리뷰 해야 할 점이 너무 많겠지만(죄송합니다ㅠㅠ) 리뷰 해주신 것 보고 열심히 배우겠습니다!

@DongHyunKIM-Hi
Copy link

개인적으로는 멀티모듈을 구성할 때 도메인별로 나눠서 구분하는 방식을 더 선호합니다. 이유는 현재 멀티 모듈에 대해서 잘 알지못하는 상황에서 프로젝트를 진행 할 때는 참조할만한 다양한 레퍼런스가 많이 있어야 하는데 도메인별로 구분된 경우가 레퍼런스가 압도적으로 많이 있기 때문입니다.
그래서 현재 생각하는 구조에 대한 접근 방향이 좋은 것 같습니다.

장르를 테이블로 따로 뺄 필요가 있을까? 라는 생각이 들기는 합니다. 영화의 필드로 가지고 있고 이를 Enums로 구분하면 더 좋지 않을까? 그 이유는 장르라고 해봐야 아무리 많아봐야 컬럼이 10개 이내라고 생각이 들고 장르가 이후에 다양하게 추가될 것도 아니기 때문입니다. 이런 경우에 그냥 Enums로 관리하면 충분한데 굳이 테이블로 뺄 필요가 있을까? 라는 접근 입니다.

모듈로 잘 분리한 것 같기는 하지만 구조가 조금은 헷갈리는 것 같아요.
스크리닝 모듈은 controller, service 등등 가지고 있고 무비나, 극장의 경우는 domain만 가지고 있는데 이게 아직 작성되기 전이라고하면 상관 없는데 그렇지 않다면 구조를 통일해주는 것이 좋을 것 같습니다. 제가 이해한 바로는 도메인별로 분리하려고 했고 가지고 있는 도메인을 극장, 스크리닝, 영화 로 이해했습니다.

ScreeningRepositoryImpl에서 createQuery는 괜찮기는 하지만 굳이 이렇게 복잡하게 처리할 필요가 있는가에 대한 근본적인 의문이 생기기는 합니다. 현재 작성된 코드가 1개의 api 뿐이라서 어떤 구조로 프로젝트를 진행하고 각각의 모듈별로 어떻게 상호작용 할 것인지에 대한 그림이 명확하게 그려지진 않네요.

ScreeningService에서 entity -> dto 변환 과정은 개인적으로는 정적 팩토리 메서드를 사용해서 처리하는 것을 선호합니다.
현재는 생성자에 필드 때려넣어서 dto 객체를 생성하고 있는데 이렇게 사용된다면 해당 객체가 어떤 이유로 생성 되었는지 파악하기가 어렵습니다. 그래서 정적 팩토리 메서드를 사용한다면 특정 객체가 어떤 이유로 생성 되었는지 메서드 이름으로 지정해줄 수 있어서 더 좋습니다.
또한 불필요한 복잡한 로직을 service 부분에서 처리하는 것이 아니라 코드의 가독성도 개선될 것 같아요.

테스트를 진행할 때는 지금처럼 어떤 시나리오를 만들고 그 시나리오에서 정상적으로 서비스를 제공할 수 있을지에 대해서 작성하면 좋습니다. 현재 설정한 시나리오에 대해서는 너무 잘 설정한 것 같아요. 이제 여기서 이런 상황이 발생한다면? 저런 상황이 발생할수도 있지 않을까? 하면서 예외 혹은 특수 상황을 주고이를 대응하면서 프로젝트를 고도화 시킬 수 있습니다. 너무 잘 작성하셨어요.

.http 를 테스트 할 수 없는 상황이라면 굳이 .http를 제공할 필요는 없다고 생각합니다. 대신에 테스트 코드를 통해서 내가 만든 코드들이 정상적으로 동작함을 보여주면 될 것 같아요.

dependencies {
// 모듈 의존성
implementation project(':module-common')
implementation project(':module-theater')

Choose a reason for hiding this comment

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

현재는 사용하지 않고 작성된 api 가 없어서 제거한 것이 맞는 것이겠죠? 이후에 추가된다면 상관은 없지면 현재 구조로 간다면 구조를 통일해서 사용하는 것이 좋다고 생각합니다.

Copy link
Author

@sliverzero sliverzero Jan 12, 2025

Choose a reason for hiding this comment

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

  • module-theater은 api 작성할 때 사용하지 않은 모듈이라 삭제했습니다!

  • module-api에 module-theater을 의존하고 있는 module-screening을 추가했고 이후에 api 쪽에 다른 의존성이 추가될 가능성이 적을 것 같습니다.

  • module-movie, module-theater에도 필요하면 controller, repository, service 작성할 생각으로 도메인별 모듈을 생성했지만 시나리오상 필요하지 않을 것 같아 작성하진 않았습니다. controller, repository, service 이 부분이 작성되기 전 상황은 맞지만 앞으로도 시나리오상 추가하지 않을 것 같다면 구조를 통일시키는 게 좋을까요?

  • 구조를 통일하라는 말씀은 domain만 있던 movie나 theater 모듈을 따로 사용하지 않고 module-common쪽에 domain 패키지로 관리하면 되는 것일까요?

Choose a reason for hiding this comment

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

아하 시나리오상 필요 없어서 현재 필요한 부분에 대해서만 진행하신 것이군요! 도메인 별로 모듈을 구분하였는데 스크리닝 모듈과 다른 무비, 극장 모듈과 같은 레벨의 모듈로 보이는데 스크리닝 모듈에만 service, repository 등등의 구조들이 보이길래 말씀드렸습니다!

LocalDate todayDate = LocalDate.now();
List<Screening> currentScreenings = screeningRepository.findCurrentScreenings(todayDate);

return currentScreenings.stream()

Choose a reason for hiding this comment

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

해당 부분은 정적팩토리 메서드로 변환하는 과정이나 컬럼들은 ScreeningDto 클래스 내에서 처리하는 것이 더 가독성 측면에서 유리할 것 같습니다. 아래와 같은 느낌으로 말이죠!
currentScreenings.stream()
.map(ScreeningDto::of)
.toList();

private String genreName;
private String theaterName;
private LocalTime startTime;
private LocalTime endTime;

Choose a reason for hiding this comment

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

이런식으로 정적팩토리 메서드 사용
public static ScreeingDto of (Screeing screeing){
return new ScreeingDto(.....)
}

@DongHyunKIM-Hi
Copy link

커밋 메시지를 못찾아서 그런데 현재 모듈벼로 의존하고 있는 것 보면 중복된 코드를 가지고 있는 것 같아요.
예를 들어서 module-movie는 implementation project(':module-common') 를 가지고 있는데

implementation project(':module-common') 에서 implementation 'org.springframework.boot:spring-boot-starter-data-jpa'를 가지고 있음에도 module-movie에서도 implementation 'org.springframework.boot:spring-boot-starter-data-jpa'
를 가지고 있어요.

멀티 모듈을 사용하는 이유는 각 모듈별로 의존하고 있는 설정값들을 어렵게 연결해서 설정하는 불편함은 있지만 중복된 설정들 중복된 내용들을 줄일 수 있어서 사용하는데 현재는 불필요한 코드 중복이 반복하고 있는 구조 입니다.

module-movie

dependencies {
    // 모듈 의존성
    implementation project(':module-common')

    implementation 'org.springframework.boot:spring-boot-starter-data-jpa'
    compileOnly 'org.projectlombok:lombok'
    annotationProcessor 'org.projectlombok:lombok'
    developmentOnly 'org.springframework.boot:spring-boot-devtools'
    runtimeOnly 'com.mysql:mysql-connector-j'

    testImplementation platform('org.junit:junit-bom:5.9.1')
    testImplementation 'org.junit.jupiter:junit-jupiter'
    testImplementation 'org.springframework.boot:spring-boot-starter-test'
    testImplementation 'org.springframework.boot:spring-boot-starter-data-jpa'
}

module-common

dependencies {
    implementation 'org.springframework.boot:spring-boot-starter-data-jpa'
    compileOnly 'org.projectlombok:lombok'
    annotationProcessor 'org.projectlombok:lombok'
    developmentOnly 'org.springframework.boot:spring-boot-devtools'
    runtimeOnly 'com.mysql:mysql-connector-j'

    testImplementation platform('org.junit:junit-bom:5.9.1')
    testImplementation 'org.junit.jupiter:junit-jupiter'
    testImplementation 'org.springframework.boot:spring-boot-starter-test'
    testImplementation 'org.springframework.boot:spring-boot-starter-data-jpa'
}


@DongHyunKIM-Hi
Copy link

좋은점

  • 어떤 것을 작업하고 어떤 것을 모르고 하는 점과 이런 내용을 한눈에 보기 쉽게 readme로 구체적으로 작성해주는 것이 좋았다.
  • 커밋 메시지가 꼼꼼해서 좋았다. -> 단점과 연결

아쉬운점

  • 멀티모듈에 대한 개념에 대해서 꼭 한번 정리해봤으면 좋겠다. gradle 설정 중복이 발생하고 있음
  • 커밋 메시지가 불필요하게 너무 꼼꼼한 것 같다. 코드 한줄 변경에 커밋 한번 -> 코드 리뷰할 때 불필요하게 확인해야 할 커밋의 수가 늘어나게 됨.

@sliverzero
Copy link
Author

꼼꼼하게 리뷰해 주셔서 정말 감사합니다!

@phyeran phyeran changed the base branch from main to sliverzero January 17, 2025 02:07
@spartacontents spartacontents deleted the branch hanghae-skillup:main January 17, 2025 03:20
@phyeran phyeran changed the base branch from sliverzero to main January 19, 2025 05:58
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants