우테코 - 사다리 타기 미션 회고
사다리 타기 미션을 진행하면서 있었던 과정을 회고해보자
두 번째 미션인 사다리 타기가 시작되었다~ 이번 미션을 통해 어떤 점을 느꼈고 어떤 걸 배운지 회고 해보자!
사다리 타기 미션 시작
브라운 당첨(?) 축하합니다…
TDD
이번 미션부터는 TDD를 적용하며 페어와 함께 미션을 진행해야 한다. TDD를 직접 적용하는 건 처음이라 많이 서툴렀던 것 같다. 코드를 작성하다가 “아 맞다 TDD..” 만 몇 번 외쳤는지 ㅋㅋㅋ 아직 TDD에 완벽하게 적응한 건 아니지만 확실히 직접 경험해 보니깐 어떤 느낌인지는 알 것 같다. 직접 하면서 느낀 장점으로는 먼저 테스트 코드를 기반으로 프로덕션 코드를 작성하기 때문에 절대 테스트 코드를 작성하지 못할 일은 없을 거 같고 빠른 피드백을 기반으로 개발할 수 있다는 게 매우 큰 장점으로 느껴졌던 것 같다.
TDD를 하다보니 다음과 같은 의문점이 들었다.
- fail -> success -> refactor 단계로 사이클을 돌아가면서 개발을 진행하는데 이 refactor 단계에서 어느정도까지 refactor를 해야 적당한지?
이 내용은 테코브러리에도 있는 켄트백의 TDD 책에도 나오는데, 리팩토링에 대한 부분은 TDD에 대한 익숙함과 도메인 지식과 관련되어있습니다. TDD에 익숙하거나 사다리게임에 대한 도메인 지식이 풍부한 상태라면 리팩토링 단계에서 생략할 수 있는 부분이 많아질 거에요. 이 부분은 생략하는것도 좋은 방법입니다.
사소한 변경사항이 생기셨을때도 fail을 보는 단계부터 시작하셨나요? 아마 무민도 은연중에 많은 부분을 건너뛰셨을거에요 😂
- 테스트코드와 기능 구현을 번갈아 가면서 진행하기 때문에 깃커밋 메시지를 test, feat 으로 번갈아가며 썼는데 이것두 맞는지 아니면 feat 한개로도 충분한지?
test, feat으로 구분해주셔서 보는 입장에선 보기 편했고 TDD로 잘 작성해주셨다는것도 알 수 있었습니다! 커밋 메시지는 오답만 있지 정답은 없는 부분이라서 나만의 생각을 정해 나가는것도 좋을 것 같아요. 무민은 번갈아가면서 쓰시는게 어떠셨나요?
역시 자기만의 기준이 제일 중요한 거 같다. 나의 기준이 잘 세워질 수 있도록 계속해서 적용해 보자!
step2(사다리 게임 실행) 시작
이번 미션에서 목표가 피드백을 최대한 많이 받는거라 이번 step2에서 빨리 내고 피드백 cycle을 최대한 많이 돌리려고 생각했다. 근데 지금 생각해보니깐 빨리만 짜고 이상하게(머리에 과부하가 와서 사실 뭘 더 고쳐서 내야 될지 못 찾음..) 낸거 같아 고생하신 리뷰어님께 죄송한 마음이 든다. 하지만 덕분에 엄청나게 많은 피드백으로 앞으로 코드를 구현할 때 어떻게 짜야될지 무엇을 고민해봐야 될지 많은 깨달음을 얻은 정말 귀중한 시간이였다! 감사합니다 터틀🐢..
각 객체와 Controller 역할 망각
리뷰어님께 온 피드백 중 상당 수가 다음과 같았다.
- 컨트롤러가 Model과 View의 상호작용 뿐만 아니라 게임 진행까지 진행하고 있는것같아요. 무민이 의도한 Controller의 역할은 무엇인가요?
- 플레이어 이름을 입력받은 다음 객체를 만들었다면 이후엔 객체간 협력을 통해 로직이 진행하도록 하면 어떨까요? 만든 객체가 아니라 입력받은 names를 통해 진행하는 로직이 많아보여요
- Position 클래스를 만들었다면 값을 꺼내서 계산하는 것이 아니라 Position 클래스와 상호작용을 통해 계산해보는건 어떨까요?
- 플레이어의 이름이 all과 같지 않아야 한다는 비즈니스 로직이 아닐까요? 적절한 책임을 갖는 객체로 이동시켜보면 어떨까요?
- 위 리뷰에서 적절한 객체로 이동한다면 이 부분도 Controller가 아니라 해당 객체에서 처리할 수 있지 않을까요?
진짜 부끄럽지만 사실대로 말하면 지금까지 코드를 짜는 동안 각 객체의 역할이나 Controller의 역할에 대해 제대로 생각해 보지 않고 짠 거 같다. 그냥 기능만 잘 돌아가게 만들고 그 위치는 아무 곳이나 넣었다 해도 과장이 아닌 것 같다.. 이 사실을 막상 마주치니깐 약간 망치로 머리를 맞은 것 같았다. 그동안 나.. 뭐하고 있었지?
맨날 객체지향, 객체지향하고 있었는데 사실 겉멋 객체지향이었던 건가..? 사실 얼마 전 객체지향의 사실과 오해에서도 이 부분과 관련해서 읽었었는데 그래도 깨닫지 못했었고 이번 피드백과 많은 다른 사람들의 코드 리뷰나 블로그 회고 등을 통해 느끼게 되었다. 앞으로 각 객체에 어떠한 적절한 책임이 주어져야 될지 고민해 보고 이들 간의 협력을 잘 이용해 보려 한다.
메서드 추출시 static
인텔리 제이 단축키를 이용해 메서드 추출을 할 때 static과 관련된 코드가 포함되어 있으면 그 추출한 메서드에 static이 붙게 되는데 이걸 까먹고 지우지 않아 종종 지적받았던 것 같다. 흠.. 추출할 때 default로 static이 붙지 않게 해주는 설정을 찾아보았지만 아직 못 찾았다ㅠ 혹시 아는 분 있으면 댓글로 좀…! 🙇
메서드 위치
코드 작성시에 메서드 위치 관련해서도 얘기가 나왔는데 다른사람이 코드를 봤을 때에도 빠르게 파악하기 위해 다음과 같은 순서로 진행되면 좋을 것 같다!
- public 주석
- 클래스
- 정적 변수 : public -> protected -> private
- 인스턴스 변수 : public -> protected -> private
- 생성자
- 정적 메소드 : static 메소드 (main 메소드가 있다면 static 메소드 이전에 작성)
- 메소드 : 접근자 기준으로 작성하지 않고, 기능 및 역할별로 분류하여 기능을 구현하는 그룹별로 작성이 이루어지도록 해야한다. (public 사이에 private 메소드가 존재할 수 있다)
- 스탠다드 메소드 : toString, equals, hashcode 와 같은 메소드
- getter, setter 메소드 : 클래스의 밑 부분에 위치
코드 예시는 다음 링크를 참고
package-private
테스트 코드에서 hasMessage를 검증할 때 다음과 같이 적용하고 있었는데 리뷰어님이 객체의 상수를 package-private로 변경해 참조하면 어떨까 추천해 주셨다.
assertThatThrownBy(() -> new Ladder(height, 4, new RandomPointGenerator()))
.isInstanceOf(IllegalArgumentException.class)
.hasMessage("[ERROR] 사다리 높이는 1이상이어야 합니다.");
public class Ladder {
//package-private 적용
static final String INVALID_HEIGHT_ERROR = "[ERROR] 사다리 높이는 1이상이어야 합니다.";
...
}
//test 코드
assertThatThrownBy(() -> new Ladder(height, 4, new RandomPointGenerator()))
.isInstanceOf(IllegalArgumentException.class)
.hasMessage(Ladder.INVALID_HEIGHT_ERROR);
package-private를 사용함으로 상수를 재활용해 볼 수 있고 접근도 public이 아닌 같은 패키지안으로 제한해 볼 수 있기 때문에 좋은 방법인 것 같다!
Stream API
Stream과 관련해서도 다음과 같은 피드백들이 왔다..ㅠㅠ
- stream API에 익숙하시지 않다면 이 부분을 stream API를 활용해 변경해보면 어떨까요?
- 이 results 컬렉션에 add해야되어서 아래 메서드에 계속 인자를 넘겨주게 되네요. 로직 중간에 다른 리스트가 인자로 넘어가거나 순서가 변경된다면 기대하는 동작이 이루어지지 않을 수도 있을것같아요. 리스트를 생성하고 add 하는 것이 아니라 새로운 ArrayList를 반환하도록 변경해보는건 어떨까요? 이 부분도 stream API를 활용하면 조금 더 깔끔해질 수 있지만 익숙하지 않다면 굳이 stream을 사용하지 않으셔도 됩니다!
그동안 Stream을 어느 정도 사용할 줄 안다고 생각해왔었는데 알고 보니 빙산의 일각이었고 ㅋㅋ 그마저 제대로 사용하지 않고 있었다. 이 계기로 현재 보던 다른 책들을 제치고 모던 자바 인 액션으로 자바의 보충 시간을 갖기로 했다!
일주일 간 흡수
지난주 코드 리뷰를 기다리는 동안 어떻게 하면 더 성장할 수 있을지, 내 부족함을 채울 수 있을지에 대해 고민했고 다른 사람들의 코드 리뷰와 블로그 회고를 보며 다른 사람들의 내공을 흡수하려고 노력했다. 대략 한 10명의 코드 리뷰를 봤던 거 같고 블로깅은 한 50개 이상 정도 보지 않았을까 예상된다. ㅋㅋㅋㅋ
꾸글스(꾸준히 글 쓰는 스터디)에도 가입했는데 다른 크루들의 글을 수십 개 읽으면서 정말 멋진 생각, 고민들을 하는 사람들이 많다는 걸 알게 되었고 앞으로의 방향성이나 어떤 고민(설계, 기술적 적용 등)을 할 수 있을지 생각해 보는 뜻깊은 기간이었다~!
지금 보니깐 약간 주접을 떤 거 같은데… 저 때 당시에는 보고 나서 “와 우리 꾸글스 크루들 진짜 멋있다.. 더 열심히 해서 어울리는 크루가 되야겠다” 라는 생각이 들어서 썼다.. ㅋㅋㅋ 지금 보니 약간 부끄럽다;; 앞으로 커비에 빙의해서 다 흡수하고 다닐 예정이다.
앞으로 적용해볼 것
다른 분들의 코드 리뷰나 블로그를 보면서 엄청나게 많은 내공들을 흡수한 것 같다! 하지만 직접 써보지 않으면 의미가 없기 때문에 이제 적용해 볼 차례. 앞으로 적용할 생각에 벌써부터 설레는 것 같다.
앞으로 적용해볼 것
- 기능 목록을 작성할 때 도메인 별 기능 정리
- Functional Interface(재입력시)
- Equals and hashcode
- 방어적 복사
- 정적 팩토리 메서드
+리뷰어님께 받은 코드 리뷰에 대해 관심이 있으면 다음 PR들을 참고!
*틀린 부분이 있으면 언제든지 말씀해 주시면 공부해서 수정하겠습니다.