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

[1, 2단계 - 체스] 토리(천은정) 미션 제출합니다. #498

Merged
merged 60 commits into from
Mar 24, 2023

Conversation

ezzanzzan
Copy link
Member

안녕하세요 코즈 !
체스 미션을 함께 하게 된 토리입니다 ˙ᵕ˙

리팩토링 과정 중 궁금한 점을 아래에 함께 첨부합니다 ˙ᵕ˙
리뷰 잘 부탁드립니다 🙇‍♀️


  1. 이중 for문 대신 flatMap 사용
private List<Square> generateSquares() {
    List<Square> squares = new ArrayList<>();
    for (Rank rank:Rank.values()) {
        for (File file : File.values()) {
            squares.add(new Square(file, rank));
        }
    }
    return squares;
}
private List<Square> generateSquares() {
    return Arrays.stream(Rank.values())
            .flatMap(rank -> Arrays.stream(File.values())
                    .map(file -> new Square(file, rank)))
            .collect(Collectors.toList());
}

Squares를 생성할 때의 코드입니다.
stream 사용법에 익숙해지고 싶기도 했고, 이중 for문으로 인해 발생하는 2개 depth가 요구사항에 위배되어 flatMap을 통해 구현하게 되었는데 여기서 flatMap의 depth 2개로 봐야하는지를 여쭤보고 싶었습니다 !

저는 위의 첫 번째 코드와 두 번째 코드를 비교한다면, 이중 for문이 가독성이 더 좋다고 생각했습니다.
다만 이중 for문에서 depth를 줄이기 위해 메소드 분리를 하게 되면 flatMap이 더 가독성이 좋다고 생각해 현재 flatMap을 통해 코드를 구현하였는데 이 부분에 대한 코즈의 의견이 궁금합니다 🤔


  1. 인스턴스 변수를 바로 반환하는 메서드 네이밍에는 get이 없는 것에 대해 어떻게 생각하시나요?
private final int x;

File(final int x) {
    this.x = x;
}

public int x() {
    return x;
}

클래스에서 값을 반환받는 메소드들의 네이밍을 get~으로 통일해서 사용하고 있는데,
위 코드처럼 클래스의 인스턴스 변수를 바로 반환하는 메서드 네이밍에는 get 대신 인스턴스 필드의 네이밍을 그대로 사용하는 것에 대해 코즈의 의견이 궁금합니다 🤔

hyeonjerry and others added 30 commits March 14, 2023 15:24
Co-authored-by: ezzanzzan <eunzzann@gmail.com>
Co-authored-by: ezzanzzan <eunzzann@gmail.com>
Co-authored-by: ezzanzzan <eunzzann@gmail.com>
Co-authored-by: ezzanzzan <eunzzann@gmail.com>
Co-authored-by: ezzanzzan <eunzzann@gmail.com>
Co-authored-by: ezzanzzan <eunzzann@gmail.com>
Co-authored-by: ezzanzzan <eunzzann@gmail.com>
Co-authored-by: ezzanzzan <eunzzann@gmail.com>
Co-authored-by: ezzanzzan <eunzzann@gmail.com>
- Game 객체 제거
- Board 인스턴스 변수 자료형 변경
- Row 객체 제거
- Square piece 필드 제거

Co-authored-by: ezzanzzan <eunzzann@gmail.com>
Co-authored-by: ezzanzzan <eunzzann@gmail.com>
Co-authored-by: ezzanzzan <eunzzann@gmail.com>
Co-authored-by: ezzanzzan <eunzzann@gmail.com>
Co-authored-by: ezzanzzan <eunzzann@gmail.com>
Co-authored-by: ezzanzzan <eunzzann@gmail.com>
Co-authored-by: ezzanzzan <eunzzann@gmail.com>
Co-authored-by: ezzanzzan <eunzzann@gmail.com>
Co-authored-by: ezzanzzan <eunzzann@gmail.com>
Co-authored-by: ezzanzzan <eunzzann@gmail.com>
- 타겟 위치에 상대팀 말이 존재할 경우 이동 가능

Co-authored-by: ezzanzzan <eunzzann@gmail.com>
Co-authored-by: ezzanzzan <eunzzann@gmail.com>
Co-authored-by: ezzanzzan <eunzzann@gmail.com>
Co-authored-by: ezzanzzan <eunzzann@gmail.com>
Co-authored-by: ezzanzzan <eunzzann@gmail.com>
Co-authored-by: ezzanzzan <eunzzann@gmail.com>
Co-authored-by: ezzanzzan <eunzzann@gmail.com>
Co-authored-by: ezzanzzan <eunzzann@gmail.com>
Co-authored-by: ezzanzzan <eunzzann@gmail.com>
Co-authored-by: ezzanzzan <eunzzann@gmail.com>
Co-authored-by: ezzanzzan <eunzzann@gmail.com>
hyeonjerry and others added 8 commits March 16, 2023 15:12
Co-authored-by: ezzanzzan <eunzzann@gmail.com>
Co-authored-by: ezzanzzan <eunzzann@gmail.com>
Co-authored-by: ezzanzzan <eunzzann@gmail.com>
Co-authored-by: ezzanzzan <eunzzann@gmail.com>
Co-authored-by: ezzanzzan <eunzzann@gmail.com>
Co-authored-by: ezzanzzan <eunzzann@gmail.com>
Co-authored-by: ezzanzzan <eunzzann@gmail.com>
Copy link

