💋 코드 저장소
이건 우테코 리뷰어에게 받은 리뷰의 PR이고
이건 다른 크루들에게 받은 리뷰 PR이다.
💋 처음 해보는 3인 페어
우테코 인원이 홀수인지 꼭 한 팀은 3인 페어를 시킨다. 먼가 다들 3인 페어가 특이해서 그런건지 아니면 사람 많으면 뱃사공 산 이슈 때문인지 약간 기피하는 경향이 있었는데, 암튼 나는 그냥 삼인페어에 말려들어갔다.
근데 난 오히려 좋았다. 사실 나는 페어랑 하루종일 말하는게 너무 힘든데, 두 페어가 이야기할 때 조금씩 쉴 수도 있고, 또 사람이 많다보니 좀 더 활기찬 분위기가 있어서 좋았다.
페어 둘 다 나보다 굉장히 설계에 대한 고민을 많이 하는 스타일이었는데, 그래서인지 되게 많이 배웠다. 한 친구(우르)는 설계에 굉장히 진심이어서 화이트보드에 막 적어 나가는데, 뭔가 생각하는 방식에 대해서 좀 배운 것 같다.
첫 날은 이렇게 설계에 대한 이야기만 굉장히 오래 했는데, 너무 완벽하게 하려고 처음에 너무 열을 낸 것 같다. 결과적으로 처음에 한 설계를 많이 고치게 되었고, 네오가 기한을 늘려주지 않았다면 기한 안에 다 구현하지도 못했다.
💋 TDD 감잡기 15%
TDD의 시작을 어떻게 해야 할까에 대해서 지난 미션까지는 고민이 많았다. 나는 요구사항을 읽고 가장 작은 단위를 뽑아내질 때도 있고 아닐 때도 있다. 랜덤임. 근데 항상 사람이니깐 크게 크게 어떤 요구를 해야 할 지에 대해서는 알고 있다. 저렇게 큰 요구(왼쪽)부터 점점 작은 단위(오른쪽)까지 폭포 떨어지듯 내려오고, 이제 더 작은 친구에게 요구할 수 없겠다 싶을 때까지 만들면, 그 오른쪽 끝부터 구현을 시작하는게 TDD의 정신일까..?
TDD를 하면서 또 고민이었던 것이, 작은 단위는 큰 단위 안에 들어가게 된다. 그러면 작은 단위에 대한 테스트를 완벽하게 했다면 중복되는 부분에 대해서는 큰 단위에서 테스트하지 않아도 될까? 에 대한 답은 지금은 하지 않아도 된다이다.
또 설계가 바뀌면 특히나 작은 단위의 메서드 시그니처가 바뀌면 갑자기 불쾌한 빨간 글씨가 뜨면서 26 problems 하면 갑자기 머리가 어지러워지면서 집에 가고싶어질 때가 있다. 이런 경우에는 어떻게 해야할까? 그냥 성실하게 고쳐야할까?
💋 조금의 반성
우리 팀이 왜 처음 정해진 기한 안에 못했을까 생각을 해봤다. 설계한 내용에 대해 어떻게 구현될 지 상상할 수 있는 정도에 비해 설계에 너무 많은 고민을 했기 때문이라고 생각하고 있다. 물론 나 혼자만의 생각이라서 내 페어는 어떻게 생각할 지 모르겠다.
조금만 반성을 더 해보자면, 나는 아직 저렇게 추상화를 한 다음에 끝까지 어떻게 구현이 될 지 상상하는 능력이 부족하다. 이만큼 복잡한 프로그램은 처음 만들어봐서 그런 것 같고, 이전의 레벨만큼은 이제 꽤나 상상이 된다. 이 능력은 좀 복잡한 것을 더 많이 만들다 보면 길러질 것 같은데, 암튼 앞으로는 그래서 적당히 설계 단계를 끊고 시작해보는 용기(?)도 필요할 것 같다. 설계는 중간에 바뀔 수 있는데 첫날 설계에 너무 많은 시간을 쏟다보니 페어 세 명 다 조금 맘이 급해져서, 후에 설계에 문제가 있음을 알게 된 후에도 이런걸 보상심리라고 하나..? 시간을 오래 쏟은 만큼 페어 세명이서 이제 절대로 설계로 태클 걸지 말고 우리는 이걸로 고정이다! 절대 바꾸지 말자 고 해섴ㅋㅋ 안좋은 설계를 오래 유지한 것이 좀 아쉽다.
절대 바꿀 수 없는 설계는 없다. (남이 만들어 놓은거면 못바꿀라나?)
암튼 그리고 설계와 구현을 적절히 조화롭게 하는 것도 길러야겠다.
💋 로직이 너무 복잡해서 힘들었다.
일단 난 체스를 해본 적이 없다.. 그래서 도메인에 대한 이해도 한 2시간 정도 걸렸던 것 같다.
근데 오히려 하나도 모르고 복잡하니깐, 이전에 했던 것보다 요구사항을 꼼꼼하게 생각하게 되어서 나중에 가서 혼동은 적었던 것 같기도..?
첫날은 그래서 가는 길에 누가 있나에 대해 생각해보지 못했고, 단순히 체스말에게 나 여기 갈 수 있음? 물어보면 체스판이 텅텅 비었다는 가정에서 ㅇ/ㄴ만 반환하도록 하는 설계를 했다. 그리고 나서 여러 칸을 이동할 수 있는 Queen, Bishop, Rook 이런 것에 대해 생각해보니 사이에 다른 애가 있다면 못간다는것..? 그래서 열심히 설계를 고쳤다... 결국에 ㅇ/ㄴ을 반환하지 않고, 이동 경로의 살펴봐야 하는 모든 Position을 반환하는 객체로 Path를 반환했다.
Pawn을 만드는게 진짜 너무 힘들었ㄷr... 난 알고리즘 요런거 잘 안해봤었는데, 그러니깐 약간 복잡한 규칙이 얽혀 나오니 약간 머리가 아팠다. 물론 잘 분기를 하면 된다. if 인덴트가 막 5칸 넘어가게 하면 된다. 그치만 설계도 객체 지향적으로 잘 하고 싶고 책임도 곧바로 나누고 싶다보니, 생각이 잘 안될 때가 있었다.
무엇보다 시간에 쫓겨서 TDD를 제대로 하지 못한 것 같다. 사실 실패하는 테스트를 적은 후에 제일 빠르게 성공할 수 있게 죽 밥이 되든 만들었어야 했는데, 혼자서도 고민이 많은데 이번 페어가 3인이었기 때문에 더 의견이 모아지기가 쉽지 않았다.
암튼 제출을 잘 했다.
기억에 남던 순간이, 1단계를 마치고 우르가 화장실 간 사이에 내가 OutputView를 만들겠다고 하고, 바로 딱 만들어서 출력했는데 한방에 잘 되었을 때 그 희열을 못 잊음. 그래서 이번 썸네일임
💋 그래도 테스트코드가 모자랐다고..?
분기를 엄청나게 없애고 신나게 PR 보냇는데 또 폰이 말썽을 부렸다. 하 분명히 테스트코드를 잘 짰다고 생각했는데도 놓치는 케이스가 있었다. 종이에 더 더 열심히 적어봐야겠다. 이상하게 모니터를 보면 생각이 다채롭게 안될 때가 있는 것 같다. 공책을 잘 활용하는 중...
@DisplayName("초기 위치가 아니면 2칸 이동할 수 없다.")
@Test
void test_searchPathTo5() {
Pawn pawn = new Pawn(Color.WHITE);
assertThatThrownBy(() ->
pawn.searchPathTo(new Position(2, 4), new Position(2, 6), Optional.empty()))
.isInstanceOf(IllegalStateException.class);
}
private Path searchPathToEmptyPosition(final Position from, final Position to, final Movement movement) {
if (movement != CAN_MOVE_EMPTY_DESTINATION.get(color)) {
throw new IllegalStateException("움직일 수 있는 방향이 아님!");
}
if (isMoveOneStep(from, to)) {
return new Path();
}
if (isInInitialPosition(from) && isMoveTwoSteps(from, to)) {
final Position wayPoint = from.moveBy(CAN_MOVE_EMPTY_DESTINATION.get(color));
return new Path(wayPoint);
}
throw new IllegalStateException("움직일 수 있는 방법이 아님!");
}
어쩔 때 보면, 객체를 막 찢어 분리하는 것보다도 그냥 잘 지은 분리된 메서드가 진짜 좋을 때도 있는 것 같다... 흠 정말 폰을 어떻게 고쳐야 할지 아직도 너무 고민이다...
💋 파라미터로 Optional을 받는 것은 안티패턴이다! 설득하지 못함 ㅠㅠ
Board로부터 가고자 하는 자리에 다른 체스말이 있는지 받는 과정에서, 만약에 찾지 못한다면 null의 형태로 반환하는 일이 생길 수 있다. 그래서 우리 3인 페어는 약 세 가지의 의견이 있었다.
1. Piece로 받고, 먼저 null에 대한 확인을 한다.
2. Optional<Piece> 타입으로 받는다.
3. Piece로 받고, null인 체스말에 대해서는 Piece를 상속한 EmptyPiece를 생성한다.
나는 3으로 하자고 했지만, 다른 페어들이 2를 좋아해서 그렇게 갔다. Optional을 파라미터로 쓰는 것이 맘에 들지 않았지만, 이유를 제대로 말하지 못하겠어서 흑흑.. 그런데 리뷰어가 이것을 안티패턴이라고 이야기해주었다.
왜 안티패턴이냐! Optional의 취지에 맞지 않지만, 빈 Optional을 Optional.empty()가 아닌 Optional.of(null)로 했을 때, 파라미터를 처리하는 쪽에서 Optional.isEmpty()를 호출했을 때에 Optional.of(null)가 잡히지 않는다는 문제점이 있다. 그래서 항상 신경을 더 써줘야 하기 때문에 Optional은 반환 타입으로만 쓰는 것이 좋다고 한다.
이제까지 Optional을 잘 사용해오지 않아서, 어떻게 잘 써야하는지 잘 알지 못했는데 오히려 한 번 크게 안티패턴 당하고 나니 앞으로 좀 더 잘 쓸 수 있을 것 같다. 또 누군가가 나에게 Optional을 파라미터로 쓰자고 제안한다면 앞으로는 잘 설득할 수 있겠지...? 그치만 이것에 대한 죄로 약 40개의 메서드를 수정해야 할 것 같다...ㅎㅎㅎㅎㅎㅎㅎㅎㅎ 힘내자 깃짱
https://yeonyeon.tistory.com/224
💋 도메인의 예외는 어디까지 처리해주는 것이 좋을까?
정말로, 발생 가능성이 있다면 모두 처리해줘야 하는걸까?
그럼 List를 쓸 때에도 항상 저렇게 생각을 하면서 쓰는 사람이 있을까? 그러면 무서워서 메서드 분리를 못할 것 같다. 어떻게 쓰는 것이 현명할까나
💋 잘 안다고 생각했던 람다와 스트림 아직도 잘 몰루
또 같은 주에 람다와 스트림 테코톡 발표가 있어서 정말정말 힘들었는데, 덕분에 스트림 공부를 진짜 많이 했다. 근데...! 아직도 잘 모르는 저 거대한 Collectors 클래스.. 잘 공부하면 여러모로 활용하기 진짜 좋을 것 같다. 휴 아무래도 모던 자바 인 액션이던가 그거 좀 잘 읽어봐야겠다. 근데 이러고 JAVA8보다 아랫버전 쓰는데로 취업하면 어캄? 억울해서 잠 못잘듯
함수형 프로그래밍의 개념이 헷갈리는 때가 많은데 (이해했다가도 다음날이면 다시 설명 못하겠음) 그 부분에 대해서도 블로그 글을 한 번 써봐야겠당 희희
그럼 3단계에서 만나자, 체스!
'우아한테크코스5기' 카테고리의 다른 글
[우테코] 블랙잭 미션 회고: 상태 패턴 사용, abstract/final 제어자, 중복되는 내용을 필드로 놓는 것에 대해.. 등등 (2) | 2023.03.24 |
---|---|
[우테코] 체스 미션 1, 2단계 리팩터링 회고 (feat. 네오의 피드백 강의) (2) | 2023.03.21 |
[우테코] 데이터베이스와 기초 SQL (0) | 2023.03.08 |
[우테코] 사다리 미션 2단계 회고: TDD, 원시값 포장, 객체의 책임... 너무 어려웡 (3) | 2023.02.27 |
[우테코] 사다리 미션 1단계 회고 (2) | 2023.02.19 |