본문 바로가기
우아한테크코스 프리코스

우테코 6기 프리코스 2주 차 자동차 게임 회고

by 준형코딩 2023. 11. 2.

 

들어가면서

벌써 프리코스의 2주 차가 마무리가 되었다. 시작한 지 엊그제 같은데 벌써 절반의 과정이 지나갔다니 믿기지가 않는다. 앞으로 2주 차가 남았는데 배워야 할 것은 산더미 같고 갈수록 더 어려워질 난이도에 대한 걱정과 시간이 갈수록 더 잘하고 싶다는 욕심이 생겨서 자꾸 조바심이 들고 지치기도 한다. 하지만 목표를 프리코스를 통한 스스로의 성장에 두고 눈앞에 있는 과제들을 하나하나 해결해나가 보면 언젠가는 우테코 프리코스를 무사히 완주하고 성장한 나 자신을 볼 수 있을 거라고 기대한다! 곧 시작되는 3주차도 파이팅 해 보자!!! (같이 프리코스에 참여하고 계신 많은 분들도 조금만 더 같이 힘내봐요 파이팅!)

 

2주 차에 무엇을 공부했나?

 

1. 객체지향과 자바 기본기에 대해 더 공부하였습니다.

1주차 과제를 진행하면서 자바와 객체지향의 기본기가 많이 부족하다는 것을 깨닫게 되었고, 기본기를 더 연마하기 위해 우테코 1주차 피드백에 있던 안드로이드 과정의 캡틴 제이슨님이 진행해주신 숫자야구피드백강의를 듣게 되었습니다. 처음 시작하는 분들도 이해하기 쉽게 자바와 객체지향에 대해 설명을 해주셔서 기본기를 조금 더 다질 수 있었고, 더 깊이 있는 개념들을 이해하기 위해 2주차를 진행하면서 따로 '객체지향의 사실과 오해'라는 책과 '오브젝트'라는 객체지향 심화 서적을 읽으면서 객체지향에 대한 개념들을 확실하게 이해하고 코드에 적용하기 위해 노력을 하였습니다.

 

2. JAVA의 다양한 Map 자료형에 대해 공부하였습니다.

2주차 과제를 진행하면서, 자동차의 움직임을 저장할 수 있는 방법에 대해 고민하였고, 결국 자동차의 이름을 key로 관리하고 상태를 저장할 수 있는 자바의 Map 자료형을 이용하여 기능을 구현하기로 결정하였습니다. 현재는 List 자료형으로 이루어진 일급 컬렉션으로 대체하였지만, Map으로 자동차의 상태를 저장하는 기능을 구현해보면서 다양한 Map 자료형이 있다는 것을 알게 되었습니다. 특히, 자동차의 순서를 저장하기 위해 Map에 입력된 순서를 기억하는 LinkedHashMap을 이용하여 기능을 직접 구현해보면서, 다양한 Map의 차이와 장단점을 공부할 수 있었습니다.

 

3. 처음으로 코드에 대한 리뷰를 주고 받았습니다.

1주차가 끝나고 프리코스 커뮤니티를 통해 리뷰에 참여하게 되었습니다. 아무래도 많은 리뷰를 받고 싶다면 먼저 다른 분들에게 리뷰를 많이 드려야 한다고 생각했기 때문에 리뷰 모집글을 작성하고, 다른 분들이 올린 모집글에도 찾아가서 리뷰를 남기는 방식으로 리뷰를 주고받을 수 있었습니다. 먼저 다른 분들의 코드를 읽으면서 리뷰를 처음 남겨보게 되었는데, 생각지도 못한 방법으로 과제를 구현하신 분들이 많아서 많이 보고 배울 수 있었습니다. 특히 정규식을 통해 validation을 구현한 코드를 보고, 다음에는 제 코드에도 정규식을 공부해서 validation을 적용해보아야겠다는 생각을 하게 되었습니다. 그리고 다른 분들이 제 코드에 남겨주신 리뷰를 통해서도 많은 것을 얻을 수 있었습니다. 생각하지도 못했던 부분들에 대해 정성스럽게 피드백을 남겨주셨고, 특히 일급 컬렉션이 적용되지 못한 코드, 컨트롤러의 비대한 부분, 반복적인 코드에 대한 피드백이 2주차 과제를 수행하는데 많은 도움이 되었습니다. 이렇게 처음으로 리뷰에 참여해보면서 소통을 통해 함께 성장하는 것의 중요성과 혼자서 공부하는 것보다 더욱 빠른 속도로 성장할 수 있겠다는 것을 다시 한번 깨닫게 되었습니다.

 

+ 1주 차 리뷰

 

 

4. 일급 컬렉션에 대해 공부하고 코드에 적용하였습니다.

