페어 미션 (블랙잭)
배운 점
페어와 많은 이야기를 하면서 다양한 지식을 얻었지만, 여전히 궁금했던 부분들을 리뷰어에게 질문했었다.
다음은 내가 의문이 들었던 내용과 리뷰어에게 받은 답변을 정리해 봤다.
Q. Scanner는 어떻게 선언하는게 좋을까요?
페어와 출력을 구현하다가 페어가 scanner를 선언할 때, private static final Scanner scanner = new Scanner() 로 구현하는 것을 알 수 있었습니다.
하지만 현재까지 저는 Scanner를 static final으로 선언했을 때, 인스턴스가 함수 밖에서 초기화 되는 것이 좋다고 생각하지 않아 어떤 방식이 더 좋을까?이야기하였습니다.
하지만 페어의 의견도 이해가 되었던 것이 Scanner에서 사용하는 System은 이미 static으로 하나를 함께 사용하는 형식인데 굳이 Scanner가 한 개 이상 생성될 필요 있을까?라는 의견이었습니다.
여담으로 또다른 의견으로 static final이 아니라 static으로만 구현하여 scanner가 사용될 때 scanner가 생성되지 않았다면 생성하도록 하고 아니면 원래 만들어진 것을 사용하도록 하여 인스턴스를 함수 안에서 초기화하는 장점과, static으로 하나만 제작되도록 하는 장점을 섞을 수도 있지 않을까?하는 생각도 하였습니다.
A. Scanner가 한 개 이상 생성될 필요가 없다는 생각에 동의합니다.
static final로 선언했다는 것은 singleton 객체로 사용하겠다는 의미인것 같습니다.
여담으로 고안한 방식은 lazy loading을 의미한 것 같습니다. 객체의 생성비용이 큰 경우 이 또한 좋은 방식이 될 수 있을것 같습니다.
다만 해당 방식을 사용하였을때 동시성 이슈에 대한 처리도 고려해야하는 등 지금 미션에서는 조금 과한 초기화 방식이 될 수 있을것 같습니다.
인스턴스를 함수 안에서 초기화하는 장점
위와 같이 말씀해주셨는데 정확히 어떤 장점을 고려하고 질문을 주신것일까요?
scanner를 static final로 선언했을 때 제어의 영역을 벗어나게 됩니다. 만약 이에 따라 애플리케이션의 테스트가 불가능해진다면 저는 외부에서 주입해 주는 형태로 바꾸는 고려를 할 것 같습니다.
Q. 콜백이나 함수형 인터페이스를 활용해 view와의 의존성을 분리하여 도매인 로직으로 녹여내세요.
이러한 일련의 흐름 (카드를 더 받을지 묻고 -> 더 받고싶다는 응답이 왔을때 카드를 더 받는다) 도 검증을 하면 좋을것 같습니다.
view에 대한 의존성 때문에 검증하기 힘든 부분으로 보이실 수 있는데 함수형 인터페이스와 callback을 활용한다면 의존성을 분리하여 도메인 로직으로 녹여낼 수 있을 것 같습니다.
A. 함수형 인터페이스를 사용하도록 변경하였습니다.
이전에 view에 대한 의존성 때문에 컨트롤러에서 많은 일을 하도록 구현하였습니다.
해당 로직을 함수형 인터페이스를 이용하여 뷰와의 의존성을 분리하고, blackJack 내에서 해당 로직을 실행하도록 수정하였습니다!
함수형 인터페이스명 | 설명 | 추상메서드 | 주 사용법 |
Consumer<T> | 객체 T를 받아 소비 | void accept(T t) | 입력 값을 이용한 연산이나 출력 등의 동작에 사용 |
BiConsumer<T, U> | 객체 T, U를 받아 소비 | void accept(T t, U u) | |
Supplier<T> | 객체 T를 반환 | T get() | 주로 입력 받는 방식을 결정해 파라미터 없이 특정 결과를 생성하는데 사용 |
UnaryOperator<T> | 객체 T를 객체 T로 매핑 | T apply(T t) | |
Function<T, R> | 객체 T를 객체 R로 매핑 | R apply(T t) | |
Predicate<T> | 객체 T를 받아 boolean을 반환 | boolean test(T t) | 주로 객체를 조건에 따른 |
카드를 더 받을지 여부 구현 시 사용
- 카드를 받을지 입력 함수 - Predicate<Name>
: 이름을 전달해 input에서 해당 이름 참가자의 카드를 더 받을지 여부 입력 → boolean으로 반환 - 추가 카드 반환 함수 - Supplier<Card>
: 카드를 추가할 상황일 시 해당 함수를 호출해서 카드 받기 - 카드 추가 후 카드 결과 출력 함수 - BiConsumer<Name, Cards>
: 이름과 카드 정보를 받아 outputView에서 해당 이름과 카드 정보를 출력
소감
블랙잭 미션은 전 미션들보다 난이도가 높았던 것 같다.
사실 블랙잭을 몰라서 어려웠던 점이 많았다. 블랙잭의 룰을 모르다보니 설계하는데 어려움이 많았고, 실수도 많았다.
이래서 금융 기업에 개발자가 되고 싶다면 금융 지식이 필요하듯이 개발만 잘한다고 되는게 아닌 것 같다.
그렇게 블랙잭도 모르는 두 명이서 블랙잭을 만들기 시작했었다 (페어도 모름)
블랙잭 미션을 하면서, 페어와 맞지 않는 점은 없었다. 이번 페어와는 전에 배웠던 TDD를 완벽하게 수행했다.
그래서 처음 코드 작성할 땐, 정말 테스트가 통과되도록 최악의 코드를 작성하였다.
그리고 기능 구현이 되었을 때, 점차 코드를 리팩터링해서 멋진 코드가 되는 과정을 완벽하게 느꼈다.
그 희열은 말로 설명할 수 없었다. ㅋㅋㅋㅋ
진짜 심지어 TDD를 하고자 구현해놨던 코드로 인해서, 코드 수정으로 발생하는 오류도 손 쉽게 찾을 수 있었다.
다시 한번 TDD 굿 👍
'부트캠프 > 우아한테크코스' 카테고리의 다른 글
우아한테크코스 회고 - 첫 만남은 너무 어려워 🎶 (1) | 2024.09.22 |
---|---|
우아한테크코스 회고 - 우물 속에서 탈출하다 (1) | 2024.07.27 |
우아한테크코스 회고 - 사다리 타기 (2) | 2024.03.18 |
우아한테크코스 회고 - 자동차 경주 (1) | 2024.03.08 |
우아한테크코스 회고 - 연극을 왜 하죠? (1) | 2024.03.08 |