본문 바로가기

Hub Development/Woowacourse

[우아한테크코스] 우테코 6기 프리코스 2주차 피드백 정리

728x90

📜 우테코 6기 프리코스 2주 차


🔹 2주 차 프리코스의 미션은 자동차 경주 게임을 만드는 미션이었다. 미션을 진행하면서 내가 고민했던 부분과 코드 리뷰를 통해서 받았던 피드백 내용을 공유해 보고자 글을 작성했다.

 

GitHub - noxknow/java-racingcar-6: 우아한테크코스 6기 자동차 경주 미션을 진행하는 저장소

우아한테크코스 6기 자동차 경주 미션을 진행하는 저장소. Contribute to noxknow/java-racingcar-6 development by creating an account on GitHub.

github.com

 

➡️ 이번 미션의 시작은 구현 기능 목록 작성이 아닌 코드 리뷰였다. 코드 리뷰를 하기 전에는 과연 이 과정이 도움이 될 수 있을까? 라는 생각을 가졌고, 코드 리뷰를 하는 것보다 리뷰를 받음으로써 생기는 피드백이 더 도움이 될 것이라는 생각을 가졌다.

 

하지만, 예상과는 다르게 다른 사람의 코드를 리뷰함으로써 발전하는 부분이 더 컸던 것 같다. 물론 코드 리뷰를 받고 생긴 피드백 역시 이번 미션에 적용하고 싶은 내용도 많았고, 고민을 해결하는 역할을 했다. 코드 리뷰를 하면서는 더 정확한 정보를 제공하기 위해 학습하고, 그에 따라 돌아온 답변을 보며 나와는 다른 견해를 통해 미션에 접근하는 시야가 넓어졌다고 생각했다.

 

위와 같이 코드 리뷰의 중요성을 알게 된 후 이번 코드를 작성하면서는 많은 부분이 달라졌다. 코드를 작성하면서도 프로그램의 구조를 지금과 같이 설계한 이유, wrapper 클래스를 사용했다면 리뷰어 분들이 wrapper 클래스를 사용한 이유를 물어봤을 때 나는 뭐라고 대답해야 할까 진짜 필요한 부분일까 와 같이 제가 작성한 부분에 대해서 확실하게 알고 넘어가야겠다는 생각을 했다. 아래 부분은 mermaid를 활용한 클래스들의 UML과 이번 미션을 진행하며 고민했던 과정과 다음 미션에 적용할 내용들에 대해 적어뒀다.

 

👻 문제 해결 과정 중 고민 사항

 

❓ DTO와 VO의 차이


🔹코드 리뷰를 하면서 DTO를 사용한 코드를 많이 볼 수 있었다. 개인적으로 미션에서 DTO를 사용할 만한 부분이 보이지 않았었는데 문득 DTO와 VO의 정확한 차이를 모르고 있다는 생각이 들었다.

 

DTO와 VO에 대해서 알아보며 느꼈던 점은 Data를 전달하는 객체로 동일한 개념을 갖고 있지만, VO는 값 자체를, DTO는 Data를 전달한다는 차이점을 알게 되었다. 즉, DTO는 getter/setter 두 가지의 메서드만 존재해야 하지만 VO의 경우는 불변성을 위해서 setter가 없어야 하고 다른 로직이 들어가도 된다고 이해했다. 그렇다면 미션에서는 VO를 통해 내부적으로 validate와 같은 유효성 검사 로직을 구현해도 좋고, DTO를 활용한다면 외부의 Validator 클래스를 두고 호출을 통해 검증하는 과정을 만든다면 어느 방식을 사용해도 괜찮다는 결론을 내렸다.

 

🧐 Arrays.asList vs List.of


🔹저번 미션에서는 배열을 리스트로 변환할 때 Arrays.asList를 사용했지만 이번 미션을 진행하면서 List.of를 알게 되었다. 단순하게 둘은 같은 타입을 반환할 것이라고 생각했지만, 전혀 다른 타입을 반환한다는 사실에 놀랐다. 이 두 함수에 대해서 좀 더 자세하게 알아볼 필요성을 느끼게 되었다.

 

    1. .collect(Collectors.toList()) :

 

stream을 사용하여 데이터를 처리한 후, .collect(Collectors.toList())를 사용하면 ArrayList를 반환한다. 이 ArrayList는 변경 가능하며 요소를 추가, 제거 또는 변경할 수 있다.

 

    2. Arrays.asList() :

 

Arrays.asList()를 사용하여 배열을 List로 변환하면 java.util.Arrays.ArrayList의 인스턴스를 반환한다. 이 ArrayList는 수정할 수 없으며 요소를 추가 또는 제거할 수 없다. 즉, 크기가 고정된 리스트.

 

    3. List.of() :

 

List.of()를 사용하면 수정할 수 없는 불변한 List를 반환한다. 이 List는 크기가 고정되어 있으며 요소를 추가, 제거 또는 변경할 수 없다.

 