처음 2주차 과제를 수행할 때 일급 컬렉션에 대한 이해도가 부족한 상태에서 과제를 진행하다 보니 Map 자료형인 LinkedHashMap을 이용해서 자동차 전진 로직과 상태를 담당하게 하였습니다. 나중에 리팩토링을 통해서 클린 코드를 적용하는 과정에서 일급 컬렉션 형태로 LinkedHashMap을 생성하긴 하였으나, 일급 컬렉션의 장점인 final 접근 제어자를 통해 불변성을 가지기에 다른 곳에서 변경될 가능성이 없다는 장점을 살리지 못하였습니다. 또한 기존 코드는 다른 곳에서 자동차의 상태를 직접 변경하여 불변성을 가지고 있지 않고, validation을 여러 로직에 흩어진 상태로 진행하고 있었기 때문에 일급 컬렉션을 흉내만 내고 있다는 것을 깨닫게 되었습니다. 그래서 기존 코드가 LinkedHashMap을 이용해서 기능이 모두 구현된 상태였기에 수정을 위해 대대적인 리팩토링을 진행했고, 그 과정에서 일급 컬렉션에 대해서 제대로 공부할 수 있었습니다. 특히 흩어져 있던 validation 로직을 일급 컬렉션을 생성하면서 한 번에 할 수 있었고, 불변성을 가지고 있기 때문에 안정적인 코드를 작성할 수 있다는 장점을 체감할 수 있었습니다.

 

+ 일급 컬렉션을 적용한 CarNames

package racingcar.model;

import java.util.List;

public class CarNames {

    private final String CAR_NAME_ERROR_MESSAGE = "[ERROR] 5자리를 초과한 자동차 이름이 입력되었습니다.";
    private final List<String> carNames;

    public CarNames(List<String> carNames) {
        validateNameLength(carNames);
        this.carNames = carNames;
    }

    public List<String> getNames() {
        return this.carNames;
    }

    public void validateNameLength(List<String> carNames) {
        for (int i = 0; i < carNames.size(); i++) {
            if (carNames.get(i).length() > 5) {
                throw new IllegalArgumentException(CAR_NAME_ERROR_MESSAGE);
            }
        }
    }


}

 

 

5. Stream에 대해서 공부하였습니다.

2주차 과정에서 리팩토링을 진행하면서 기존 비즈니스 로직들은 대부분 for문을 사용해서 지저분하고 알아보기도 어려웠습니다. 그런 코드들을 리팩토링하기 위해 Stream에 대해 공부하고 직접 적용해 보면서 코드가 굉장히 간결해지는 경험을 했습니다. 복잡하게 짜여져 있던 for문들을 한줄이나 두줄을 통해 같은 결과값으로 구현할 수 있는 Stream의 위력을 체감했고, 앞으로 더 자유자재로 Stream을 활용할 수 있을 정도로 더 공부해야겠다는 생각을 했습니다. 그러나 최근 우테코 프리코스와 함께 공부하기 시작한 '이펙티브 자바' 서적에서는 Stream을 주의해서 사용하라는 내용을 보았고, 무조건적으로 Stream이 좋은 것이 아니라는 것을 알게 되었습니다. 그래서 어떤 상황에서 for문을 대체해서 Stream을 사용해야 하는지에 대해 더 깊이 있는 공부를 해야겠다는 생각을 했습니다.

 

 

+ for문을 활용하여서 생성한 List<Car> cars - 전

List<Car> cars = new ArrayList<>();
for (String carName : carNames) {
    Car car = new Car(carName);
    cars.add(car);
}

 

+ Stream을 활용하여서 생성한 List<Car> cars - 후

List<Car> cars = carNames.stream().map(carName->new Car(carName)).collect(Collectors.toList());

 

 

6. TDD에 대해서 공부하고 코드에 적용시켜보았습니다.

이번 주차에서 핵심 목표로 잡았던 TDD였기에, TDD에 대한 부족한 이해도를 높이기 위해 유튜브에 있는 포비님의 문자열 계산기 TDD 강의를 따라서 코드를 작성해보기도 하고 우테코 선배님들의 테코톡을 보면서 TDD에 대한 개념들을 정리할 수 있었습니다. 이런 학습을 바탕으로 2주차 과제가 시작되기 전인 수요일에 미리 1주차 과제를 제출하고, 1주차 숫자야구의 코드를 TDD로 리팩토링해보는 연습을 하면서 TDD 코드에 익숙해지려고 노력했습니다. 그렇게 목요일에 2주차 과제가 공개되자 연습했던 TDD 방식으로 2주차 과제에 참여하게 되었습니다. 처음에는 테스트 코드를 먼저 작성하고 기능을 구현하는 것이 생소하고 어렵게 느껴졌지만, 나중에 controller에서 TDD 방식으로 이미 안전하게 구현된 메소드들이 조합되는 과정에서 오류 하나 없이 한 번에 조립이 되는 것을 보고 TDD의 위력을 느낄 수 있었습니다. 하지만 리팩토링을 진행하면서 일급 컬렉션 적용이 잘못되어 기존 로직을 크게 바꾸어야 하는 상황이 발생하자 이런 상황에서는 테스트 코드도 수정을 해야하고, 실제 기능 코드도 수정을 해야 했기에 2배의 노력이 들어가는 힘든 경험을 하게 되었습니다. 그러다가 우테코 선배님이 TDD에 대해 발표해주신 테코톡에서 리팩토링을 진행할 때 기존 테스트가 깨지게 된다면 TDD를 제대로 작성한 것이 아니라는 말씀을 떠올리게 되었고, 더욱 더 TDD와 테스트 코드에 대한 숙련도를 올려야겠다는 다짐을 하게 되었습니다.

 

