[레벨1] 사다리 게임 미션에서 배운 것들

yoondgu·2023년 3월 5일
0

원래 나는 새로운 경험에 대한 기록을 남기기를 즐겼던 것 같은데, 우테코에 들어와서는 되려 회고 글 하나 쓰기에도 커다란 부담을 느끼고 있다.

개인적으로 좋았던 점, 배운 점, 아쉬운 점을 기록해두고는 있다.
하지만 시간이 지난 뒤 나 자신은 다른 사람이나 다름 없음을 고려하면, 회고 또한 타인이 읽기 좋은 글로 쓰는 것이 베스트이기 때문에 지금 방식으로는 충분하지 못하다는 생각이 든다.

결국 당장의 부담을 극복하는 것이 급선무인 것 같다. 더는 미루면 안된다는 생각으로 지난 사다리 미션에서 주요하게 배운 것들, 앞으로 더 공부해야 할 것들을 미흡하더라도 빠르게 정리해보려고 한다.


사다리 미션

LEARNING FROM LADDER GAME ...

우아한테크코스 5기 백엔드 레벨1에서 진행한 두번째 미션으로,
게임 참여자 이름과 결과를 입력받아 사다리 게임의 결과를 확인할 수 있는 콘솔 프로그램을 구현하는 미션이다.
1단계에서는 사다리 게임 결과를 출력까지만 하도록 만들고,
2단계에서는 이름에 해당하는 결과를 검색하는 기능을 추가 구현하였다.

작성한 기능 목록 및 코드는 여기에서 확인할 수 있다.

또한, 기능 구현에 있어서 아래와 같은 프로그래밍 요구 사항이 주어졌다.

프로그래밍 요구 사항

  • 자바 코드 컨벤션을 지키면서 프로그래밍한다.
  • indent(인덴트, 들여쓰기) depth를 2를 넘지 않도록 구현한다. 1까지만 허용한다.
    • 예를 들어 while문 안에 if문이 있으면 들여쓰기는 2이다.
    • 힌트: indent(인덴트, 들여쓰기) depth를 줄이는 좋은 방법은 함수(또는 메서드)를 분리하면 된다.
  • 3항 연산자를 쓰지 않는다.
  • else 예약어를 쓰지 않는다.
    • else 예약어를 쓰지 말라고 하니 switch/case로 구현하는 경우가 있는데 switch/case도 허용하지 않는다.
    • 힌트: if문에서 값을 반환하는 방식으로 구현하면 else 예약어를 사용하지 않아도 된다.
  • 모든 기능을 TDD로 구현해 단위 테스트가 존재해야 한다. 단, UI(System.out, System.in) 로직은 제외
    • 핵심 로직을 구현하는 코드와 UI를 담당하는 로직을 구분한다.
    • UI 로직을 InputView, ResultView와 같은 클래스를 추가해 분리한다.
  • 함수(또는 메서드)의 길이가 10라인을 넘어가지 않도록 구현한다.
    • 함수(또는 메서드)가 한 가지 일만 하도록 최대한 작게 만들어라.
  • 배열 대신 컬렉션을 사용한다.
  • Java Enum을 적용한다.
  • 모든 원시 값과 문자열을 포장한다
  • 줄여 쓰지 않는다(축약 금지).
  • 일급 컬렉션을 쓴다.

미션을 제출하고, 현업에 종사중인 리뷰어님께 코드리뷰를 받아보면서,
아래와 같은 내용들을 고민하고 또 새로 생각해보게 되었다.

1. Enum은 언제 쓰면 좋을까

2. 원시값 포장과 복잡도

  • 모든 값들을 포장하려고 하다 보니, 2단계 미션에서는 비즈니스 로직을 위한 클래스 관계가 상당히 여러 겹의 계층으로 이루어져 너무 복잡해진 것은 아닐지? 고민이 되었다.
  • 가장 큰 원인은boolean 값을 표현하는 부분까지도 객체로 포장했기 때문이었는데, true/false 대신 도메인의 의미를 표현해주는 장점이 있어 이는 유지하고 싶었다.
  • 이에 대해 리뷰어님은 지금 미션에서는 내가 생각하는 방향이 적절할 수 있지만 개인 프로젝트, 팀 프로젝트를 넘어서 현업에 가게 된다면 객체 포장을 함으로써 복잡도가 올라가는 점을 인지해보기를 권장해주셨다!
    뭐든 극한으로 작업해보고, 중간을 찾아나가면서도 현업 관점으로 고려해보기도 잊지 말아야겠다는 새로운 배움을 얻은 것 같다.

