[우테코] 프리코스 4주차 회고록

Hayoon·2022년 11월 27일
0

마지막 4주차 미션이 끝이 났다. 마지막 주차 미션은 생각이상으로 어려웠다. 1~3주차의 조건을 모두 충족시켜 완성해야 하는 미션이었달까.
마감기한 1시간 전 "예상치 못한 오류가 발생했습니다." 를 보고 지하철코딩을 강행했다. (요구사항에서 패키지 이동을 하면 안된다를 간과해서 생긴 불상사다.)

❗️3주차 미션 피드백

  1. 발생할 수 있는 예외 상황에 대해 고민한다.
    -> 사소한 예외까지 언제, 어떻게 발생할 수 있을지 고민해보는 시간이었다.
  2. 비즈니스 로직과 UI 로직을 분리한다.
    -> 입/출력 로직과 비즈니스 로직을 분리하자. 1메서드 1기능을 잊지말자. 원래 입력 + 비즈니스 로직을 한 번에 담았었는데 분리하도록 노력하자.
  3. "연관이 있는 상수"는 static final 대신 enum 활용.
  4. 객체는 객체스럽게 사용한다.
    -> 객체에서 데이터를 꺼내지(get)말고 메세지를 던지돋록 구조를 바꿔 데이터를 가지는 객체가 일하도록 한다.
    getter의 사용을 자제하고 데이터를 가지는 객체가 일하기 위해 해보았으나 제일 어렵다.
  5. 필드(인스턴스 변수)의 수를 줄이기 위해 노력한다.
    -> 각 객체가 어떤 역할을 하는지, 어떻게 엔티티를 설계해야 하는지에 깊은 고민을 해보아야 한다. 무작정 코드를 작성하기보다는 일단 종이로 그림을 그려보자.

⏰ 목표

클래스(객체)를 분리하는 연습
리팩토링
먼저 기능이 작동하도록 구현하고, 리팩토링을 해나가는 과정을 통해서 메서드 길이를 줄이고, 간결한 코드가 되도록 구현해보자.
MVC 디자인 패턴

✏️무엇을 배웠나?

이전 3주차까지는 MVC 패턴을 배제하고 구현하였지만, 이번 4주차에는 MVC패턴을 신경쓰면서 설계해보았다. 모델에는 객체들이 들어가도록, 뷰에는 입/출력 관련 클래스를, 컨트롤러는 모델과 뷰를 중개하는 역할로 큰 틀을 잡았다. 컨트롤러에는 최대한 비즈니스 로직이 들어가지 않게하고, 대부분을 모델 안에 도메인에서 구현하도록 집중했다. 컨트롤러는 모델과 뷰에 의존하고, 모델은 컨트롤러와 뷰에 의존하지 않는다.두 개는 지키도록 노력하면서 코드를 짰다.

다음과 같이 어떻게든 MVC로 분리는 했으나, Exception Enum, 게임실행 클래스는 어디다가 넣어야할지 모르겠다.

메서드 분리

public void readBridgeSize() {
        boolean isOccurException;
        do {
            String bridgeLength = enterBridgeSize();
            isOccurException = checkExceptionOccur(true, bridgeLength);
        } while (isOccurException);
    }

    private boolean checkExceptionOccur(boolean isOccurException, String bridgeLength) {
        try {
            System.out.println();
            isOccurException = bridgeException.invalidLengthInputValue(bridgeLength);
            settingBridgeValues(bridgeLength);
        } catch (IllegalArgumentException e) {
            System.out.println(e.getMessage());
        }
        return isOccurException;
    }

    private String enterBridgeSize() {
        String bridgeLength;
        System.out.println(MessageView.INPUT_BRIDGE_LENGTH.getMessage());
        bridgeLength = Console.readLine();
        return bridgeLength;
    }

    private void settingBridgeValues(String bridgeLength) {
        bridge.setSize(Integer.parseInt(bridgeLength));
        this.gameStatistics.setAnswerRoad(bridge.getBridgeMaker().makeBridge(Integer.parseInt(bridgeLength)));
    }

readBridgeSize(), checkExceptionOccer(), enterBridgeSize(), settingBridgeValues()는 하나의 메서드에서 분리시킨 메서드들이다. 어떻게든 메서드를 분리시키려고 한건데 메서드명이 비슷하거나 중복되는 느낌이 들기도 한다. 좀더 간결하게 코드를 리팩토링 하고 싶은데, 아직 코드역량이 부족한 탓일까. 쉽지 않다.

단위 테스트

@Nested
    @DisplayName("게임 커맨드 예외처리")
    class Test1 {

        @DisplayName("다리 길이를 입력 시, 3 ~ 20 아니면 예외처리")
        @ParameterizedTest
        @ValueSource(strings = {"a", "2", "-1", "100"})
        void 다리_길이_유효성_검사_테스트(String bridgeLength) {
            assertThatThrownBy(() -> new BridgeException().invalidLengthInputValue(bridgeLength))
                    .hasMessageContaining(ErrorView.error)
                    .hasMessageContaining(ErrorView.INVALID_BRIDGE_LENGTH.getMessage())
                    .isInstanceOf(IllegalArgumentException.class);
        }

@ParameterizedTest를 사용해 다양한 변수로 테스트를 한 번에 할 수 있었다. AsserThatThrownBy() 뒤에 옵션들 (.hasMessageContaining, isInstanceOf())도 이용해보았다.
@Nested를 활용하니 테스트 성격별로 카테고리를 나눌 수 있었다.

🔧 아쉬운 점

어찌저찌 코드를 요구사항에 맞게 짜고, 리팩토링도 하고 완성을 했지만 만족스럽지가 않다. 앞으로 최종 코딩테스트 응시자격 발표가 2주 조금 더 남았다.
도메인엔티티, 서비스로 나누어 비즈니스 로직과 객체스러움으로 나누고 컨트롤러모델의 로직을 연결해주는 목적성에 맞게 지난 미션들로 연습해보아야겠다. 자바스트림은 쉬운거부터 계속 연습해 보아야겠다. indent를 1줄로 줄일 수 있는 게 매우 유용한 것 같다.

결과가 어떻게 될지는 모르지만, 최선을 다해 후회없는 시간이 되었으면 좋겠다.

profile
Junior Developer

0개의 댓글