🔹 학습을 진행하면서 .collect(Collectors.toList()) 도 같은 타입을 반환할지 궁금해서 추가해서 학습하게 되었고 위와 같은 결과를 얻게 되었다. 추가적인 사실로는 Arrays.asList()는 List.of()보다 힙에 더 많은 개체를 생성하기 때문에 더 많은 오버헤드 공간을 차지한다. 따라서, 단지 값 요소가 필요한 경우라면 List.of()가 적합하다 라는 내용에 이번 미션은 List.of()를 활용했다.

// 중략
public class ConsoleInput implements InputHandler {

    // 중략    

        private List<String> stringToList(String input) {
        try {
            return List.of(input.split(","));
        } catch (Exception e) {
            throw INVALID_INPUT.getException();
        }
    }

    // 중략
}

 

🚗 예외 처리한 내용과 정규 표현식


🔹코드를 작성하면서 유효성 검사와 정규 표현식에 대한 고민을 했다. 문제의 요구사항에는 자동차의 이름으로 한글, 스페이스 바 등의 입력이 가능한지 명시되어 있지 않았기 때문에 이런 부분은 개인적으로 판단해서 해결해야겠다고 생각했다.

 

예외 사항으로 체크한 항목

  1. 자동차 이름으로 가능한 것은 소문자와 대문자 영어, 한글만 가능하도록 했다. 보통의 자동차 이름은 현대, BMW와 같이 숫자, 스페이스바, 기타 기호가 들어가지 않기 때문에 앞에서 말한 값에 대한 예외가 발생하도록 처리했다. 이런 부분에 대해서 예외 처리를 함으로써 ,가 두번 들어가는 부분에 대해서도 처리가 가능했다. 이에 대한 정규 표현식은 아래와 같이 적용해 보며 활용했다.
  2. 각 자동차의 이름이 중복되지 않도록 했다. 최종 우승자가 동일한 이름을 갖는다는 것은 옳지 않다는 생각에 예외로 처리했다.
  3. 요구사항에 나와있던 입력이 5자 이하가 아닌 경우 예외가 발생하도록 했다.
  4. 시도할 횟수로 입력 가능한 값은 숫자로 변경이 가능한 값이여야 하기 때문에 다른 부분에 대해서는 예외로 처리했다.
  5. 시도할 횟수라는 것은 적어도 1번 이상의 시도는 한다고 판단했기 때문에 1보다 아래의 값이 들어온다면 예외가 발생하도록 했다.

💬 wrapper 클래스와 정적 팩토리 메서드


🔹 이번 미션에서는 CarName, CarNames, CarPosition, TryCount를 wrapper 클래스와 같이 만들었다. wrapper 클래스를 사용한다면 아래와 같은 장점을 갖는다. 이러한 장점을 이유로 wrapper 클래스를 사용했다.

 

🚧 의미 부여 : 이름을 통해 변수의 의미를 더 명확하게 전달할 수 있다.

🚧 유지보수성 : 코드의 변경이 필요한 경우, 해당하는 wrapper 클래스만 수정하면 된다. 이렇게 하면 코드 변경이 더 효율적이고 다른 부분에 미치는 영향을 최소화할 수 있다.

🚧 SRP : 객체 지향 설계 원칙 중 하나인 단일 책임 원칙(SRP)을 지키는데 도움이 된다. wrapper 클래스는 특정 데이터나 개념을 캡슐화하고 관리하는 역할을 수행하므로 단일 책임을 갖는다.

 

🔹 정적 팩토리 메서드의 경우 피드백을 통해 알게되어 활용했다. 정적 팩토리 메서드는 객체 생성을 위해 클래스의 인스턴스 생성자 대신 사용되는 정적 메서드이다. 이러한 메서드는 해당 클래스의 인스턴스를 반환하며, 주로 해당 클래스의 인스턴스를 생성하고 초기화하는 과정을 캡슐화하거나 다양한 생성 방법을 제공하는 데 사용한다. 정적 팩토리 메서드의 컨벤션을 지키고 이를 활용한다면 아래와 같은 장점을 갖기 때문에 이번 미션에 활용했다.

 

🚧 객체 생성의 캡슐화 : 객체 생성 로직을 클래스 내부에 숨기는 역할을 한다. 이로써 객체 생성에 필요한 복잡한 로직이나 초기화 코드를 숨길 수 있으며, 단순히 메서드를 호출하여 객체를 얻을 수 있다.

🚧 코드 가독성 : 이름으로 객체 생성의 목적을 더 명확하게 나타내므로 코드 가독성이 향상된다.

 


🧐 피드백 및 리뷰 내용

 

🧪 칭찬을 받았던 코드 내용


 

🧪 클래스의 응집성


➡️ 첫번째 피드백 내용이다. 이러한 피드백 내용에 따라 이번 미션은 응집도를 높이는 부분에 집중했고 객체간 응집도를 높이는 코드를 작성했다고 생각한다.

 

🧪 변수 네이밍


➡️ 두 번째 피드백 내용은 for문과 관련된 내용이었다. 

 

📸 참조