우아한 테크 코스 6기 2주차 프리코스 회고

Polla·2023년 11월 6일

우테코

목록 보기
3/7
post-thumbnail

우아한 테크 코스 2023년 6기 프리코스 2주차 회고


벌써 우테코를 시작한지 2주가 흘렀다!
거의 2주 내내 밤을 새며 우테코만 하고 있는 것 같은데
내가 우테코와 개발을 즐기지 않았다면 미쳤을 것 같다는 생각이 들었다ㅋㅋㅋㅋㅋㅋ
그럼에도 내가 진짜 개발을 좋아하는구나 싶어서 뿌듯했다.

1. 1주차를 제출하며... 공통 피드백을 분석해보자!


폭풍 같던 1주차가 지났다!
거의 매일 우테코만 하며 하루를 보냈던 것 같은데, 우스갯소리로 학교에서

우테코 디스코드에서 거의 살고 있다며??

소리를 듣기도 했다 ㅋㅋㅋㅋ
그래서 그냥 4주간 내 집이라고 하기로 했다.
실제로도 동거하는 새벽반 분들과 내적친밀감이 생겨 들어갈때마다 인사를 나누기도 했다.

목요일이 되니, 첫 공통 피드백이 주어졌는데


2주차 미션에서는 함수를 분리하고 테스트를 작성하는 것
우테코에서 주어지는 새로운 목표였다.

뭔가 레벨을 하나씩 올리는 것 같기도 하고?
게임을 클리어 할때마다 새로운 목표를 주는 것 같아 메일을 보는 재미도 있었다ㅋㅋ

이번 미션은 자동차 경주 였고 나는 기존 목표와 공통 피드백을 반영하고
기존에 코드리뷰를 하며 좋았던 기능 명세들의 특징을 잡아

와 같이 피드백을 정리한 기능명세서를 만들어 두고 미리 신경써야 할 점들을 공부 한 후
보면서 구현을 시작했다!



🚀 2. 나의 머나먼 피드백 반영기...



2-1. 새로운 README


이전 1주차 프리코스 회고 에서 표현했듯이,
정말 많은 분들께서 리뷰를 남겨주셨었고 이를 정리하고 학습하는 것에 약 3일간의 시간을 썼었다.

1주차 회고에

이후엔 후회할지 모르겠지만
리뷰를 끝까지 마무리하고 싶었고,
입학 설명회때 제임스 코치님께서 해주신 말씀이 떠올라서 우선 시도를 해보기로 했다.

라고 작성했는데,
다행히 오히려 피드백을 정리하고 README를 작성 하니
이를 보여 목표에 집중하여 코드를 작성해 볼 수 있었고 덕분에 늘 파일 속의 테스트 코드는 한번에 통과하여 요구사항을 잘 써놨구나 싶어 뿌듯하기도 했다 😊

다만 간과했던 점이 있었다.
1주차 프리코스를 맛보았으니 2주차는 좀 더 빠르게 구현이 가능할 것이라고 믿었는데

오히려 느낀 것은, 성장이 문제의 난이도 로부터 오는 것이 아니라

1주차의 피드백을 적용하며 새롭게 공부를하고,
공통 피드백의 커밋 메시지 컨벤션을 읽어보고 인터페이스를 만들어 보는 등

상호 리뷰를 받고 의견을 주고 받으면서 이를 코드에 수용하기 위해 공부하는 과정에서
성장하는 것
을 뼈저리게 느끼게 되었다

이에 2주차 리뷰를 받은 이후
와 같이 작성했던 것 같다.
리뷰를 해주시는 분들께서 꼼꼼히 해주시고 그리고 서로 성장하려는 마음이 합쳐져서
시너지를 내는 것 같다고 느꼈고 그런 마음을 적어보려고 했던 것 같다.
전해졌을까요..?


2-2. 커밋 메시지 컨벤션을 지켜보자!


우선 공통 피드백을 주요로 반영해보려고 했다.

학습은 우테코에서 주어진 AngularJS Git Commit Message Conventions 을 통해서 학습하고자 했다

간단하게 요약하자면 메시지의 형식을

<type> : 주제
<Blank>
<내용>
<Blank>
<footer>

와 같이 주자는 것인데,

... includes motivation for the change and contrasts with previous behavior

body에는 이전 행동과 대조를 해서 변화된 점을 작성하라고 적혀있었다.
footer에는 그에 대한 근거와 상세한 내용을 작성하라고 되어있었는데,

