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

Feat(#95): 캐릭터 생성 #101

Merged
merged 22 commits into from
Feb 17, 2025
Merged

Feat(#95): 캐릭터 생성 #101

merged 22 commits into from
Feb 17, 2025

Conversation

kimyu0218
Copy link
Collaborator

@kimyu0218 kimyu0218 commented Feb 16, 2025

작업 개요

(캐릭터 생성 api 작업 중입니다. draft로 올려달라고 하셔서 아직 작업 중입니다)

  • SurveyService에서 캐릭터 생성 이벤트 호출
    • 온보딩 캐릭터 생성 - 번들 정보를 못 찾아서 FIXME 주석만 작성해놓았습니다.
  • ValueCharacter에 장점, 단점 등 필드 추가
  • 진행중인 캐릭터도 조회할 수 있도록 수정
  • 머지 전에 ddl 수정
  • N번째 구현 및 리팩토링
    • 아직 구현하지 않았지만 매번 숫자 기반으로 변환하는 것보다 db에 넣어주는 게 맞다고 생각해서 db에 넣어주고 있습니다
    • 캐릭터 목록 조회에서 아직 만들어지지 않은 설문 번들도 보여야 한다는 요구사항이 있어 한 번 정도는 직접 변환 작업이 필요하기 때문에 db에 숫자로 저장할지 다시 고민해봐야 할 것 같습니다.

수정해야 하는 부분은 TODOFIXME를 작성해뒀습니다.

작업 사항

  • one to one 관계에 있던 character_value_report 제거 후, character_recordvalue_report one to many 관계로 연결
  • Characters 객체를 이용하여 캐릭터와 관련된 엔티티 생성
    • CharacterRecord & ValueReport
  • KeywordScores 객체가 survey 리스트를 받아 설문 번들의 설문의 모든 키워드 점수 리스트 생성

고민한 점들(필수 X)

  • CharacterRecord 저장 시 ValueReport도 저장되도록 persist 걸어줬습니다!
  • 민혁님께서 전달해주신 로직은 아직 다른 작업 하느라 검토하지 못했습니다. 검토 받으면서 수정하겠습니다..!
  • 첫번째, 두번째 적용하려고 하는데 어떤 식으로 적용하시려고 했는지 여쭤봐도 될까요? 숫자가 커지면 한글이 꽤 길어질 것 같아서요

Copy link

github-actions bot commented Feb 16, 2025

Test Results

104 tests   102 ✅  4s ⏱️
 69 suites    2 💤
 69 files      0 ❌

Results for commit 3108ac1.

♻️ This comment has been updated with latest results.

Comment on lines +45 to +55
@Override
public boolean equals(Object o) {
if (this == o) {
return true;
}
if (o == null || getClass() != o.getClass()) {
return false;
}
ValueReport that = (ValueReport) o;
return keyword == that.keyword && Objects.equals(percentage, that.percentage);
}
Copy link
Member

Choose a reason for hiding this comment

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

entity 객체 동일성을 키워드랑 퍼센티지로 계산하는 이유가 무엇인가요? 보통 entity는 식별자를 통해 객체 동일성을 판단해서 여쭤봅니다. 만약 이 비교가 필요한 로직이 있다면 VO를 따로 만드는 게 좋을 것 같습니다.

Copy link
Member

Choose a reason for hiding this comment

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

저도 Entity에 EqualsAndHashcode를 재정의할 것이라면 Id와 유니크한 필드만 재정의해야된다고 생각합니다 !

@kimyu0218 kimyu0218 linked an issue Feb 16, 2025 that may be closed by this pull request
@kimyu0218 kimyu0218 linked an issue Feb 16, 2025 that may be closed by this pull request
2 tasks
@kimyu0218 kimyu0218 force-pushed the feature/#95-캐릭터-생성 branch from e4bc5a4 to 85a1eaa Compare February 16, 2025 14:44
Copy link
Member

@NaMinhyeok NaMinhyeok 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 52 to 53
.startDate(bundle.getCreatedAt().toLocalDate())
.endDate(LocalDate.now())
Copy link
Member

Choose a reason for hiding this comment

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

해당 두 부분은 번들내부의 제출 이력에서 submittedAt을 꺼내서 사용해야될 것 같아요 !!

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 +45 to +55
@Override
public boolean equals(Object o) {
if (this == o) {
return true;
}
if (o == null || getClass() != o.getClass()) {
return false;
}
ValueReport that = (ValueReport) o;
return keyword == that.keyword && Objects.equals(percentage, that.percentage);
}
Copy link
Member

Choose a reason for hiding this comment

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

저도 Entity에 EqualsAndHashcode를 재정의할 것이라면 Id와 유니크한 필드만 재정의해야된다고 생각합니다 !

Copy link
Collaborator Author

@kimyu0218 kimyu0218 left a comment

Choose a reason for hiding this comment

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

이어서 작업하실 때 도움이 될까 하여 코멘트 남겼습니다. pr 본문에 아직 구현한 부분, 구현하지 않은 부분 표시해두었습니다.

다른 업무로 바쁘시다면 리뷰만 부탁드립니다..! 퇴근하고 작업해볼게요

Comment on lines 116 to 132
@EventListener
@Transactional(propagation = Propagation.MANDATORY)
public void createCharacter(final CreateCharacterEvent event) {
final Characters characters =
Characters.builder()
.member(event.member())
.bundle(event.bundle())
.scores(event.scores())
.submissions(event.submissions())
.valueCharacters(valueCharacters)
.build();
characterRecordRepository.save(characters.provideCharacterRecord());

final CharacterValueReport report =
characterValueReportRepository
.findByCharacterIdAndDeletedAtIsNullWithCharacterAndValueReports(command.characterId())
.orElseThrow(() -> CustomException.CHARACTER_VALUE_REPORT_NOT_FOUND);
return CharacterValueReportResponse.of(report.getValueReports());
log.info(
"Handled CreateCharacterEvent for memberId {} and bundleId {}",
event.member().getId(),
event.bundle().getId());
Copy link
Collaborator Author

Choose a reason for hiding this comment

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

서비스 메서드로 처리 중인데 이벤트 핸들러 객체를 사용하는 게 좋을지 고민입니다.

import lombok.Builder;

@Builder
public record SimpleCharacterResponse(
Copy link
Collaborator Author

Choose a reason for hiding this comment

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

  • Simple이 붙은 게 캐릭터 목록 조회에 사용되는 dto라고 보시면 될 것 같습니다.
  • 완성되지 않는 캐릭터도 보여주기 위해 isCompleted가 추가되었습니다.

import java.util.stream.Collectors;
import org.nexters.jaknaesocore.domain.character.model.CharacterRecord;

public class SimpleCharacterResponses {
Copy link
Collaborator Author

Choose a reason for hiding this comment

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

내 캐릭터 목록과 가장 최근 번들을 넘기면

  • 캐릭터 목록은 characterId가 null 이 아니고, isCompletedtrue인 dto가 생성됩니다.
  • 최근 번들은 characterId가 null이고 isCompletedfalse로 설정됩니다.


private SimpleCharacterResponse toIncompleteResponse(final Long bundleId) {
return SimpleCharacterResponse.builder()
.characterNo("TODO")
Copy link
Collaborator Author

Choose a reason for hiding this comment

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

N번째로 수정해야 합니다

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

@pythonstrup 여기 누락된 것 같아요..! 주석으로 적어놓을 걸 그랬네요 😅

Comment on lines 52 to 53
.startDate(bundle.getCreatedAt().toLocalDate())
.endDate(LocalDate.now())
Copy link
Collaborator Author

Choose a reason for hiding this comment

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

아...! 번들 생성은 미리 해놓는 거였군요.. 😂

import org.nexters.jaknaesocore.domain.survey.model.SurveySubmission;

@RequiredArgsConstructor(access = AccessLevel.PRIVATE)
public class Characters {
Copy link
Collaborator Author

Choose a reason for hiding this comment

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

이 부분이 말씀하신 CharacterProvider입니다.

  • 처음엔 이렇게 작성했다가 여기서 ValueReport도 생성되는 게 이상해서.이름을 변경했습니다.
  • 근데 생각해보니 Character와 완벽하게 일치하는 엔티티가 없어서 CharacterProvider로 해도 문제 없을 것 같네요 😅

Comment on lines 33 to 38
final Long characterNo,
final Member member,
final SurveyBundle bundle,
final List<KeywordScore> scores,
final List<SurveySubmission> submissions,
final Map<Keyword, ValueCharacter> valueCharacters) {
Copy link
Collaborator Author

Choose a reason for hiding this comment

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

캐릭터 생성에 필요한 파라미터입니다.

  • scores: 번들 내부 점수 리스트
  • submissions: 회원의 설문 제출 이력
  • valueCharacters: 캐릭터 목록

Comment on lines 42 to 48
@PostConstruct
void setUp() {
valueCharacters =
valueCharacterRepository.findAll().stream()
.collect(
Collectors.toMap(ValueCharacter::getKeyword, valueCharacter -> valueCharacter));
}
Copy link
Collaborator Author

Choose a reason for hiding this comment

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

캐릭터가 7개 뿐이고, 생성할 때마다 키워드 기준으로 조회하기 보다 메모리에 저장해놓는 게 좋을 것 같아 이런 식으로 불러오도록 구현했습니다. 더 좋은 방법이 있으시다면 조언 부탁드립니다.

이 방법 안 좋은 것 같네요 😂 데이터베이스 내용이 변경되어도 다시 서버 띄우지 않으면 그 전까진 바뀐 내용을 못 보겠네요..

Comment on lines 208 to 209
// FIXME: 확인 후 주석 제거 필요 (온보딩 번들 전달)
// createCharacter(member, null, submissions);
Copy link
Collaborator Author

Choose a reason for hiding this comment

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

온보딩 번들을 찾아서 전달해야 합니다. 온보딩 설문을 찾아 번들로 접근해야 하는 건가요??

@pythonstrup pythonstrup force-pushed the feature/#95-캐릭터-생성 branch from 30ebe6e to 7e58e39 Compare February 17, 2025 12:08
@pythonstrup pythonstrup force-pushed the feature/#95-캐릭터-생성 branch from 7e58e39 to 32f9496 Compare February 17, 2025 12:12
Copy link
Collaborator Author

@kimyu0218 kimyu0218 left a comment

Choose a reason for hiding this comment

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

수고하셨습니다!! 👏
dto 부분만 확인해주실 수 있을까요...!

Comment on lines +119 to +121
this.valueCharacter = valueCharacter;
this.startDate = submissions.getFirst().getSubmittedAt().toLocalDate();
this.endDate = submissions.getLast().getSubmittedAt().toLocalDate();
Copy link
Collaborator Author

Choose a reason for hiding this comment

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

수정 감사합니다 👍

.endDate(it.getEndDate())
.build())
.findLatestCompletedCharacter(memberId)
.map(CharacterResponse::of)
Copy link
Collaborator Author

Choose a reason for hiding this comment

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

엄청 깔끔해졌네요 👍

+) 이건 제가 잘못 사용하고 있나 해서 빌더 쓰자고 얘기 했던 것 같은데 지양하자는 거였나요?!

Copy link
Member

Choose a reason for hiding this comment

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

저번에 얘기했을 때, 빌더 패턴은 정적 팩토리 메소드 안에서 사용하자고 알아 들었는데 아니었나요..?
@NaMinhyeok


private SimpleCharacterResponse toIncompleteResponse(final Long bundleId) {
return SimpleCharacterResponse.builder()
.characterNo("TODO")
Copy link
Collaborator Author

Choose a reason for hiding this comment

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

@pythonstrup 여기 누락된 것 같아요..! 주석으로 적어놓을 걸 그랬네요 😅

.getSurveyBundle();
final KeywordScores scores =
KeywordScores.of(submissions.stream().map(SurveySubmission::getSurvey).toList());
characterService.createFirstCharacter(
Copy link
Collaborator Author

Choose a reason for hiding this comment

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

현업에서 서비스에서 다른 서비스를 의존하기도 하나요?? 잘 몰라서 여쭤봅니다

Copy link
Member

@pythonstrup pythonstrup Feb 17, 2025

Choose a reason for hiding this comment

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

넵 있습니다. 다만 팀의 컨벤션에 따라 정책이 다를 거라는 생각이 드네요. 서비스가 서비스를 의존하게 되면 순환 참조가 발생할 수도 있어서요. 따라서 저희 팀의 경우 아래 원칙을 지키고 있습니다.

  • implementation layer의 service는 다른 service를 의존하지 않는다.
  • facade service는 다른 service를 의존할 수 있다.
  • 불가피한 경우를 제외하고 도메인 의존성의 방향이 한 방향으로 흐르게 만든다.

@pythonstrup pythonstrup marked this pull request as ready for review February 17, 2025 12:14
@pythonstrup pythonstrup merged commit c82ad88 into main Feb 17, 2025
2 checks passed
@pythonstrup pythonstrup deleted the feature/#95-캐릭터-생성 branch February 17, 2025 12:44
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.

feat: 캐릭터 생성
3 participants