지금까지 자동차경주, 로또 미션을 진행했는데 이번 블랙잭 미션은 도메인 이해도가 가장 낮은 미션이였다.
한 번도 해본 적이 없는 게임이지만 미션을 보고 이렇게 게임이 돌아가는 구나~ 라고 생각해서 구현을 했다.
그랬더니 아래와 같은 리뷰를 받았다.
실행 결과의 예시가 아래와 같아서 나는 이 리뷰가 굉장히 의문이여서 다시 질문을 드렸다.
리뷰어님 왈 : 이거는 블랙잭 게임을 구현하는 것이 목표이지 거기 써져 있는 구현 사항만 지키는게 목표가 아님! 예시로 쓰여 있는 것은 가이드일뿐!
이 말을 듣고 무릎 탁! 이마 탁!을 하게 되었다.
내가 만드는 것도 하나의 어플리케이션인데, 미션을 구현하기에 바빠 어떻게 구현하는 것이 사용자가 더 편리하게 사용할 수 있고 더 재밌게 즐길 수 있을지에 대한 고민을 하나도 하지 않았기 때문이다..
배달의 민족 CEO이신 김범준님이 EO에서 하신 말이 굉장히 인상 깊었고 나중에 이런 개발자가 되어야지 라는 생각도 했었는데, 당장 앞에 보이는 나무만 생각해서 정작 숲을 보지 못 했던 것 같다.
그래서 반성의 반성의 반성을 하며,, 좋은 프로덕트가 무엇이고 내가 이 것으로 어떤 가치를 만들 수 있는지 항상 고민할 수 있는 개발자가 되도록 노력해야겠다 :)
객체지향의 사실과 오해를 보면, 객체지향의 세계는 현실 세계의 은유라고 나온다.
그 이유는 실제 존재하는 용어를 사용했을 때, 더 이해가 쉽기 때문이다.
위의 리뷰와 약간 비슷한 느낌인데 사용할 도메인에 대한 이해를 높이는 것이 중요한 것 같다!
안녕하세요 주디! 구현해주신 부분 잘 봤습니다.
1단계 구조를 잘 잡고 가서 그런지 기능이 잘 추가 되었네요.
간단히 고민할만한 부분들 코멘트 남겨두었어요.
그리고 테스트 돌려보니 생각보다 커버리지가 낮은 것 같아요!
주디가 생각하는 도메인에 대한 부분만이라도 조금 높은 커버리지를 가져가야
안정적인 애플리케이션이 되지 않을까요??
드린 코멘트 이해 안되거나 하시는거 있으면 편히 DM 주세요 :)
2단계 리뷰 요청을 한 후, 이렇게 코멘트를 주셨는데 이걸 처음 본 당시에는 커버리지가 뭔지도 몰랐다..ㅎㅎ
저 버튼을 누르고 어플리케이션을 돌리고 나면, 아래와 같이 테스트가 되었는지 뜬다.
나는 도메인의 경우 Method가 100%가 되도록 노력했다!
설계할 때부터 모든 테스트를 작성하도록 노력하지만 실제로 구현하다보면 그게 안될 때가 많은데 이 기능을 활용하면 좋을 것 같다!
처음 게임 결과 판단 기준은 아래와 같았다.
BLACKJACK(1.5, (dealer, gamer) -> gamer.isBlackJack() && !dealer.isBlackJack()),
WIN(1.0, (dealer, gamer) -> !gamer.isBust()
&& (dealer.calculateResult() < gamer.calculateResult() || dealer.isBust())
),
DRAW(0.0, (dealer, gamer) -> !gamer.isBust()
&& dealer.calculateResult() == gamer.calculateResult()
),
LOSE(-1.0, (dealer, gamer) -> gamer.isBust()
|| (dealer.calculateResult() > gamer.calculateResult() && !dealer.isBust())
);
그리고 승패를 찾는 로직은 아래와 같았다.
private static GameResult findResult(final Dealer dealer, final Gamer gamer) {
return Arrays.stream(values())
.filter(result -> result.predicate.test(dealer, gamer))
.findFirst()
.orElseThrow(() -> new IllegalArgumentException("[ERROR] 존재하는 결과가 없습니다."));
}
나는 ENUM의 순서대로 결과를 찾기 때문에 내 판단 기준에 큰 문제가 없다고 생각했는데 리뷰어님이 아래와 같은 리뷰를 주셔서 다시 생각해 볼 수 있는 계기가 되었다.
해당 판단 기준이 private으로 캡슐화되어 있다고 하더라도 각 ENUM은 독립적으로 쓰일 수 있어요.
예를 들면, 지금과 같은 상황에서 WIN, DRAW, LOSE의 순서만 변경되더라도 로직이 틀어지는 부분이 생길 수 있습니다. 제가 생각할 때는 각각의 케이스가 모든 경우를 커버하도록 완전하게 작성되어야 할 것 같은데 어떻게 생각하시나요?
가끔 무지성으로 코드를 작성할 때가 있다..
private void checkCardSize() {
if (deck.size() == EMPTY_DECK_SIZE) {
throw new IllegalStateException("[ERROR] 더이상 카드를 뽑을 수 없습니다.");
}
}
위와 같이 코드를 짰었는데 deck.isEmpty() 이라는 좋은 메서드가 존재함에도 불구하고 괜히 불필요한 상수를 하나 더 만드는 만행을 저질렀다..
반성하자 주리링 ㅠ.ㅠ
저도 테스크 커버리지 궁금했는데 찾아보게 되었어요!