이 부분을 적용해서
2주차의 모든 commitfeat과 같은 type과 함께
어떤 점이 변화되었는지를 내용에 같이 담고
자 했고, 실제로 커밋 내용을 볼때도 협업을 할때
굉장히 편하겠다고 느꼈다.

한편으로는 commit 또한 리뷰하시는 분들 께서도 볼 수 있도록
자주 하기 보다는 신중히 해야겠다는 생각도 들었다!


2-3. Java Collection을 이용해보자!


1주차 리뷰를 받으며,
Stream을 사용하면 훨씬 편하다는 평을 많이 받을 수 있었다.

그래서 2주차 프리코스에서는 일급컬렉션도 적용해보고 이에 맞게 Collection
많이 이용해보자는 생각이 들었다.

    public List<String> findWinners() {
        int maxDistance = findMaxDistance();

        return cars.stream()
                .filter(car -> car.getDistance() == maxDistance)
                .map(Car::getName)
                .collect(Collectors.toList());
    }

    private int findMaxDistance() {

        return cars.stream()
                .mapToInt(Car::getDistance)
                .max()
                .orElseThrow(() -> new IllegalArgumentException(CARS_ARE_EMPTY));
    }

    public void randomMove(RandomGenerator randomGenerator) {
        cars.stream()
                .filter(car -> randomGenerator.isCanMove())
                .forEach(Car::moveCar);
    }
