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

[BE] issue122: 스터디 참여 기능 #132

Merged
merged 29 commits into from
Jul 29, 2022
Merged

Conversation

tco0427
Copy link
Collaborator

@tco0427 tco0427 commented Jul 26, 2022

요약

스터디 참여 기능

세부 설명

도메인에서의 검증이나 스터디원 증가 로직이 중요하다고 판단하여, Bottom Up 으로 도메인 부터해서 올라가는 식으로 구현하였습니다. 오늘 인수 테스트 작성은 완료하지 못하였고, 내일 중으로 완료될 것 같습니다!
누락된 검증이나 피드백 주시면 감사하겠습니다!😃

  • API 명세 도출
  • 한 사람은 하나의 스터디에 대해 한 번만 참여가 가능하다.
  • 인원이 다 찼을 경우 모집을 종료한다.
  • CLOSE 상태의 스터디에는 참여가 불가능하다.
  • 모집 기간(enrollmentEndDate)인 동안만 참여가 가능하다.
  • 인수 테스트 작성

close #122

@tco0427 tco0427 self-assigned this Jul 26, 2022
@tco0427 tco0427 added 🚀 feature New feature or request 🖥 backend New backend feature labels Jul 26, 2022
Copy link
Collaborator

@sc0116 sc0116 left a comment

Choose a reason for hiding this comment

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

디우 잘 구현하셨네요 허허이~! 몇가지 코멘트 남겨두었어요 확인 부탁드려요!

@@ -34,6 +38,12 @@ public Details(final String title, final String excerpt, final String thumbnail,
this.description = description;
}

