나를 기록하다
article thumbnail
반응형

우아한테크코스 2주차 - 자동차 경주

정신없던 우아한테크코스 1주차 미션이 끝나고 2주차 미션으로 자동차 경주를 안내받았다. 이전 과제들을 풀어본 경험이 없기에 새로운 마음으로 처음 구현해보는 내용이었다. 1주차 미션에서 피드백으로 받았었던 매직 넘버의 상수화, 메서드명 줄여쓰지 않기, 일급 컬렉션 적용, 중복 로직 제거를 적용하고자 노력하였고, 내가 부족했던 부분인 스트림과 람다를 공부하기 위해 각종 레퍼런스를 참고하며 공부하였으며 현재는 모던 자바 인 액션을 읽고 있다. 이번 회고에는 내가 2주차 미션을 수행하면서 하였던 고민과 구현 과정에 대해 상세히 기록하고자 한다.


요구사항

초간단 자동차 경주 게임을 구현한다.
- 주어진 횟수 동안 n대의 자동차는 전진 또는 멈출 수 있다.각 자동차에 이름을 부여할 수 있다.
- 전진하는 자동차를 출력할 때 자동차 이름을 같이 출력한다.
- 자동차 이름은 쉼표(,)를 기준으로 구분하며 이름은 5자 이하만 가능하다.
- 사용자는 몇 번의 이동을 할 것인지를 입력할 수 있어야 한다.
- 전진하는 조건은 0에서 9 사이에서 무작위 값을 구한 후 무작위 값이 4 이상일 경우이다.
- 자동차 경주 게임을 완료한 후 누가 우승했는지를 알려준다.
- 우승자는 한 명 이상일 수 있다.
- 우승자가 여러 명일 경우 쉼표(,)를 이용하여 구분한다.
- 사용자가 잘못된 값을 입력할 경우 IllegalArgumentException을 발생시킨 후 애플리케이션은 종료되어야 한다.

 

입력

  • 경주할 자동차 이름(이름은 쉼표(,) 기준으로 구분)
prao,faker,dobi,chovy
  • 시도할 횟수
5

 

출력

  • 각 차수별 실행 결과
prao : -
faker : ---
dobi : --
chovy : ----
  • 단독 우승자 안내 문구
최종 우승자 : chovy
  • 공동 우승자 안내 문구
최종 우승자 : prao, chovy

 

실행 결과 예시

경주할 자동차 이름을 입력하세요.(이름은 쉼표(,) 기준으로 구분)
pobi,woni,jun
시도할 회수는 몇회인가요?
5

실행 결과
prao : -
faker : 
dobi : -
chovy : -

prao : --
faker : -
dobi : -
chovy : --

prao : --
faker : -
dobi : -
chovy : ---

prao : ---
faker : --
dobi : --
chovy : ---

prao : ----
faker : --
dobi : --
chovy : ----

최종 우승자 : prao, chovy

 

추가된 요구 사항

요구사항
indent(인덴트, 들여쓰기) depth를 3이 넘지 않도록 구현한다.
3항 연산자를 쓰지 않는다.
함수(또는 메서드)가 한 가지 일만 하도록 최대한 작게 만들어라.
JUnit 5와 AssertJ를 이용하여 본인이 정리한 기능 목록이 정상 동작함을 테스트 코드로 확인한다.

고민했던 내용

유효성 검사의 위치

어디서 유효성 검사를 하는 것이 좋을까에 대한 고민을 했다. 1주차 미션에서는 Validator를 구현하여 컨트롤러에서 InputView를 호출하여 값을 받아올 때 유효성 검사를 할 수 있도록 구현하였다. 개인 공부와 스터디를 통해 일급 컬렉션의 장점에 대해 알게 되었고, 이번 미션에서는 일급 컬렉션을 적용하여 비즈니스 로직을 가지고 있는 모델에서 값을 생성할 때 자체적으로 유효성 검사를 수행하여 요구사항을 만족하는 값만을 저장할 수 있도록 하였다.

 

View의 역할

화면을 담당하는 View의 역할 또한 고민했다. 1주차 미션에서는 그저 CLI에 보여지는 화면만을 담당한다고 생각하고 구현했는데 코드 리뷰 및 다른 분들의 코드를 살펴보니 다들 View에서 간단한 유효성 검사를 실시하는 것을 추천하였다. 그러한 이유로는 뷰에서 확인할 수 있는 요구사항에 올바르지 않은 입력값(null이나 공백 등) 등을 입력했을 때 Model을 거치기 전에 걸러낸다면 보다 효율적이기 때문이다. 나도 이런 의견에 동의하였고, 이번 미션에서는 View에서 자동차 이름 입력에서 null 검사, 시도할 횟수 입력에서 null 검사와 숫자 여부 검사를 통해 올바르지 않은 값을 입력했을 경우 바로 예외 처리를 하고 예외 메시지를 띄울 수 있도록 구현했다.

 