@kouz95 kouz95 left a comment

Choose a reason for hiding this comment

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

안녕하세요 토리 :)
리뷰 확인해주세요


  1. for문과 flatMap 둘 다 괜찮다고 생각합니다 :)
  2. 같이 작업하는 사람과 의견이 맞춰질 수 있다면 상관 없다고 생각합니다. 토리가 생각하는 방식은 자바 14에서의 record 클래스에서 사용하고 있기도 합니다.

import java.util.List;

public class GameCommand {
private enum gameCommandIndex {
Copy link

Choose a reason for hiding this comment

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

Suggested change
private enum gameCommandIndex {
private enum GameCommandIndex {

}
}

private enum moveIndex {
Copy link

Choose a reason for hiding this comment

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

Suggested change
private enum moveIndex {
private enum MoveIndex {

클래스이기 때문에 대문자로 시작해야할 것 같아요.

Copy link
Member Author

Choose a reason for hiding this comment

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

자바 네이밍 규칙에 대해서 다시 한 번 정리하고 전체적으로 수정하였습니다 ! 🥺

}

private void validateMoveCommand(final String source, final String target) {
if (!source.matches(SQUARE_BOUND_REGULAR_EXPRESSION) && target.matches(SQUARE_BOUND_REGULAR_EXPRESSION)) {
Copy link

Choose a reason for hiding this comment

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

해당 로직은 도메인 로직으로 봐야하지 않을까요? 다른 view가 생긴다면 중복으로 적힐코드이지 않나요?

Copy link
Member Author

@ezzanzzan ezzanzzan Mar 21, 2023

Choose a reason for hiding this comment

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

1단계 미션을 구현 할 때 start, end 만을 체크하는 기능이었는데, 2단계 미션을 구현하며 여러 기능이 추가되었던 걸 생각하지 못하고 파일 위치를 확인하지 못한 것 같습니다. 도메인 패키지로 이동시켰습니다 !

src/main/java/chess/GameCommand.java Outdated Show resolved Hide resolved
try {
return new GameCommand(inputView.readGameCommand());
} catch (final IllegalArgumentException e) {
System.err.println("[ERROR] " + e.getMessage());
Copy link

Choose a reason for hiding this comment

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

위 문구는 체스 어플리케이션을 이용하는 사용자에게 노출하기 위한 문구일까요?
OutputView를 사용하지 않고 Controller에서 출력하는 이유가 있나요?

Copy link
Member Author

Choose a reason for hiding this comment

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

네! 체스 어플리케이션을 이용하는 사용자에게 보여주고 재입력을 받기 위한 메세지 입니다.
생각해보니 에러메시지를 출력하는 기능도 OutputView에 메서드로 만들어 볼 수 있겠네요 !!

}

private boolean isMovableToTargetFile(final int targetFile, final int fileWeight) {
return getFile() + fileWeight == targetFile;
Copy link

Choose a reason for hiding this comment

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

멤버변수에 직접 접근하는것이 아닌, getter를 사용하는 이유가 있나요?

Copy link
Member Author

Choose a reason for hiding this comment

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

public int getFile() {
    return file.getX();
}

public int getRank() {
    return rank.getY();
}
return file.getX() + fileWeight == targetFile;

멤버 변수에 직접접근하게 되면 File 객체 내부의 값을 빼와야 하는데, 이 기능을 하는 메서드가 있어서 getter를 사용하여 코드를 구현하게 되었습니다 !

import java.util.List;

public class King extends Piece {
private static final List<Move> possibleMoves = makePossibleMove();
Copy link

Choose a reason for hiding this comment

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

Suggested change
private static final List<Move> possibleMoves = makePossibleMove();
private static final List<Move> POSSIBLE_MOVES = makePossibleMove();

Comment on lines 17 to 23
public boolean isMovable(final Square source, final Square target, final Move move) {
throw new UnsupportedOperationException();
}

public boolean isMovable(final Square source, final Square target, final KnightMove move) {
throw new UnsupportedOperationException();
}
Copy link

Choose a reason for hiding this comment

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

KnightMove와 Move를 추상화하여 같은 타입으로 만들면, 추상메서드를 사용할 수 있을것 같습니다

Copy link
Member Author

Choose a reason for hiding this comment

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

KnightMove를 Move로 합치고 계산 로직을 변경하여 추상 메서드를 사용할 수 있도록 리팩토링 해보았습니다 !!

}

@Override
public boolean equals(final Object o) {
Copy link

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.

전체적인 코드에서 체스판 위의 말들을 체크할 때 Role과 Team을 사용해서 비교해주고 해당 역할에 맞는 기능을 수행하도록 구현하였는데 코멘트를 보고 equals 재정의가 된 기능을 사용한 부분을 다시 한 번 찾아보니 empty 객체를 비교할 때와, 테스트 코드에서만 사용되었다는 것을 확인했습니다.
equals를 통해 새로운 말을 생성해서 비교하는 것보다 piece에게 너 비어있는 말이니? 라고 물어보는 메서드를 추가하는 것이 좋아보여 isEmpty()라는 메서드로 비어있는 말을 체크하도록 리팩토링하였는데 의도하신 방향이 이것이 맞을까요 ?!

Copy link

Choose a reason for hiding this comment

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

동일성과 동등성에 대해 참고해보셨으면 좋겠습니다 :)
https://creampuffy.tistory.com/140
Piece 객체가 속성이 같으면 같다고 봐야할 모델일 수도, 객체의 레퍼런스로 판단하는게 더 적절한 모델일 수도 있을텐데, 어떤걸 의도하고 equals 메서드를 정의하신건지 궁금하여 질문드린 것이었어요.

Copy link
Member Author

Choose a reason for hiding this comment

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

동일성과 동등성에 대해 이해하고 다시 질문을 읽어보니 의도하신 부분을 이해할 수 있었습니다 🥲
저는 Piece 내부의 값이 변하기도 하고, 객체의 레퍼런스로 판단하는 것보다 값을 비교해서 판단하는것이 좋다고 생각했습니다 !

package chess.domain.piece;

public enum Role {
KING("K"),
Copy link

Choose a reason for hiding this comment

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

콘솔에 노출될 문구를 도메인이 갖고 있는것 같습니다. 추후 웹 view가 생기는 상황을 생각해보면, view가 도메인을 바라보고 어떻게 노출될지 결정하는 것이 확장성에 유리할 것 같아요

Copy link
Member Author

Choose a reason for hiding this comment

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

생각해보지 못했던 부분이었습니다 ㅠㅠ 오류 메시지 출력도 마찬가지였구요
좋은 코멘트 감사드립니다 🙇‍♀️

Role enum class에서 문구를 제거하고 view 패키지 안에 pieceMessage enum class를 생성하여 view에서 관리할 수 있도록 리팩토링해주었습니다 !!

Copy link

@kouz95 kouz95 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 File findFile(int fileIndex) {
if (!FILES.containsKey(fileIndex)) {
throw new FileCanNotFindException();
Copy link

Choose a reason for hiding this comment

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

현재 구조도 의존 방향을 생각해보면 domain -> exception -> 문구 의 구조가 되게 됩니다.
영어 버전을 지원하는 체스게임이 되어 영어 문구를 노출해야한다면 어떻게 해야할지 고민해보셨으면 좋겠습니다 :)


public void move(final Square source, final Square target) {
if (board.isNotMyTurn(source, turn) || board.isEmptyPiece(source)) {
throw new IllegalArgumentException("자신의 말만 이동할 수 있습니다.");
Copy link

Choose a reason for hiding this comment

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

리뷰 코멘트로 남겨드렸습니다 :)
다음 단계에서 적용해보시고 혹시 마땅한 방법이 떠오르지 않는다면 편하게 질문주세요

return EMPTY;
}

return Arrays.stream(Move.values())
Copy link

Choose a reason for hiding this comment

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

무조건 Map을 사용하는게 유리하다는 뜻은 아니었습니다. 토리가 생각하기에 가독성이 높아지거나, 딱히 성능적 이득을 볼 부분이 아니라고 판단이 된다면 순회도 좋습니다 :)

}

@Override
public boolean equals(final Object o) {
Copy link

Choose a reason for hiding this comment

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

동일성과 동등성에 대해 참고해보셨으면 좋겠습니다 :)
https://creampuffy.tistory.com/140
Piece 객체가 속성이 같으면 같다고 봐야할 모델일 수도, 객체의 레퍼런스로 판단하는게 더 적절한 모델일 수도 있을텐데, 어떤걸 의도하고 equals 메서드를 정의하신건지 궁금하여 질문드린 것이었어요.

@kouz95 kouz95 merged commit a3a1406 into woowacourse:ezzanzzan Mar 24, 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.

3 participants