Skip to content

1주차 금요일 그룹 1

CodingLuizy edited this page Jun 28, 2024 · 1 revision

김현종

💡 클래스의 책임이 무엇일까?
  1. 각각의 클래스가 어떤 책임을 가지고 있는가? 보드는 그저 piece를 가지고 보관하고 있는 클래스일 뿐이다! 보드를 가져다가 외부에서 보드의 정보를 통해 다른 기능을 구현하자. 이를 통해서 각종 BoardManager들이 탄생을 했고 board를 주입받아 그 board를 조작하게 됐습니다. 이는 Piece객체에서도 마찬가지의 고민이었습니다. 움직임 자체는 피스의 책임이 아닙니다. 따라서 피스는 규칙을 가지고 있고 외부의 이동상황에서 규칙에 해당하는 움직임인지를 판단해 가능여부를 리턴해 주는 방식으로 구현을 하게 됐습니다.
  2. 하지만 특수룰 고민이 부족했어요.. 후반부에 들어 특수룰이나 체스게임의 동작을 고려했을 때 지금의 구현으로는 힘들 것 같은 상황이 펼쳐졌습니다. 이번이야 리팩토링의 연습이 어느정도 목표기 때문에 큰 문제는 아니었지만 만약 이게 실제 개발을 하는 것이면 도메인 지식이 있었다면? 도메인 지식이 있다면 설계에서 부터 큰 도움이 됐을겁니다.
  3. 다른 사람들의 생각은 재밌다 코드리뷰를 할 때마다 느끼는데 참 사람마다 생각이 다릅니다. 그리고 그 때 마다 배울점이 많아요. 특히 기억에 남는건 규칙에 따라 움직임이 이루어지니 규칙을 Enum으로 관리했다는 아이디어는 특히 흥미로웠습니다. 뿐만 아니라 다른 분들의 의견들도 좋았던게 많습니다. 오늘도 성장했네요.

오민석

🔥 목표 : **다른 분들이 하는 이야기 알아듣기**
  • 코드 설명

    • 레이어드 아키텍쳐 처럼 Board는 DB만 담당! ChessGame은 서비스 로직만 담당!
    • Piece는 목적지를 주면 1. 빈 보드에서 목적지를 갈 수 있는지 2. 방향은 어디인지를 알려준다.
    • 방향을 알려주는 방식은 Direction에 대한 반복문을 한번 돌면서 목적지와 가장 가까워지는 방향을 반환한다 (맨해튼 거리)
    • 마지막으로 move 시에 목적지와 방향이 정의되면 Iteration이 자동으로 정의되므로 재귀로 짜면 모든 기물들이 한 함수로 끝낼 수 있게 된다!
  • 코드 리뷰 느낀점

    • 역시 다른 분들은 구조나 여러 고민들을 하면서 코드를 짜시는 것 같다. 좀 더 보완해서 현재 고민 중인 부분들을 어떻게 해결할 수 있을 지 공부해봐야 겠다.
    • abstract class, interface, enum 등에 대해 주말에 학습하고 코드를 다시 봐야겠다!
    • 나의 코드를 다른 분들한테 설명하는 것이 어렵다는 것을 알게 되었다. 오히려 글을 작성해 놓는 것이 더 맞는 것 같으니 지속적으로 문서화를 해놔야겠다.

이경민

💡 구현에 초점을 두고 리팩토링을 진행하자!

📣 본인 코드의 포인트가 있다면?

  • Board를 DB라고 생각했습니다! → 위치 정보가 키값이 되고 기물이 벨류로 활용하자! 이에 Map<Location, Piece>를 적용해서 Board를 구현했습니다!
  • Type Enum을 사용할때 내부 필드로 Class <? extends Piece>를 사용해 Piece 구분과 생성을 한번에 처리할 수 있도록 했습니다!
  • 체크메이트를 구현했지만 체크는 구현하지 못했어요..
    • 체크도 구현을 했지만 GUI에 표현하기에 시간이 부족해서 체크는 제외했습니다.
    • 왕의 이동 가능 위치 조회 → 반대편 말들의 이동 가능 기물 위치 조회 → 왕이 가상으로 이동했을 때 체크 상태가 되는지 모두 점검 → 이동이 불가능하다 = 체크메이트!!
    • 위의 로직으로 구현을 진행했습니다!
  • GUI 구현을 했습니다.
    • 기물 드래그를 하면 이동이 가능하고 드래그를 위해 클릭 할 시 이동 반경을 표현해줘요 :D

