목차
1. GitHub 저장소
2. 구현 기능 목록
3. 새로운 도전
4. 생각하기
5. 회고
1. GitHub 저장소
GitHub: https://github.com/yeon-06/java-chess/tree/step1
Pull Request: https://github.com/woowacourse/java-chess/pull/297
2. 구현 기능 목록
- 입력 명령어에 따른 여러 동작 (start, move, status, end)
- 체스판 초기화 (입력: start)
- 체스 말 이동 (입력: move)
- 체스 규칙에 따라 각 기물들 이동 가능
- pawn의 대각선 이동은 다른 팀의 말을 잡을 때만 가능
- pawn의 첫수(첫 시작)는 1칸 또는 2칸 이동 가능
- pawn은 팀의 색깔에 따라 이동 가능 방향이 다름
- check 상태인 경우 check 상태를 벗어날 수 있는 이동만 가능
- 체스 종료
- end 명령어 입력 (입력: end)
- checkmate 상황 발생 시 종료 가능
- 현재 점수 계산 (입력: status)
용어 정리
- check: 다음 턴에 킹을 잡을 수 있음
- checkmate: 체크에서 벗어날 수 없는 상황
3. 새로운 도전
3-1. 여러 방법으로 페어 프로그래밍 하기
페어 프로그래밍을 진행하며 시도했던 몇 가지 방법에 대해 정리한다.
Special thanks to Sudal
- 각자의 노트북에서 작업하기
- Mac / Windows 호환성 때문에, Code With Me의 버그 때문에 작업이 어려웠다.
- 기능을 하나씩 번갈아가며 구현하고 push / pull 을 받아가며 진행한다.
- 👍 장점
- 익숙한 작업 환경이라 개발 속도가 빠르다.
- 개발의 흐름이 끊기지 않는다.
- 👎 단점
- 드라이버 - 네비게이터 교대 타임이 일정하지 않다.
- 드라이버 - 네비게이터 교대 타임이 일정하지 않다.
- 작업 시간 정하기
- 지치고 나서야 쉬는 시간을 잠깐 갖다보니 어느 시점 이후로는 머리가 돌아가지 않았다.
- 👉 해결 방안
- 90분 작업 → 10분 쉬는 시간 같이 쉬는 시간에 강제성을 두니 효율이 올라갔다.
- 90분 작업 → 10분 쉬는 시간 같이 쉬는 시간에 강제성을 두니 효율이 올라갔다.
- 지치고 나서야 쉬는 시간을 잠깐 갖다보니 어느 시점 이후로는 머리가 돌아가지 않았다.
- 의견이 다른 경우
- 의견이 다른 경우 각자 코딩을 하고 서로의 의견을 절충했다.
- 👍 장점
- 내가 생각한대로 코드를 짜기 쉽다.
- 개발 속도가 더 빠르다.
- 👎
치명적인단점- 한 쪽의 로직이 채택된 경우 다른 쪽이 해당 로직에 대한 이해도가 떨어진다.
- 한 쪽의 로직이 채택된 경우 다른 쪽이 해당 로직에 대한 이해도가 떨어진다.
- 👉 해결 방안
- 코드 없이 말로만 설명하는 연습을 위해서라도 ‘각자 코딩’의 상황 자체를 피한다.
- 정말 불가피한 경우에만 코딩 후에 설명한다.
- 의견이 다른 경우 각자 코딩을 하고 서로의 의견을 절충했다.
- 서로를 파악할 시간
- 페어 시작할 때 미션에 대한 불안감이 크더라도 아이스 브레이킹 시간이 중요하다.
- 이미 잘 아는 페어라 생각하지 말고 서로 대화를 해보자.
- 설득은 근거와 함께
- 어떠한 의견을 제시할 때 ‘근거’는 매우 중요하다.
- 이러한 의견을 받아들이면 어떤 장단점이 있는지에 대해 설명할 수 있으면 좋다.
- 단축키를 모른다면 함께 찾아보기
- 페어가 모르는 단축키를 사용하면 바로바로 물어보자.
- 페어가 단축키를 물어보면 Mac ↔ Windows 다르더라도 한번 찾아보자.페어가 기뻐하면서 쓰는걸 보면 정말 뿌듯하다.
3-2. 상태 패턴
상태 패턴을 사용해보고 싶었는데 개념 이해가 잘 안됐다.
그냥 해보자!!!! 하고 코드를 다 짜고보니 이게 커맨드 패턴과도 관련되었다는 것을 알았다 😅
상태 패턴과 커맨트 패턴이 막 섞였다는 느낌...?
사실 아직 설계 잘 한건지 잘 모르겠다.
아무튼 적용해본걸 조금 설명해보자면 아래와 같은 구조로 되어있다.
public interface State {
boolean isEnd();
State run(List<String> inputs);
}
위와 같이 되어있어 isEnd는 End인 경우에만 true를 반환하고,
run에서는 각 기능에 해당하는 로직이 수행한다.
실제 사용할 때는 run() 메서드만 호출하게 하면 된다.
예외 처리나 세부 내용은 제외하고 돌아가는 주요 로직만 보면 아래와 같이 사용된다.
public void start() {
Board board = boardGenerator.create();
State state = new Ready(board); // 상태 시작
while (!state.isEnd()) { // 끝이 아닌 경우
state = state.run(InputView.inputCommand());
}
}
4. 생각하기
🙋♀️: 연로그(본인), 🙍♂️: 스티치(리뷰어), 👉: 깨달은 점
4-1. BoardGenerator
// AS-IS: BoardGenreator에서 Board에 저장될 목록 가져온 것을 이용
Board board = new Board();
board.init(boardGenerator.create());
// TO-BE: BoardGenreator에서 Board를 반환
Board board = boardGenerator.create();
👉 기존에는 Board에 저장될 Map을 BoardGenerator에서 가져온 다음, init()이라는 메서드에서 putAll()의 작업을 거쳤다. 하지만 BoardGenerator에서 바로 Board를 반환하면 이러한 작업이 필요 없다는 것을 알게 되었다.
4-2. View를 위한 메서드
각 체스말은 이름을 갖고 있고 흑팀이면 대문자, 백팀이면 소문자로 표현된다.
이는 팀이 갖고 있는 규칙이라고 생각하고 Team이라는 Enum에 다음과 같은 메서드를 생성했다.
public String convert(String value) {
if (this == BLACK) {
return value.toUpperCase();
}
return value.toLowerCase();
}
🙍♂️ View만을 위한 코드가 관리되고 있는 것 같아요!!
👉 대소문자 구분해서 '출력'하는 것은 View의 역할이라고 판단, 해당 메서드는 View로 이동하였음
4-3. Row, Column 이름에 대해
🙍♂️ 체스 도메인에서 사용되는 이름을 써보는 것은 어떨까요?
🙋♀️ 요 부분에 대해서는 저도 고민하던 사항인데요ㅠ_ㅠ
처음에 Rank를 봤을 때 이게 검정팀 1위, 하양팀 2위 이런 식의 랭크인지 오히려 혼란이 왔습니다.
마찬가지로 File을 봤을 때 파일을 읽어 들여서 뭔가를 사용하는건가?? 라는 식의 혼란이 왔고요
체스 용어는 아니지만 누구나 직관적으로 이해할 수 있는 이름(row, column)을 채택했는데 이러한 관점에 대해서는 어떻게 생각하시나요?
🙍♂️ 연로그의 생각도 충분히 타당한 생각이라고 생각합니다 :) (생각이 두 번 나오니깐 뭔가 문장이 어색하네요 ㅎㅎㅎ)
만약 저의 생각을 물어보신다면 전 코드는 해결하고자 하는 문제를 풀어내는 도구라고 생각해요!! 이번에 연로그가 풀려고 하는 문제는 체스입니다. 즉 체스 도메인을 코드로 풀어내는 작업을 하는 중이죠!! 그렇다면 이 코드는 누구를 위한 코드일까요??
체스라는 도메인을 사용하지 않지만 코드를 만들어내는 우리를 위한 코드일까요, 아니면 체스라는 도메인을 풀어내고 싶어하는 사람을 위한 코드일까요? 저는 후자가 아닐까 생각합니다.
랭크와 파일은 체스라는 도메인을 사용하지 않는 우리에게는 어색한 표현이라고 보지만, 체스 도메인을 사용하는 사람에게는 되려 행, 열이라는 용어보다 더 정확하고 명확한 용어가 아닐까요? 블랙잭에서 한장을 더 받는 행위를 그냥 '드로우'가 아니라 '힛'이라는 용어를 사용하는 것 처럼요!!!
그런 관점에서 저는 코드는 도메인을 그대로 표현할 수 있어야 한다고 생각해요!! 누군가 체스를 구현한 코드를 보면서 '체스에서 사용한 파일이 어디에 있지?'하고 찾을 때 찾을 수 있도록요!!
저는 이러한 생각을 가지고 코드를 짜려고 노력하는 것 같아요!! 연로그의 생각이 잘못되었다는 것은 절대 아닙니다! 그리고 그 방법이 틀린것도 절대 아니구요!! 단지 저의 입장에서 왜 이러한 피드백을 드렸을까? 에 대한 답변이 필요할 것 같아서 제 생각을 적어봤어요 :) 한번 참고 부탁드릴게요 ㅎㅅㅎ
4-4. 정확한 이름 짓기
calculate가 너무 편해서 남발하고 있었다. 😅
아래와 같은 메서드를 보고 스티치가 피드백 주셨다.
public int calculateIndex(Row row) {
return row.index - this.index;
}
🙍♂️ calculate라는 메서드 명이 빼기를 한다는 의미를 잘 담아낼 수 있을까요?? 보다 적절한 메서드 명을 지어보면 좋을 것 같아요!!
👉 이에 동의하고 calculateDifference()로 변경
5. 회고
머지.. 당해버렸다.
블랙잭까지는 그래도 아쉬운 점은 많았어도 당했다 까지는 아니라고 생각했는데..😢 (과거의 저와 합의하지 않고 작성한 글입니다.) 아직 고칠 점이 많고 찝찝한 점도 많다. 특히나 상태 패턴에 대한 고찰이 너무너무 어렵다. 게더에서 많은 의견을 주고 받았는데 내가 내린 결론은 아래와 같다.
현재까지는 콘솔 게임으로만 적용한다는 가정 하에 개발을 했기 때문에 상태 패턴을 적용했다.
- 상태와 뷰를 분리하기 위해 불필요한 메서드가 계속 늘어남
- 파라미터로 BiConsumer 등을 넘길 수 있지만 이를 이용하는 경우 View와 완전히 분리된 것이 아니라고 생각
(https://yeonyeon.tistory.com/209의 4-4 항목 참고) - 현재는 특정 조건(end 입력)이 나타날 때까지 계속 request를 받을 수 있음
하지만 웹의 경우에는 request를 한번 받으면 한번의 response가 무조건 보내줘야 함
위와 같은 사유로 현재 사용한 상태 패턴을 유지하며 웹으로 전환하면 득보다 실이 많다고 판단했다.
ConsoleGame을 삭제하면서 Controller도 만들고 대규모 공사를 진행할 예정이다.
PR 제출 쯤엔 스티치가 깜짝 놀랄지도...? 미리.. 죄송합니다 ^^....
여태까지는 자바의 어떠한 개념이나 간단한 수준의 디자인 패턴을 적용하는 수준이었는데..
요번 미션에서는 '설계의 중요성'을 깨닫는 것 같다 어려웡ㅠ.ㅠ
'Memo > 우테코 4기' 카테고리의 다른 글
[우테코] 레벨1 인터뷰 (2) | 2022.04.24 |
---|---|
[우테코] 체스 미션 4~5 단계 학습 로그 (6) | 2022.04.12 |
[우테코] 블랙잭 미션 2단계 학습 로그 (2) | 2022.03.20 |
[우테코] 블랙잭 미션 1단계 학습 로그 (0) | 2022.03.15 |
[우테코] 로또 미션 2단계 학습 로그 (0) | 2022.03.05 |