3. 도메인을 정제된 형태로 뷰에 보내고 싶다면 컨트롤러에서 처리하자

  • 뷰에 보낼 도메인 데이터를 적합한 자료구조(예를 들면 map)로 바꾸는 것까지는 모델에서 해줘도 괜찮지 않나? 라고 생각했었는데,
    이번 미션에서 페어와 리뷰어를 통해 이 역시 뷰를 위한 로직을 모델이 하는 것이기 때문에 OCP 원칙이 깨진다는 것을 알게 되었다.
  • 만약 정제된 형태로의 변환이 필요하다면 이를 컨트롤러에서 해주기로 했다.

4. stream을 제대로 활용하자

  • 그동안은 stream을 다른 분들 코드에서 본 방식들만 어깨넘어 어떻게 알아가지고 겨우 써왔다.
  • 그래서 이번에도 stream으로 원하는 종류의 map 객체(예를 들면 linkedHashMap)를 만들 줄 몰라서 stream에서 외부의 map에 put을 해주는 방식으로만 로직을 짰었다.
  • 이에 대해 리뷰어님이 짚어주셔서 이번 기회에 Collectors.toMap()을 사용하는 법을 직접 찾아보게 되었다. 앞으로도 stream을 쓸 거면 제대로 쓸 수 있도록 공부해야겠다.

5. 불변 보장과 방어적 복사

  • Collections.unmodifableList가 정말로 완벽한 불변을 보장해주는 메서드라고 생각하고 의심 없이 사용해왔다.
  • 하지만 사실상 원본 객체에 접근할 수 있어 불변이 보장되지 않았고, add와 같은 메서드를 호출했을 때 예외를 발생시키기 때문에 예측 불가능한 코드를 만든다는 단점이 있었다. 그래서 아예 원본과의 연결을 끊는 방어적 복사 방식을 사용하게 되었다.
  • 이를 통해 자바 API에 대한 새로운 지식만 얻은 게 아니라, 제공된 API에 대해서도 의심하고 정확히 파악하려는 노력이 필요하다는 것을 알게 되었다.

6. 전통적인 null 처리 vs Optional 타입 사용

  • Optional 타입의 존재는 알고 있었지만 이것이 널 안정성을 위함이라는 것, 전통적인 null 처리를 대신할 수 있다는 것을 알게 되었다.
  • 아직은 언제, 왜, 어떻게 써야 하는지 경험적으로는 많이 체득하지 못했다. 하지만 널 안정성에 대해 찾아보며 조금씩 이해가 가기 시작해서 얼른 공부하고 싶어진 주제이다!!

7. 가장 작은 단위에서부터 시작해보자

  • 사다리 미션 피드백 강의에서 들은 하위 개념을 구현할 때, 상위 개념에 대해 너무 생각하면 문제가 생길 수 있다는 이야기가 인상 깊었다.
  • 물론 상황에 따라 in->out, out->in 방식 중 더 적합한 것이 있을 수도 있고, 이 두 방식을 핑퐁하듯이 사용할 수도 있다.

그 외에도 코드 리뷰를 통해서 "내가 모르는 것"을 많이 알 수 있었고, 나의 기술 부채 목록에 적립하고 있다.

다만 가장 개선하고 싶은 점은 요구사항과 설계에 대해 더 시간을 많이 투자해보면 좋겠다는 것, 예외 사항을 더 집요하게 생각보자는 것이다. 프리코스 때는 기능 목록도 최대한 원자화시켜서 오래 작성하던 버릇이 도움이 됐는데, 막상 본 과정에서는 마음이 조급한지 초심을 잃은 것 같다. 남은 미션에서는 좀 더 정확하게 파악하려고 노력하고 싶다.

사실 위 내용 외에도 처음으로 TDD를 시도해본 만큼 이에 대해서도 할 얘기가 꽤 있을 것 같다. TDD 관련해서는 별도로 정리해보아야겠다.
마찬가지로 1단계의 페어프로그래밍에서도 참 배운 게 많은데 이것도 다음에 별도 주제로 묶어서 써보아야겠다..^.^!

0개의 댓글