✍️ 프로젝트를 진행하면서 아쉬웠다 or 드는 생각!

  • 구현 관점에서 살펴봤을때는 도메인 Knowledge가 부족했다라는 아쉬움이 존재했습니다.
    • 프로젝트 진행 마지막 쯤에서야 체크에 대한 개념을 파악하고 서둘러 구현하게 된 점.. 등등..
  • 도메인에 대해서 좀 더 공부할 수 있었다면 더 좋은 결과가 나올 수 있지 않았을까?
    • 물론 이번 주 프로젝트의 목적이 다양한 리팩토링 경험과 구현에 대한 고민을 직접 해보면 좋을 것 같다! ← 이거인거 같긴 하지만 .. 그래도 스스로의 아쉬움이 남았습니다.
  • 앙파상을 구현하기 위해서는 어떻게 해야 할까에 대한 고민 → 모든 기물 이동에 대한 로그를 남겨두면 수월하게 구현이 가능하다!
  • 체크 메이트 로직이 너무 복잡하고 성능이 좋지 않은 부분 → 각 기물이 공격 가능한 위치에 대해서 따로 보관해두고 갱신한다면 더 좋지 않았을까…

김현욱

오늘의 발표 요약

1. 추상화, 관심사 분리를 중심적으로 클래스를 분리했습니다.
2. 상속받은 클래스들을 테스트하기 위해서 필수로 검증해야할 테스트 목록을 interface로 추출한 뒤, 해당 클래스의 테스트 클래스에서 상속받아 테스트 코드 구현을 강제하도록 하면 놓치는 실수를 줄일 수 있습니다.
3. 다형성을 이용해서 최대한 통일된 메서드를 사용하도록 구현했습니다.
4. DI구조를 이용하여 구체화한 클래스를 갈아끼우기 쉽게 설계하여 테스트코드 작성에 용이하게 만들었습니다.  
5. 그림을 그리며 설계하는거 매우 좋은방법입니다.

오늘의 코드 리뷰

- 역시 다른사람의 코드를 많이 보는게 최고입니다.

- 개발은 역시 서비스에 대한 도메인을 빡세게 공부한 뒤 진행해야 한다는것을 폰의 특수룰을 구현한 팀원들을 보고 다시금 느꼈습니다.

- var 키워드를 애용하는 구체적인 이유가 많은 import문이 생기는것을 방지한다는 이유가 있다는 의견이 있어서 한번 이용해보겠습니다.

- 폰의 특수 규칙 및 체스의 특수 규칙들을 따로 관리하는 코드를 보고 아이디어를 얻을 수 있었습니다.

소감

역시 다른사람 코드를 보는것은 매우 재밌습니다.

같은 요구사항을 여러가지 방법으로 구현하는 방법을 통해 내 아이디어에서 보강할점을 찾을 수 있어서 좋았습니다.

조희승

발표 요약

  • 마지막 차례라 비슷한 부분들은 넘기며, 이동 기능 구현 위주로 소개, 특이 사항인 check 구현 소개

소감

  • java 문법안에서 다양한 기법을 활용하신 분(enum을 클래스같이 메서드 작성)들이 있으셔서 새로웠습니다. 문법을 최대한 활용해서 독특하게 짜는게 다른 사람들이 보기에 좋은 코드 인가에 대한 약간에 의구심이 있습니다. 다만 각자가 사용한 방식에 대해 이유를 물었을 때 구체적인 이유를 말할 수 있는 걸 보고 그분들이 누군가와 같이 일 한다면 본인의 방식대로 구현을 하는걸 설득 할 수 있을거라 생각했습니다.
  • 특수 기능들 까지 끝까지 구현한 팀원들을 보고 의지가 대단하다 느꼈습니다.

박정제

💡 핵심 관심사 : 규칙적용
  • 모든 이동은 규칙에 따라 이동한다 (행마법, 캐슬링…)
  • 제일 오랫동안 집중적으로 구현할 부분이 규칙이동이라고 생각
  • 규칙을 enum 으로 정의하고 규착마다의 이동 방식을 구현하는 방법으로 구현

구현

기물

  • 기물을 일반화 시킨 Piece.class 구현