+ 참고한 강의(1.문자열TDD, 2. 피카의 TDD와 단위테스트, 3. 제이의 단위 테스트 4. 손너잘의 테스트 코드 최적화 여행기)

https://www.youtube.com/watch?v=rEkPAfZw41o

https://www.youtube.com/watch?v=3LMmPXoGI9Q&t=90s

https://www.youtube.com/watch?v=mIO4Rbe_M74

https://www.youtube.com/watch?v=N06UeRrWFdY

 

7. Junit의 assertThat과 assertj의 assertThat의 차이에 대해서 공부하였습니다.

2주 차부터 본격적으로 테스트 코드를 작성해 보면서 기존에는 Junit의 assertThat을 사용해서 테스트 코드를 작성하였는데 2주 차 테스트 코드에 대한 가이드에 assertj의 assertThat을 사용하는 것을 보고 둘의 차이에 대해서 공부를 하게 되었습니다. 그 과정에서 Junit의 assertThat보다 assertj의 assertThat이 확장성과 가독성이 더 좋아서 생산성을 향상시킬 수 있다는 것을 알게 되었고 앞으로는 assertj의 assertThat을 활용해서 테스트 코드를 작성해야겠다는 생각을 하게 되었습니다.

 

 

아쉬웠던 점

1. 단위 테스트를 작성하였지만 application 통합 테스트를 작성하지 못하였습니다.
2. 자동차들의 전진 기능을 구현하면서 테스트 코드에서 결과값을 알 수 없는 내부의 createRandomNumber 같은 메소드들이 있을때 내부의 결괏값을 예측하거나 Mock을 통해 생성한 정확한 테스트 코드를 완성하지 못했습니다.
3. TDD를 이용해서 2주 차를 진행하기는 하였지만 중간에 리팩토링을 하는 과정에서 끝까지 TDD를 통해 과제를 진행하지 못하였습니다.
4. 과제를 진행하면서 너무 많은 리팩토링을 진행하였습니다. 그 과정에서 커밋이 100개가 넘어가게 되었습니다. 3주 차에는 조금 더 설계를 탄탄하게 하여서 리팩토링을 줄여보고 싶습니다.

 

 

3주 차의 목표

1. 이번에 켄트 백의 테스트 주도 개발 서적과 실용주의 단위 테스트라는 테스트 관련 서적들을 구매하게 되었습니다. 이 서적들을 공부하면서 TDD 개념과 테스트에 대한 이해도를 높여서 3주 차에는 더 탄탄한 테스트를 작성하는 것이 목표입니다.
2. Mock에 대해서 공부하여서 예측할 수 없는 결괏값이 있을때 그런 결괏값을 대체하여 테스트코드를 작성할 수 있는 방법에 대해서 공부할 것입니다.
3. 설계를 더 탄탄하게 해서 리팩토링 개수를 줄여보고 싶습니다.
4. 남는 시간에 반복적으로 과제를 수행해서 과제 수행 시간을 줄일 것입니다.
5. 아직 익숙하지 못한 클린 코드와 객체지향 개념들에 더욱 익숙해질 수 있도록 꾸준하게 관련 서적을 조금씩 읽으면서 공부하고 실제 코드에 적용시켜보고자 합니다.

 

+ 구매한 서적들

 

끝으로

2주 차에 목표하였던 MVC 패턴, 클린 코드, 객체지향 5원칙, TDD를 공부하고 적용해 보기 시작했고 특히 가장 핵심으로 여겼던 TDD를 구현해 보면서 TDD를 왜 사용해야 되는지 직접 경험을 통해서 체감하게 되었고 TDD를 더욱 깊이 있게 공부를 해보아야겠다는 생각을 가지게 되는 2주 차였습니다. 그리고 프리코스를 진행하면서 마주쳤던 이해가 되지 않았던 코드들의 해답을 자바나 객체지향 관련 서적에서 발견하게 되면서 기존에는 지루하게 느껴졌던 이론적인 내용들이 실제 코드를 짜면서 고민했던 경험들과 만나 굉장히 즐거워지기 시작했습니다. 그래서 남은 프리코스 3주 차 4주 차 동안 더 깊이 있는 객체지향과 테스트 코드, 자바에 대한 이해도를 높이고자 다양한 서적들을 구매하게 되었고 남은 기간 동안 더 열심히 몰입해서 코드를 짜고 서적을 읽으면서 실력을 끌어올려야겠다는 결심을 하게 되었
습니다. 

 

+ 2주 차 자동차 경주 풀리퀘스트

https://github.com/woowacourse-precourse/java-racingcar-6/pull/1319