객체의 책임

객체의 책임에 대해서는 객체지향의 사실과 오해라는 책을 읽고 나서부터 항상 고민했던 문제다. 객체지향이란 객체와 메시지로 구성되고, 객체가 다른 객체에게 메시지를 전송하여 메시지를 받은 객체와 협력하여 업무를 수행해간다. 따라서 이번 과제에서 내가 만든 각 객체의 책임은 다음과 같다.

 

  • 자동차(Car)
    • 책임: 랜덤 값이 4 이상이면 위치를 전진(+)하고 아닐 경우 정지(0)한다.
    • 정보: 이름(name), 위치(position)
  • 경주에 참가하는 자동차들(RacingCars)
    • 책임: 자동차 이름 배열을 입력받아 검증을 거친 후 자동차 타입의 배열로 변환한다.
    • 구성: List<Car> cars(자동차 타입의 배열)
    • 기능
      1. 최종 우승자 찾기
      2. 가장 많이 이동한(위치값이 가장 높은) 자동차의 위치 구하기
      3. 문자열 자동차 이름 배열을 자동차 타입(Car)으로 변환하기
    • 유효성 검사
      1. 자동차의 최소 개수보다 적은 회수가 입력 되었으면 예외 처리(`IllegalArgumentException`)
      2. 자동차의 이름 양식(영문 알파벳만으로 구성)에 맞지 않으면 예외 처리(`IllegalArgumentException`)
      3. 자동차의 이름 최대 길이보다 길면 예외 처리(`IllegalArgumentException`)
      4. 자동차의 이름이 중복되면 예외 처리(`IllegalArgumentException`)
자동차 리스트 정보를 알고 있는 RacingCars에게 자동차 리스트 정보가 필요한 기능들은 RacingCars 내부에 구현하였다.
  • 무작위 값 생성기(RandomValueGenerator)
    • 책임: 정해진 범위 안(0 ~ 9) 무작위 값 생성
  • 입력뷰(InputView)
    • 책임: 입력 화면 담당 및 간단한 유효성 검사
    • 유효성 검사
      1. 경주 할 자동차 이름 입력
        1. null 입력 시 예외 처리(`IllegalArgumentException`)
      2. 시도할 횟수 입력
        1. null 입력 시 예외 처리(`IllegalArgumentException`)
        2. 숫자가 아닌 값을 입력할 경우 예외 처리(`IllegalArgumentException`)
        3. 0을 입력할 경우 예외 처리(`IllegalArgumentException`)
  • 출력뷰(OutputView)
    • 책임: 실행 결과 출력
    • 기능
      1. 위치(position)값만큼 자동차의 실행 결과에 "-" 출력
      2. 최종 우승자 출력
  • 자동차 경주 컨트롤러(RacingCarController)
    • 책임: 뷰와 도메인 연결
    • 기능
      1. 입력 받은 자동차 이름의 개수만큼 자동차 생성
      2. 입력 받은 횟수만큼 게임(라운드) 진행
      3. 위치를 비교하여 우승자 선정
      4. 출력뷰를 통해 우승자 출력
  • (Enum)에러 메시지(ErrorMessage)
    • 에러 메시지를 관리하는 Enum 클래스
  • (Enum)게임 조건(GameCondition)
    • 매직 넘버를 모은 게임 조건을 설정하는 Enum 클래스
  • (Enum)정규표현식(RegexPattern)
    • 사용되는 정규표현식을 모은 Enum 클래스
  • (Enum)기호(Symbols)
    • "-", "," 등 게임에 사용되는 기호를 모은 Enum 클래스

수요일에 과제를 제출하고 오늘부터 다른 분들의 PR을 확인하고 있는데 아무래도 전공자도 많고 우아한테크코스는 잘하시는 분들이 많기에 현타가 많이 왔다. 부족한 점이 많지만 빠르게 보충해야할 부분부터 기재하겠다.

 

아쉬웠던 부분

빈약한 테스트 코드

아직 Junit과 AssertJ에도 익숙하지 않은데 Mock, Mockito 등을 활용할 방법을 제대로 학습하지 못해 테스트 코드도 많이 부실하다. 3주차 과제를 진행하기 전에 다른 분들의 PR을 참고하고 기타 레퍼런스를 통해 공부하면서 다양한 테스트 코드를 작성하는데 익숙해지는게 목표다.

 

디자인 패턴에 대한 이해

