이번 미션은 사다리 게임이었습니다. 우아한 테크 코스 레벨 1을 진행하면서 제 자신이 스스로 다짐한 목표가 있는데,
"이전 미션들에서 받은 리뷰들을 다시 받지 않기"입니다.
그래서 최대한 자동차 경주에서 받았던 리뷰를 다시 받지 말자라는 생각을 하며 미션을 진행해 봤습니다.
이번에는 미션을 진행하면서 리뷰어 뿐만 아니라 페어와도 많은 의견을 나누면서 배웠습니다.
validation은 어디에서 처리해야할까?
이 부분은 자동차 경주에서도 정리했던 내용입니다. 다만 다른 점이 있다면 자동차 경주에서는 자동차의 이름에 관한 validation으로 "원시 값 포장"을 통해서 validation 책임을 분산시켰습니다.
이번 사다리 미션에서도 마찬가지로 이름 길이 제한이 있었습니다. 자동차 경주에서의 피드백처럼 도메인 규칙은 도메인에서 처리해야 하기 때문에 Person이라는 클래스에서 해당 validation을 처리했습니다.
문제는 이제 사다리 미션에서의 최소 참가자 수 제한, 이름 중복 불가에 대한 요구사항이었습니다. 저는 이 부분이 "게임"적인 요소라 생각이 들어서 InputView에서 처리를 했습니다.
하지만 리뷰어님이 아래와 같이 말씀해 주셨습니다.
참가자 수, 이름 중복 X 요구 사항은, inputView의 역할로 볼 수도 있지만, 게임 자체의 로직으로도 볼 수 있을 것 같은데요!
일급 컬렉션 등을 활용하여 도메인 로직에서 이를 검증하는 것은 어떨까요?
저도 이 부분은 게임 자체의 로직으로 생각했지만 리뷰어님과의 생각과 다르게 도메인 로직에서 검증하는 것이 아닌 InputView에서 처리를 했습니다.
리뷰를 보고 "각 사람마다(ex 이름) validation"은 Person이라는 원시 값 포장 객체에서 처리를 하고, "모든 사람(참가자 수 제한, 이름 중복) validation"은 People이라는 일급 컬렉션에서 처리를 하는 게 좋지 않을까?라는 생각을 다시 하게 됐습니다.
또한, InputView가 변경되었을 때 이러한 validation 이 누락된다면 장애가 날 수 있기 때문에 최대한 도메인에서 진행하여 테스트 코드를 통해 이를 방어하면 좋지 않을까 하는 리뷰어님의 의견에 적극 동의했습니다.
느낀 점
결론은 validation은 그 클래스에 맞도록 책임을 분산시키는 게 좋아 보입니다. 이 부분은 사람마다 의견이 매우 갈리게 됩니다. 하지만 저는 사용하다 보니 인스턴스 변수가 많은 객체에서 모든 validation의 책임을 갖고 있는 것이 가독성 + 책임이 너무 많다고 생각되어 포장을 하는 게 좋다고 느꼈습니다. 또한, 애플리케이션 자체에서의 도메인 관련 validation은 일급 컬렉션이든 원시 값 포장이든 간에 도메인에서 처리하고 이를 테스트 코드로써 방어하면 매우 안정적인 애플리케이션이 될 거라 생각합니다.
테스트 시 exception 발생 여부도 좋지만 제대로 생성됐는지 확인해 보자
제목과 똑같은 내용입니다. 처음에는 객체를 생성할 때, exception이 터지지 않으면 제대로 생성됐다고 생각하고 테스트를 작성했습니다.
느낀 점
하지만 그건 코드를 작성한 저의 생각이기 때문에 테스트를 통해서는 exception의 발생 여부도 좋지만 제대로 생성됐는지 확인하는 게 좋아 보인다는 리뷰어님의 말씀을 적극 지지합니다!!
페어와 메서드 네이밍 고민
private void validateHeightOf(List<Line> lines);
이번에 페어 프로그래밍을 같이하면서 페어는 메서드 이름 뒤에 전치사를 붙여서 한 번에 메서드명 + 파라미터까지 읽히는 것을 선호한다고 했습니다.
저는 이때까지 서술적으로만 작성했기 때문에 처음 보는 메서드 네이밍 전략(?)이었습니다. 그런데 가끔 한 호흡에 읽히는 게 가독성이 정말 좋아 보일 때가 있습니다. 위 메서드를 보면 lines의 높이를 검증한다 바로 읽히는 것처럼 말이죠.
느낀 점
그래서 페어가 제시한 방법을 파라미터가 많지 않을 때 사용해도 좋아 보이고, 한 호흡에 읽힌다라는 게 큰 장점인 것 같습니다.
Supplier 함수형 인터페이스를 사용하여 exception 처리
public class IllegalArgumentExceptionHandler {
public static <T> T handleExceptionByRepeating(final Supplier<T> supplier) {
try {
return supplier.get();
} catch (IllegalArgumentException exception) {
System.out.println(exception.getMessage());
return handleExceptionByRepeating(supplier);
}
}
}
// LadderEnigne.java
private People makePeople() {
return IllegalArgumentExceptionHandler.handleExceptionByRepeating(
() -> convertNamesToPeople(InputView.inputName())
);
}
private Ladder makesLadder(People people) {
return IllegalArgumentExceptionHandler.handleExceptionByRepeating(
() -> {
int height = InputView.inputMaxLadderHeight();
List<Line> lines = makeLines(people, height);
return new Ladder(people, lines);
}
);
}
// InputView.java
public static List<String> inputName() {
return IllegalArgumentExceptionHandler.handleExceptionByRepeating(() -> {
System.out.println("참여할 사람 이름을 입력하세요. (이름은 쉼표(,)로 구분하세요)");
String input = ScannerUtil.nextLine();
return splitNames(input);
});
}
페어 프로그래밍을 하면서 exception이 발생했을 때, 재입력하는 기능을 넣고 싶었습니다.
그래서 try-catch를 사용하며 exception이 터지면 같은 메서드를 호출하는 메서드들이 전부 비슷한 형태를 띠고 있었습니다.
이를 공통화하고 싶다 했었는데, 페어가 방법을 알고 있다며 Supplier<T> 함수형 인터페이스를 통해서 handler를 따로 빼고 exception 처리하는 부분을 Supplier 인자로 넘기는 것입니다.
느낀 점
이러한 방법을 처음 봤었고, 이게 진짜 모던 자바의 참맛인가라는 생각을 했습니다. 그리고 함수형 인터페이스의 힘은 무궁무진하구나,, 이런 것도 처리할 수 있고,,
다시 모던 자바 인 액션 책을 보면서 모던 자바를 공부해야겠다는 생각을 하게 됐습니다.
일급 컬렉션의 장점 파악
public class Ladder {
private final People people;
private final Line line;
private final List<String> resultCandidates;
// ...
}
사다리 미션에서의 인스턴스 변수들입니다.
resultCandidates는 결과후보들에 대해서 따로 처리할 게 없다고 생각해서 일급 컬렉션을 적용하지 않았습니다.
코치님과 이 부분에 대해서 대화를 나눴었는데, 변수명으로도 무엇인지 나타낼 수 있지만 "타입"으로 말하는 것을 선호한다고 하셨습니다.
해당 말씀을 듣고 타입으로 말한다에 대해서 한번 생각을 해보았습니다. 타입으로 말한다.. 이게 뭘까,,? 또다시 동욱님의 블로그를 뒤적뒤적거렸습니다,, 하하
일급 컬렉션의 장점 중 하나인 이름이 있는 컬렉션을 가질 수 있다는 점이었습니다. 그리고 이게 코치님이 말씀하신 타입으로 말한다와 일맥상통하다고 느꼈습니다.
또한, 오브젝트 책(pg46)을 읽다가 코치님과 같은 말씀을 하셔서 발췌해 보았습니다.
객체지향의 장점은 객체를 이용해 도메인의 의미를 풍부하게 표현할 수 있다는 것이다.
그래서 저는 책을 읽으면서 코치님 말씀이 생각났고, 이게 객체지향의 장점 중의 하나라고 생각할 수 있구나라고 배웠습니다.
느낀 점
변수명으로도 표현하는 것도 좋지만, 타입으로 표현하면 얻는 장점들이 더욱 많아집니다.
디렉터리에서도 파악할 수 있으며(ex. Ladder는 People, Line, Goal로 이뤄져 있음), 뜻이 명확해질 수 있습니다.
그래서 resultCandidates에서 따로 처리할 일이 없어도 의미 파악을 위해서 일급 컬렉션을 사용하는 그 가치는 충분하다고 생각합니다.
이전 자동차 경주에서는 상태와 행위를 한 곳에서 관리할 수 있다는 장점을 느낄 수 있었는데, 이번 미션에서는 일급 컬렉션의 장점을 하나 더 몸으로 느낄 수 있었습니다.
'woowacourse 5기' 카테고리의 다른 글
레벨 2 회고 (0) | 2023.06.26 |
---|---|
[우아한테크코스] 4주차 체스 회고 (2) | 2023.04.05 |
[우아한테크코스] 3주차 블랙잭 회고 (0) | 2023.03.25 |
[우아한테크코스] 1주차 자동차 경주 (0) | 2023.02.20 |
[우아한테크코스] 우테코 5기 백엔드 합격 (2) | 2023.02.20 |