...
  
    private static void validateNameLength(List<String> names) {
        long countNames = names.stream()
                .dropWhile(name -> name.length() >= MINIMUM_NAME_LENGTH && name.length() <= MAXIMUM_NAME_LENGTH)
                .count();

정말 이것저것 시도해 본것 같다.
특히 dropWhile의 경우 찾아보면서도 처음 봐 실제로 사용해보기도 했는데
그러다 보니 더 간단하게 할 수 있는 것을 어렵게 구현하기도 한 것 같아 제출할때 조금 아쉽기도 했다. 🥹

2-4. 이름을 통해 의도를 드러내보자!


해당 피드백을 보며 개인적으로 InputOutput의 의도를 드러낼 방법을 정말 많이 고민했었다.
그러던 도중 머릿속에서 번뜩

input과 같은 class들은 이름만으로 input임을 알 수 있다면 굳이 클래스 이름을 가져오지 않아도 되지 않을까?

라는 생각이 스쳐 지나갔고 이와 관련해 찾아보던중
import static에 대해 알게 되었다.

public final class Input {

    public static final Pattern REMOVE_REGEX_PATTERN = Pattern.compile("\\s");
    public static final String DIVIDING_STANDARD = ",";
    public static final int MAXIMUM_NAME_LENGTH = 5;
    public static final int MINIMUM_NAME_LENGTH = 1;

    public static List<String> inputNames() {
        String name = Console.readLine();

        return devideToList(name);
    }

    public static int inputTrialAmount() {
        String trialAmount = Console.readLine();
        validateNotBlank(trialAmount);

        try {
            return Integer.parseInt(trialAmount);

        } catch (InputIllegalArgumentException e) {
            throw new InputIllegalArgumentException(InputError.MUST_BE_NUMBER);
        }
    }  

이에 우선 행동으로 옮겨 input~ 이라는 이름으로
"무엇을 받는다"는 것을 표현하였고

    public void startCarGame() {
        printMessage(OutputMessage.HOW_MANY_TIME);
        trialAmount = inputTrialAmount();
        printNewLine();
    }  

와 같이 사용하게 되었다!
개인적으로 Input.inputTrialAmount 처럼 중복이 되는 형식이 있는 것보다
보기 편하다고 느끼게 되었다.

물론 개인의 생각이라 리뷰를 받아보며 정리해봐야겠지만 그럼에도 스스로 생각했다는 것에
의의를 두기로 했다
내 칭찬은 내가! (멘탈 지켜 지켜)

2-5. 코드 리뷰를 하며....


한편으로는 코드 리뷰를 하며 좋다고 느낀 부분들은
적용해보려고 했던 것 같다.

1. String Format 사용해보기!

 public enum InputError {

    NEED_THREE_DIGIT("가 아닌 3자리의 숫자가 필요합니다."), 

기존의 나는 String + String과 같은 방식으로
문자열을 합쳐주고 있었지만 중간에 문자가 들어가는 경우에는

 public enum InputError {

    NOT("가 아닌"),  
  	NEED_DIGIT("자리의 숫자가 필요합니다.")

과 같이 끝없이 나누어야 한다는 단점이 있었다.
그러던 도중 String Format방식을 사용하는 코드를 보게 되었고 이를 2주차에 적용하게 되었다.
특히 이러한 방식은
2주차에 작성하는 Output매개 변수만 받고 이를 출력하는 행위만 하도록 작성하겠다!
는 나의 목표에 걸맞는 방식이기도 해서
사용하면서도 굉장히 뿌듯하기도 했다 😊😊


2. 일급 컬렉션 사용해보기!

코드 리뷰를 하며 많은 분들이
일급 컬렉션이라는 것을 많이 사용한다는 것을 알게되었다.

사실 처음 들어봤기도 했고
기본적으로 지식이 내 것으로 소화가 되어야 코드를 작성하는 버릇이 있어서
정말 관련된 글이란 글은 전부 읽어봤던 것 같다.

또한 🩵리뷰로도 정보를 달아주시는 분🩵 들이 계셔서 정말 많은 도움을 받아 감동했다..🥹🥹

실제 구글 검색 기록 중 일부....

이렇게 2주차에서는

public class Cars {

    private static final String CARS_ARE_EMPTY = "차가 존재하지 않습니다.";
    public static final String DISTANT_MARK = "-";

    private final List<Car> cars = new ArrayList<>();

    public Cars(List<String> carNames) {
        validateCanRace(carNames);

        for (String name : carNames) {
            cars.add(new Car(name));
        }
    }
  

과 같이 만들어볼 수 있었다!
직접 사용해보면서 로직을 한곳에서 Stream을 사용하면서 관리할 수 있어서
정말 편리하다는 생각이 들었다.

물론 여기서도 2주차 리뷰를 받으며 고쳐나가야 할 점들을 많이 느꼈지만
내 Cars가 뚠뚠해요
우테코가 아니었다면 이 시기에 알지도 써보지도 못했을 것 같아 사용하면서도 아 이래서
사용하는구나를 스스로 느끼면서 즐거웠다.

프리코스 라는 것이 서로가 맞는지를 확인하는 과정이라고 했었던 것 같은데,
개인적으로 정형화된 학습방식보다 훨씬 즐겁다고 여겨졌다.


3. Output에게 매개변수만 전달해보자!


개인적으로 당시 출력의 행위만 하려면 어떻게 해야하는가? 에 대한 고민을 하고 있었던 터라
생각했던 방식을 코드로 작성해보았다.


눈치 챘을지 모르겠지만 매개변수 의 개수로 나누어
행위를 나누고 이를 받아 출력하는 책임만 가지도록 작성해보았다.

생각보다 마음에 드는 결과가 나와서 솔직히 뿌듯했던 것 같다.
Map을 받는 경우에만 특정 로직에서만 사용이 가능할 것 같아 method이름을 다르게 줘보았다.

아직 리뷰 받아야 할 부분들은 많지만
온전히 스스로 고민하고 생각해서 만들어낸 결과물이라 우테코를 하길 정말 잘했다고 느낀 순간이었다.

😇 2-6. 소중한 리뷰어분들의 피드백 적용하기!


정말 많은 분들께서 리뷰를 남겨주셨었다.

1주차 회고에서 정리했듯이,

해당 부분들을 모두 적용해보려고 노력했다.

그러다 보니 정말 정말 어려움을 많이 느끼기도 했다.
습관에서 비롯된 점들이 많은 것도 그러했고 모르는 부분들이 상당히 많았다.😢


최대한 적용해보고 리뷰하는 분들도
해당 사실을 알 수 있도록 위와 같이 작성해보기도 하고

리뷰어 분들 덕에 다양한 시도를 해볼 수 있어서 정말 감사했다....

특히 1차 리뷰 당시 Regex 사용에 대해 알려주셨었는데

        if (!numbers.matches("[1-9]+")) {
            throw new InputException(numbers, InputError.MUST_BE_DIGIT);
        }  

를 사용하는 경우
성능이슈가 발생한다는 사실을 알게 되었다.

이후 이러한 답글을 달았었는데 이를 본 한 리뷰어께서 이를 다시 정리하여

String.matches는 왜 성능에 안 좋을까? 라는 제목의
글로 정리해주셨다.

이를 보며 이것이... 리뷰의 맛? 했던 기억이 난다.

이외에도
와 같이 스스로 생각할 기회를 던져 주신 분도 계셨는데,

2주차엔 이를 적용해서

public interface RandomGenerator {

    boolean isCanMove();
}
  

라는 interface를 만들어

 public class RandomNumberGenerator implements RandomGenerator {

    private static final int MIN_RANGE = 0;
    private static final int MAX_RANGE = 9;
    private static final int MAXIMUM_FORWARD_NUMBER = 4;

    @Override
    public boolean isCanMove() {
        int randomNumber = Randoms.pickNumberInRange(MIN_RANGE, MAX_RANGE);
        return randomNumber >= MAXIMUM_FORWARD_NUMBER;
    }
} 
  
// Application
  
        RandomGenerator randomGenerator = new RandomNumberGenerator();

        CarController carController = new CarController(cars, randomGenerator);

실제 구현 코드는 결과를 조작할 수 없도록 특정 움직임 조건을 맞는지만 반환하고
의존성도 RandomNumberGenerator만 가져가도록 했다면

테스트에서는

 public class RandomNumberGeneratorTest implements RandomGenerator {

    private int randomNumber;
    private static final int CAN_MOVE_MIN_NUMBER = 4;

    public RandomNumberGeneratorTest(int randomNumber) {
        this.randomNumber = randomNumber;
    }

    @Override
    public boolean isCanMove() {
        return randomNumber >= CAN_MOVE_MIN_NUMBER;
    }

} 

이와 같이 내가 원하는 번호를 주입할 수 있도록 만들어
실제 구현 코드에는 영향이 없는 테스트를 만들어 볼 수 있었다!

일부만 가져온 것이지
다른 분들께서도 코드까지 직접 작성하며 설명해주셨다....
내가 이런걸 받아도 되는걸까 싶을 정도로 정성이었다.

이 자리를 빌어 2주차를 좋은 방향으로 이끌어준 모든 리뷰어에게 감사를 표한다...🥹🥹

3. 그럼 이제 3주차를 위한 피드백을 정리해보자


아직 끝나지 않았다.
나에게는... 3주차가 있으니까!
리뷰어들 처럼 멋지게 개발하기 위해 피드백을 정리해보자!

  • 상수들도 접근 제어자를 신경쓰자!
  • 매직 넘버를 지양하자!
  • 객체에게 메시지를 던져 직접 요구해보자!
  • 함수의 네이밍에도 신경쓰자!
  • Exception은 던지고 있는 Exception으로 잡아주자!
  • record를 사용해보자!
  • 가독성을 위한 method 분리도 고려해보자!
  • @DisplayName 같은 어노테이션을 사용해보자!
  • 지역 변수로 호출도 고민해보자!
  • Stream을 사용하여 불변객체로 만드는것도 반드시 고려해보자!
  • 정적 팩토리 메서드를 고려해보자!
  • Console 에 println() 을 만들어 보기!

4. 마무리하며...


2주차 회고도 이렇게 끝이 났다!
함께 리뷰하고 함께 얘기하며 짧은 기간이지만 우테코를 통해서 많이 성장하는 것 같다.

당황스럽게도 나의 2주차 PR은 정말... 새로고침을 20번해야 들어가진다.

뒤에 /files 를 붙이면 내용으로 들어가져서 그나마(?) 수월하게 들어갈 수 있으니...
화난 유니콘을 마주한다면 해당 방법을 추천한다...
[자동차 경주] 장유진 미션 제출합니다.

우테코가 끝나면 이렇게 열심히
리뷰를 함께하고 의견을 나누던 분들이 흩어질까 벌써 그게 걱정이 되고 또 슬프기도 했다.
이런게.. 새벽감성?

아쉬움 없이 남은 기간도 최선을 다하고
함께 좋은 추억 좋은 성장을 쌓아가고 싶다! 모두들 화이팅입니다!

profile
트러블 슈팅 Blog => https://polla.palms.blog/home

4개의 댓글

comment-user-thumbnail
2023년 11월 6일

글 재밌게 읽었습니다! 피드백을 잘 정리해서 다음 미션에 적용하는 게 정말 좋은 학습 방법이라고 생각되네요. 저는 미션 요구사항 지키는 것도 힘든데... 대단하신 것 같습니다.

마지막 말을 듣고 보니 진짜 프리코스 얼마 안남았네요.. 하루 종일 미션 가지고 놀고 디코에 따봉 날리면서 놀았는데 끝나면 너무 아쉬울 것 같아요 ㅠㅠ 끝까지 화이팅입니다 👍👍

1개의 답글
comment-user-thumbnail
2023년 11월 8일

유진님의 글에서는 따수움이 느껴져서 좋아요... 추운 날엔 유진님 글 후후 불면서 봐야겠어..☕️☕️
보다가.. 어!! 내 얘기다!! 하고 반가웠던 커비22😋
이제 마지막주 같이 잘 달려봐용!!

1개의 답글