classDiagram
direction BT
class Bishop {
  + double DEFAULT_POINT
  + char WHITE_REPRESENTATION
  + char BLACK_REPRESENTATION
}
class King {
  + char BLACK_REPRESENTATION
  + double DEFAULT_POINT
  + char WHITE_REPRESENTATION
}
class Knight {
  + char WHITE_REPRESENTATION
  + char BLACK_REPRESENTATION
  + double DEFAULT_POINT
}
class Pawn {
  + char WHITE_REPRESENTATION
  + char BLACK_REPRESENTATION
  + double DEFAULT_POINT
}
class Piece {
  # List~Direction~ movableDirections
  # List~MoveRule~ specialMoveRules
  # Color color
  # char representation
  + int MAX_MOVE_DISTANCE
  - boolean isMoved
  # int moveDistance
}
class Queen {
  + char BLACK_REPRESENTATION
  + double DEFAULT_POINT
  + char WHITE_REPRESENTATION
}
class Rook {
  + char WHITE_REPRESENTATION
  + char BLACK_REPRESENTATION
  + double DEFAULT_POINT
}

Bishop  -->  Piece
King  -->  Piece
Knight  -->  Piece
Pawn  -->  Piece
Queen  -->  Piece
Rook  -->  Piece

Loading
  • 각 기물들은 각각의 특성들을 가지고 있다
    • 이동 방향과 이동 거리 : 행마법에 따른 움직임
    • 특수한 이동 규칙 : 폰의 이동, 캐슬링 등

이동규칙

  • 모든 기물의 이동은 규칙에 따라 이동한다
  • MoveRule enum class로 이동규칙을 정의하고 각 enum class에 이동방식과 이동을 구현했다.
  • chess/move/MoveRule.java
public enum MoveRule{
    Common {
        public void move(Board board, String source, String target) {}
        public Map<ChessPoint, MoveRule> getMovablePoints(Board board, ChessPoint source, Piece piece) {}
    },
    Castling {
        public void move(Board board, String source, String target) {}
        public Map<ChessPoint, MoveRule> getMovablePoints(Board board, ChessPoint kingPoint, Piece piece) {}

        @Override
        public boolean isAttackable() {return false;}

    },
    PawnMove {
        public void move(Board board, String source, String target) {}
        public Map<ChessPoint, MoveRule> getMovablePoints(Board board, ChessPoint source, Piece piece) {}
    },
    Promotion {
        public void move(Board board, String source, String target) {}
        public Map<ChessPoint, MoveRule> getMovablePoints(Board board, ChessPoint source, Piece piece) {}
    },
    None {
        public void move(Board board, String source, String target) {}
        public Map<ChessPoint, MoveRule> getMovablePoints(Board board, ChessPoint source, Piece piece) {}
    };

    public void adapt(Map<ChessPoint, MoveRule> map, Board board, ChessPoint source, Piece piece, boolean onlyAttackable) {
        if (onlyAttackable) {
            if (this.isAttackable()) {
                map.putAll(this.getMovablePoints(board, source, piece));
            }
        }
        else {
            map.putAll(this.getMovablePoints(board, source, piece));
        }
    }

    public abstract void move(Board board, String source, String target);

    public abstract Map<ChessPoint, MoveRule> getMovablePoints(Board board, ChessPoint source, Piece piece);

    public boolean isAttackable() {
        return true;
    }
}
  • 따라서, 각 기물에 적용되는 규칙만 알고 있으면 된다.

이동

  • 'Board' 클래스의 move 메소드를 통해 기물을 이동시킨다.
  • 출발 위치의 기물이 목적위치까지 이동할 수 있는 규칙을 찾아 이동시킨다.
  • chess/Board.java
public void move(String source, String target) {
    Piece piece = findPiece(source);
    MoveRule moveRule = piece.getMoveRule(this, ChessPoint.of(source), ChessPoint.of(target));
    moveRule.move(this, source, target);
}
  • 이동 가능한 위치인지 파악하기 위해서는 MoveRule을 적용한다
  • chess/piece/Piece.java
public Map<ChessPoint, MoveRule> getMovablePoints(ChessPoint source, Board board, boolean onlyAttackable) {
    // 기본 이동 규칙(행마법)
    Map<ChessPoint, MoveRule> moveablePoints = MoveRule.Common.getMovablePoints(board, source, this);
    // 특수 이동 규칙
    specialMoveRules.forEach(moveRule -> moveRule.adapt(moveablePoints, board, source, this, onlyAttackable));
    return moveablePoints;
}

👼 개인 활동을 기록합시다.

개인 활동 페이지

🧑‍🧑‍🧒‍🧒 그룹 활동을 기록합시다.

그룹 활동 페이지

🎤 미니 세미나

미니 세미나

🤔 기술 블로그 활동

기술 블로그 활동

📚 도서를 추천해주세요

추천 도서 목록

🎸 기타

기타 유용한 학습 링크

Clone this wiki locally