protected void checkStudyStatus() {
if (status.equals(CLOSE)) {
Copy link
Collaborator

Choose a reason for hiding this comment

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

status를 enum으로 두면 CLOSE같은 상수를 안써도 될 것 같네용

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

넵!! 린론 코드와 병합하는 과정에서 열거형 상수를 사용하게 되면 수정하도록 하겠습니다!

}

private boolean isInvalidMemberSize() {
return max == null || max <= size;
Copy link
Collaborator

Choose a reason for hiding this comment

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

max가 null이면 무제한이라는 뜻 아닌가요?? 무제한이면 받을 수 있지 않을까요?

Copy link
Collaborator Author

@tco0427 tco0427 Jul 28, 2022

Choose a reason for hiding this comment

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

    protected void checkParticipating(Long memberId) {
        if (isInvalidMemberSize() || isAlreadyParticipation(memberId)) {
            throw new InvalidParticipationStudyException();
        }
    }

넵!! 짱구 말처럼 스터디 최대 인원 이 설정되지 않은 경우에는 가입이 가능해야하는데요, 따라서 max == null 이면 isInvalidMemberSize 가 True가 반환되고 예외가 터지겠네요! max != null 로 수정하여야 겠네요!

오류 발견 굿굿!

}

protected void checkParticipatingPeriod() {
if (enrollmentEndDate != null && !enrollmentEndDate.isAfter(LocalDate.now())) {
Copy link
Collaborator

Choose a reason for hiding this comment

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

요건 취향이긴 한데 !와 isAfter면 isBefore가 더 쉽게 읽히지 않을까 합니다!

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

오..!! 좋은 생각입니다!😃

@@ -50,4 +58,18 @@ public boolean equals(final Object o) {
public int hashCode() {
return Objects.hash(enrollmentEndDate, startDate, endDate);
}

private void validatePeriod(final LocalDate enrollmentEndDate, final LocalDate startDate, final LocalDate endDate) {
if (isImproperStudyDate(startDate, endDate) || isImproperEnrollmentEndDate(enrollmentEndDate, endDate)) {
Copy link
Collaborator

Choose a reason for hiding this comment

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

굿굿

Copy link
Collaborator

@jaejae-yoo jaejae-yoo left a comment

Choose a reason for hiding this comment

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

디우 구현하느라 고생하셨어요 ~ 코멘트 확인 부탁드립니다.

public void checkStudyStatus() {
final Details details = new Details("title", "excerpt", "thumbnail", CLOSE, "description");

assertThatThrownBy(() -> details.checkStudyStatus());
Copy link
Collaborator

Choose a reason for hiding this comment

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

예외 타입은 확인하면 좋을 것 같아요 ~

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

좋습니다..!! isInstanceOf() 로 체크하도록 하겠습니다.👍


public Participants(final Integer size, final Integer max,
final List<Participant> participants, Long ownerId) {
final Set<Participant> participants, Long ownerId) {
Copy link
Collaborator

Choose a reason for hiding this comment

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

중복된 값 X 👍 명확해서 좋아요!


private boolean isAlreadyParticipation(final Long memberId) {
final Participant participant = new Participant(memberId);
return Objects.equals(memberId, ownerId) || participants.contains(participant);
Copy link
Collaborator

Choose a reason for hiding this comment

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

조건을 메서드로 분리하면 owner는 참여자에 포함하지 않기로 한 도메인 규칙이 잘 드러날 것 같아요!

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

그린론이 말해준 내용이 아래와 같을까요??
우선 아래와 같이 이해한대로 변경해 보았습니다!!

    private boolean isAlreadyParticipation(final Long memberId) {
        final Participant participant = new Participant(memberId);
        return isOwner(memberId) || isParticipant(participant);
    }

    private boolean isOwner(final Long memberId) {
        return Objects.equals(memberId, ownerId);
    }

    private boolean isParticipant(final Participant participant) {
        return participants.contains(participant);
    }

Comment on lines 41 to 46
protected void checkStudyStatus() {
if (status.equals(CLOSE)) {
throw new InvalidParticipationStudyException();
}
}

Copy link
Collaborator

Choose a reason for hiding this comment

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

checkStudyStatus보다 좀 더 의미 있는 이름은 없을까요???
현재는 스터디가 종료됐는지 확인하는데 checkStudyStatus라는 메서드 이름은 이 상황에 맞지 않은거 같아요

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

저도 isCloseStatus() 등등..이 부분에서 고민이 많았는데요..🤔
모집 종료인지 확인한다라는 의미에서 checkClosingRecruitment는 어떤가요??
우선 위의 메소드명으로 수정해보겠습니다!

Comment on lines 49 to 51
public static Participants createByMaxSizeAndOwnerId(final Integer maxSize, Long ownerId) {
return new Participants(1, maxSize, new HashSet<>(List.of(new Participant(ownerId))), ownerId);
}
Copy link
Collaborator

Choose a reason for hiding this comment

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

참여자에 방장은 넣지 않기로 하지 않았나요???

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

헉...수정하겠습ㄴ디ㅏ!

Comment on lines 62 to 74
protected void checkParticipating(Long memberId) {
if (isInvalidMemberSize() || isAlreadyParticipation(memberId)) {
throw new InvalidParticipationStudyException();
}
}

private boolean isInvalidMemberSize() {
return max != null && max <= size;
}

private boolean isAlreadyParticipation(final Long memberId) {
final Participant participant = new Participant(memberId);
return Objects.equals(memberId, ownerId) || participants.contains(participant);
Copy link
Collaborator

Choose a reason for hiding this comment

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

이부분을 participate 메서드 안에 넣어서 캡슐화하면 더 좋을 것 같아요...
현재는 Study에서 checkParticipating을 호출하는 것 처럼 보이는데 스터디에 참여하기 위해 체크하는 부분이 외부로 드러나서 캡슐화가 필요한 것 같습니다.

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

오 좋습니다!! 외부에 드러낼 필요가 없네요! 수정하였습니다!

Comment on lines 68 to 70
details.checkStudyStatus();
period.checkParticipatingPeriod();
participants.checkParticipating(memberId);
Copy link
Collaborator

Choose a reason for hiding this comment

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

각각의 Embeddable 객체에서 예외를 던지는게 아니라 상태만 확인하고 Study에서 예외를 던지는건 어떨까요??
check라는 이름이 어떤 상황일 때 예외를 던지는지에 대한 내용을 전혀 담고 있지 않기 때문에 조금 더 드러내는게 좋을 것 같습니다.
Study 클래스 하나만 보고 어떤 상황에서 사용자가 참여가능한지 드러나는게 가독성면에서 좋을 것 같아요

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

수정해보았습니다!! 확인 부탁드려요~_~

Comment on lines +44 to +52
private Study findStudyBy(final Long studyId) {
return studyRepository.findById(studyId)
.orElseThrow(StudyNotFoundException::new);
}

private Member findMemberBy(final Long githubId) {
return memberRepository.findByGithubId(githubId)
.orElseThrow(() -> new UnauthorizedException(String.format("%d의 githubId를 가진 사용자는 없습니다.", githubId)));
}
Copy link
Collaborator

Choose a reason for hiding this comment

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

이 부분은 굳이 메서드 추출하지 않아도 될 것 같습니다. 차라리 각 메서드에 드러나는게 우선은 좋아보여요...
중복된 로직이 많은 경우에 다시 한번 생각해보는게 좋아 보입니다.

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

현재는 중복되는 부분이 2곳 뿐이니 좋습니다!
그런데 개인적으로 3곳이상 중복 발생하면 이부분은 메소드로 추출해내도 괜찮은 것 같습니다.
findStudyBy(final Long studyId) 라는 네이밍에서 우리가 알 수 있어서..

import org.springframework.http.HttpStatus;
import org.springframework.jdbc.core.JdbcTemplate;

public class ParticipationStudyAcceptanceTest extends AcceptanceTest {
Copy link
Collaborator

Choose a reason for hiding this comment

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

현재 방장과 참여자를 따로 관리하고 있기 때문에 방장이 본인이 생성한 스터디에 참여시 400 반환하는 테스트도 추가해야될것 같습니다.

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

좋습니다! 추가해보도록 하겠습니다~_~

public ResponseEntity<Void> participateStudy(@AuthenticationPrincipal final Long githubId,
@PathVariable("study-id") final Long studyId
) {
studyService.participantStudy(githubId, studyId);
Copy link
Collaborator Author

Choose a reason for hiding this comment

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

participantStudy -> participateStudy

의견 : join, regist

return size;
}

protected void participate(final Participant participant) {
Copy link
Collaborator Author

Choose a reason for hiding this comment

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

default 접근 제어자가 좋을 것 같습니다.

}

protected void participate(final Participant participant) {
checkParticipating(participant.getMemberId());
Copy link
Collaborator Author

Choose a reason for hiding this comment

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

해당 메소드명으로 무엇을 check하는지 파악하기 힘들고, 추상화 수준도 맞지 않습니다.

@@ -0,0 +1,8 @@
package com.woowacourse.moamoa.study.service.exception;

public class InvalidParticipationStudyException extends RuntimeException {
Copy link
Collaborator Author

Choose a reason for hiding this comment

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

네이밍 변경

final boolean b = isOwner(memberId) || isParticipant(participant);
System.out.println("b = " + b);
return b;
return isOwner(memberId) || isParticipant(participant);
Copy link
Collaborator

Choose a reason for hiding this comment

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

👍

protected void participate(final Participant participant) {
checkParticipating(participant.getMemberId());

void participate(final Participant participant) {
Copy link
Collaborator

Choose a reason for hiding this comment

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

👍

Copy link
Collaborator

@sc0116 sc0116 left a comment

Choose a reason for hiding this comment

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

디우 피드백 반영 되게 빠르네요 이만 Approve할게요!

Comment on lines 67 to 74
public void participate(final Member member) {
final Long memberId = member.getId();
if (details.isCloseStatus() || period.isCloseEnrollment() || participants.isImpossibleParticipation(memberId)) {
throw new FailureParticipationException();
}

participants.participate(new Participant(memberId));
}
Copy link
Collaborator

Choose a reason for hiding this comment

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

memberId로 파라미터를 받는 것이 좋을 것 같습니다.

@tco0427 tco0427 merged commit d460942 into develop Jul 29, 2022
@tco0427 tco0427 deleted the feat/122-study-participation branch July 29, 2022 04:27
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
🖥 backend New backend feature 🚀 feature New feature or request
Projects
None yet
Development

Successfully merging this pull request may close these issues.

4 participants