MVC 패턴을 적용하여 사용하지만 다양한 디자인 패턴에 대한 공부가 부족한 것을 느꼈다. MVC 패턴을 꼭 사용하라는 요구사항이 없었음에도 불구하고 적절한 이유를 생각하지 않고 MVC 패턴에 종속된 설계를 한 것 같다. 많은 분야에서 사용되고 있는 패턴이지만 설계를 할 때 항상 이유를 생각하고 설계를 해야 좋은 설계가 나올 수 있을 것이라 생각한다.

 

스트림과 람다

자바 8 이전과 이후는 크게 달라졌다. 그중에서 큰 비중을 차지하는게 바로 스트림과 람다다. 프리코스 이전에는 스트림과 람다에 대해 대충은 알고 있었지만 꼭 필요한지에 대한 의문이 있었고, 필요성을 못느끼다보니 공부를 제대로 하지 않았었다. 프리코스를 진행하면서 스트림과 람다가 성능적으로도 우수하고, 가독성 면에서도 훨씬 뛰어나다는 것을 보고 사용하면서 느낄 수 있었다. 지금 보고 있는 책인 모던 자바 인 액션이 많은 분들의 추천도 있었고, 스트림과 람다를 공부하기에 적합한 책이기에 3주차 미션에서는 더욱 잘 활용할 수 있도록 정독하고자 한다.

 

컨벤션의 필요성

프리코스는 혼자 수행하는 개별과제이기에 크게 못느낄 수 있어도 나중에 협업을 한다면 컨벤션이 정말 중요하다. 나는 깃 컨벤션과 자바 코딩 컨벤션을 지키며 개발을 하고자 생각했는데 깃 외에도 다양한 부분에 컨벤션이 존재한다는 것을 알게 되었다. 변수, 생성자, 메서드 순서에도 다 컨벤션이 있기에 앞으로 진행할 미션과 개발에서는 컨벤션을 항상 생각하며 개발을 할 계획이다.

 

확장성과 메서드 분리

확장성과 메서드 분리는 정말 계속해서 고민해야 하는 부분이다. 어디까지 확장해야 하는가, 확장성을 어디까지 고려해야 하고, 클래스를 어디까지 분리해야 하는가에 대한 고민을 계속해서 하고 있지만 명확히 정답을 내리지 못했다. 다른 지원자들의 코드를 보면 어떤 사람은 클래스가 20개가 넘는 사람도 볼 수 있었다. 어떤게 좋은 코드이고 어떤게 올바른 코드일까? 요구사항에도 명시되어 있듯이 '초간단 게임'인데 말이다. 이 고민은 남은 미션과 앞으로의 개발을 진행하면서 계속 함께해야 할 고민이라 생각한다. 무조건적인 클래스 생성은 지양하되, SOLID 원칙을 최대한 지켜가면서 하나의 객체가 하나의 책임을 질 수 있게끔 설계하고, 객체와 객체의 협력은 메시지로 이어질 수 있게끔 설계할 수 있도록 노력하겠다.


회고

우여곡절을 겪으며 2주차도 지나갔다. 항상 목요일마다 다른 지원자들의 코드를 보며 현타를 느끼는 시간이 찾아온다. 저렇게 잘하는 사람들은 왜 취업을 안하고 교육을 들을려고 할까, 요즘 취업시장이 얼었다던데 그만큼 힘든가, 얼마나 공부를 더해야 할까 등등... 아무래도 컴퓨터공학과를 다니며 취업을 바라보는 학생이 아닌 비전공자로 취업을 준비하다보니 이런 걱정들이 더 찾아오는 것 같다. 배움은 즐겁지만 시간은 한정적이다. 프리코스는 적당히 독학으로 경쟁 없이 하루 분량을 채워가며 공부를 하고 있던 나에게 열정을 심어준 좋은 계기가 되었다고 느낀다. 이번 미션 PR도 2300개가 넘는 것을 보니 경쟁률은 약 30대 1정도라 생각하는데, 솔직히 이렇게 쟁쟁한 지원자들 사이에서 합격을 할 수 있을 지는 모르겠지만 프리코스를 완주만 하더라도 나의 개발 인생에 큰 도움이 되는 건 확실하다. 프리코스 이후에는 다시 독학을 하겠지만, 이제 어떤 식으로 개발을 해야할지, 코드를 작성할 때 어떤 고민을 해야하고 모든 코드에는 이유가 필요하다는 것을 배웠다. 남은 2주도 최선을 다해 후회없이 몰입하고 이 과정이 끝난다면 밀려있는 인프런 강의를 열심히 들어야겠다.

반응형
profile

나를 기록하다

@prao

포스팅이 좋았다면 "좋아요❤️" 또는 "구독👍🏻" 해주세요!

profile on loading

Loading...