[우아한테크코스 백엔드 5기] "다리 건너기" 회고

SJ H·2022년 11월 22일
0

우아한 테크코스

목록 보기
5/5
post-thumbnail

🎯미션 - 다리 건너기

다리 건너기 미션 깃허브
과제 제출 코드


🚀 구현 기능

🖋입력값 세팅(입력 받을 시 최소한의 예외 처리)

  • 다리 생성 값 입력
    • 입력 값이 숫자인지 검사
      • 숫자가 아니라면 에러 출력한 후 반복
  • 커맨드 값 입력
    • 플레이어 이동 값 입력
      • 입력 값이 알파벳 대문자인지 검사
        • 알파벳 대문자가 아니라면 에러 출력 후 반복
    • 재시작 또는 종료 값 입력
      • 입력 값이 대문자 알파벳인지 검사
        • 알파벳 대문자가 아니라면 에러 출력 후 반복

🕹 사다리 게임

  • 다리 생성
    • 입력 값의 길이를 가지는 다리 생성
      • 입력 값이 3 이상 20이하인지 검사
        • 조건과 다를 경우 에러 출력 후 반복
    • 'BridgeMaker' 를 이용해 무작위 값 받기
    • 생성된 값을 토대로 다리 생성
  • 플레이어 이동
    • 이동 값 받기
      • 'U' 또는 'D' 인지 검사
    • 입력 값에 따라 이동
      • 이동 가능
        • 'O' 를 표시후 현재까지의 결과 출력
        • '이동 값 받기'를 반복
      • 이동 불가
        • 'X'를 표시 후 현재까지의 결과 출력
        • '재시작 또는 종료' 수행
  • 재시작 또는 종료
    • 결과 값 받기
      • 'R' 또는 'Q' 인지 검사
    • 'R' 일 경우
      • '플레이어 이동' 수행
    • 'Q' 일 경우
      • 게임 종료

🖨출력

  • 게임 시작
    • "다리 건너기 게임을 시작합니다." 출력
  • 다리 길이 입력
    • "다리의 길이를 입력해주세요." 출력
    • 잘못된 값을 받았을 때
      • 입력 시 예외 처리 : "[ERROR] 다리의 길이는 자연수여야 합니다." 출력
      • 입력 후 예외 처리 : "[ERROR] 다리 길이는 3부터 20 사이의 숫자여야 합니다." 출력
  • 이동 값 입력
    • "이동할 칸을 선택해주세요. (위: U, 아래: D)" 출력
    • 잘못된 값을 받았을 때
      • 입력 시 예외 처리 : "[ERROR] 커맨드는 대문자 알파벳으로 입력해야 합니다."
      • 입력 후 예외 처리 : "[ERROR] 안내문을 참고해 올바른 커맨드를 입력해주세요." 출력
  • 재시작 또는 종료

    • "게임을 다시 시도할지 여부를 입력해주세요. (재시도: R, 종료: Q)" 출력
    • 잘못된 값을 받았을 때
      • "[ERROR] 커맨드는 대문자 알파벳으로 입력해야 합니다." 출력
      • "[ERROR] 안내문을 참고해 올바른 커맨드를 입력해주세요." 출력
  • 결과 출력

    • "최종 게임 결과" 출력
    • 게임 결과 출력
    • 게임 성공 여부 출력
    • 시도 횟수 출력

🪶후기

📚집중하려 했던 것

  1. 이번 주차 학습 목표인 클래스 분리를 지속적인 리팩터링을 통해 이루어내기
  2. 1~3주차 피드백의 내용을 모두 지킬 수 있게 코딩
  3. 제출날 23시 59분까지 한 시도 빠짐없이 작성한 코드가 좋은 코드인지 고민

🥳소감

1. 피드백 지키기

1주차 공통 피드백부터, 3주차 공통 피드백까지 모든 피드백을 공책에 하나하나 적으며 피드백 내용을 아예 지키지 않은 내용은 없는지 확인해가며 과제를 했던 것 같습니다. 클린 코드와 객체 지향 생활 체조 원칙등을 적용하려 노력하지 않아도, 피드백과 요구사항만을 지켜도 충분하다고 느꼈기 때문입니다. 1주차마다 계단을 점프해서 넘는 것 같이 실력이 올라갔다고 생각합니다.

2. 마지막 주차의 목표

이번 주차도 요구 사항을 잘 지키는 것을 많이 신경썼습니다. 요구 사항이 더 다양해진 것도 있고, 이번에는 패키지 수정이나, 상태를 변경하지 못하는 클래스들도 추가되었기 때문입니다. 코수타에서 준님이 '저번주보단 어렵지 않을 것이다.' 라고 해서 정말 그럴까? 는 생각을 했는데, 막상 오늘 마무리를 짓고 나니 틀린 말씀을 하신건 아닌 것 같아요.

제가 느끼기엔, 1, 2, 3주차 과제를 진행하면서 배운 것들을 잘 복기해본다면 구현 자체는 어렵지 않게 할 수 있었던 것 같아요. 애초에 추가된 요구 사항이 파라미터 3개 제한, 메소드 라인 10줄이하밖에 없었기 때문에, 새로 공부해야 하는 것들은 없었죠.

의도하신건지 모르겠지만, 추가적으로 더 학습하지 않아도 충분히 구현이 가능했습니다. 메일에 보내신 이번 주 목표가 클래스 분리, 리팩터링인 이유가 있구나..싶었어요.

새로 공부해야 하는건 없었지만, 사실 메소드 라인 10줄 이하는 쉽지 않았어요. 잘못된 입력을 받았을 시 에러를 출력하고, 그 부분부터 다시 반복하는 부분때문에 처음 구현할 때는 10줄이 넘는 코드가 간간히 보였습니다. 특히 다리를 한칸 씩 이동하는 부분에선, 입력 값을 잘못 입력해도 반복하고, 성공 시에도 반복해야 했기에 이 부분을 어떻게 줄여야 하지? 더 좋게 만들 수 있을까? 라는 생각을 많이 한 것 같아요.

3. 리팩터링

기본적인 구현 자체는 빠르게 끝났지만, 요구 사항에 안 맞는 것들도 다수 있었고, 클래스 분리, 함수 분리를 더 많이 할 수 있어 보여서 잘 때도, 통학하면서도, 학교 수업을 들으면서까지 계속 고민했습니다. 매주 했던 고민이지만, '한 가지의 일만 하는 것'과 '한 가지의 기능을 하는 것'을 어떤 기준으로 나눠야 할까? 가 이번 과제에서 저희가 배우길 바라는 핵심이라고 생각했습니다.

제대로 리팩토링을 시작하고 나서는, 그 전의 코드와 비교 했을 때 길이도 그렇고, 분리도 더 깔끔하고 명확하게 하는 것을 목표로 학습했습니다.

- 예외 처리 로직

예외 처리 부분은 view(입력 받는 부분)과 그 이후를 구분 지었는데, 입력 받는 부분에서 해줄 최소한의 예외 처리가 있고, 그 이후에 프로그램에서 할 예외 처리가 나뉜다고 판단했기 때문입니다. 가령 이번 과제의 입력 값은 다리 길이, 이동 커맨드, 재시작 커맨드 3개 였습니다.

다소 억지스러울 수 있지만, 나중에 다리 길이를 4, 20 이런 숫자가 아니라, "four", "twenty"로 받을 수도 있습니다. 결과적으로 입력 받는 길이의 범위는 같아도, 입력을 숫자가 아니라 문자로 받을 수도 있을겁니다.

그러므로, 어떤 입력 값을 받을지는 입력 부분에서, 그 값의 검증은 프로그램 안에서 확인하는 것으로 나눴습니다. 커맨드도 마찬가지로, 이동 커맨드가 "U", "D"가 아니라 "L", "R"로 바뀔 수도 있습니다. 검증할 때 "대문자 알파벳"인 것은 확정되어 있고, 그 다음에 뭔지 검증하는 거죠.

그래서 최소 검증, 프로그램의 요구 사항에 맞는 검증으로 나눠 로직을 짰습니다. 그런데, 입력 받는 부분과 실제 프로그램을 실행하는 부분이 같이 있으니 코드도 보기 힘들고, 더 명확하게 나누기 위해 전반적으로 게임을 관리하는 컨트롤러를 두 개로 나눴습니다. 나누고나니, 각각의 컨트롤러가 어떤 부분을 담당하는지 명확해지고, 그에 맞는 기능만 있으니 보기도 편하고 더 깔끔해보였어요.

- domain 파트

도메인 부분은 리팩토링 전, 후의 차이가 가장 큽니다. 처음에는 BridgeGame, ProgressMap밖에 없었지만, 게임 커맨드를 담당하는 command 패키지, Bridge라는 일급 컬렉션 객체, 게임의 상태를 나타내는 State와 한 번 움직였을때의 결과를 만들어주는 MoveResult가 추가되었죠.

각각의 기능을 나눌 수 있겠다는 생각 때문인 것도 있지만, 3주차 피드백 중 필드(인스턴스 변수)를 최대한 줄여라, 라인 수를 10라인 이하로 줄여라는 요구사항이 크게 작용한 것 같아요. 굳이 이 필드가 필요한가?? 이건 하나의 기능을 하는 게 맞을까? 라는 생각을 많이 하게 되어 그런지 자연스레 잘 나눌 수 있던 것 같습니다.

- State enum class

처음 게임이 반복되는 로직의 문제가, while문을 사용하다보니 반복을 멈추는 로직이 필요하고, 그러다보니 굳이 만들어야 할지 모르는 메서드들도 작성하게 되었습니다. State를 만들게 된 이유가, State enum 클래스를 통해 상태를 관리하면, 의미 없는 메서드와 코드를 없앨 수 있어 만들게 된 것입니다. 덕분에 왜 이 조건일 때 반복을 멈추는지, 지금 게임이 어떤 상태인지 더 직관적이게 변해서 가독성도 더 좋아졌습니다.

- command Package

command 패키지 안을 잘 보면 MoveCommand, BranchCommand로 나뉩니다. 둘이 같은 게임 커맨드인데, enum을 굳이 2개로 나눴어야 했나?? 라고 처음에 생각했었기 때문에, 원래는 GameCommand로 묶여 있었습니다. 그러다보니 오히려 이동 관련, 게임 재시작 관련을 나누기 위해 더 불편하게 코드를 짜야 했고, 이래서는 의미가 없다고 생각했습니다. package 자체가 관련 있는 클래스들을 모아둔 것이니 관련 있는 커맨드를 더 세심하게 나눌 수 있게 command 패키지를 만들고, 각 커맨드 종류에 맞는 상수들로 나눴습니다. 덕분에 만약 이동 커맨드가 바뀐다면 MoveCommand enum만 고치면 되니, enum을 쓰는 이유에 더 가까워진거죠.

- 메세지들도 enum으로 묶어줘야 할까?

enum에 관한 내용을 적다보니 생각난게 있습니다. 에러 메세지와 게임 메세지도 enum으로 만들어야 하는가? 에 대한 생각입니다. 에러, 게임 메세지 모두 굉장히 많습니다. 프로그램이 커지면 커질수록 더 많아질 것이고, 다양해지죠. 게다가 각 메세지들은 '에러 메세지', '게임 메세지'라는 공통점으로 묶입니다.

그렇다면 enum으로 관리하는게 더 좋지 않을까? 라는 생각이 들 수 있는데, enum으로 묶어도 어차피 그 에러를 쓰려면 에러가 모인 enum 클래스로 들어가서 확인해야합니다.

enum은 굉장히 좋은 기능이지만 그렇다고 클래스 안에 상수를 만드는게 나쁜 행위는 아니라고 생각했습니다. 단순히 에러 메시지를 모아놓고, 가져오는 것 뿐이라면 직접 만들어주는게 나아보였죠.

게다가 메세지가 많이 모여있기 때문에, 오히려 더 헷갈릴 수 있습니다. 만약 클래스에 사용될 상수가 너무 많다면, 그때는 그 클래스에 쓰일 상수들을 모은 enum을 만들어주면 됩니다. 굳이 모든 메시지를 한 곳에서 관리할 필요는 없으니까요.

그래서 메세지들은 각각의 클래스에 상수로 만들어주고, 추가적인 로직을 만들어 사용할만한 상수는 관련 있는 상수를 모아 enum을 만들어 줬습니다.

- 상수화

사실 모든 매직 넘버, 매직 스트링의 상수화도 이번 주차 미션에서는 다르게 적용했습니다. 상수화를 하는 이유가 재사용성과 유지 보수의 편함을 위해서인데, 변하지 않을 값들은 굳이 상수화를 해줄 필요가 있을까? 라는 생각이 들었기 때문에, 이번엔 상수화를 해야 하는 하나의 기준(바뀔만한 여지가 있는가)을 잡고 상수화를 진행했습니다.

- 테스트 코드

클래스 분리, 리팩터링이라는 이번 주차의 목표에 맞게 학습하고, 과제를 했다고 생각합니다. 게다가 이번 주차를 진행하며 가장 좋았던 점은, 원래 저번 주차까지만 해도 기능을 완성하고 테스트 코드를 짜고 검증을 했는데, 이번 주는 기능 하나를 만들고 테스트 코드를 작성하는 과정을 중간중간 섞어 주면서, 왜 테스트 코드가 프로그래밍에 유익한지 더 와닿았습니다.

중간중간 내 코드가 기능적으로 맞는 코드인지 검증할 수 있었고, 테스트 코드만 봐도 어떻게 이 클래스를 사용했을 때 어떤 결과가 나오고, 어떤 기능을 하는지 확인할 수 있었습니다. TDD를 시도한건 아니지만, 설계대로 코드를 만들었는지 중간중간 확인할 수 있다는 점이 리팩토링 속도를 빨라지게 하는데 큰 도움을 준 것 같습니다.

4. 스터디

생각하라 스터디도 매주 서로 어떤 코드를 어떻게 짰고, 이런 저런 방식에 대해 서로의 의견을 말하고, 고민하면서 매주 성장하는데 큰 도움을 줬습니다. 정말 만들기 잘했다는 생각이 매주 듭니다😆 게다가 마지막 스터디는 모두의 코드를 서로 한번씩 읽어보고, 추가적으로 발표까지 겸해서 진행할 생각이라서, 그 이후로 얼마나 성장할 수 있을지 또 기대가 됩니다.

5. 프리코스의 끝

이번 주차는 마지막 과제인만큼, 프리코스의 꽃이라고도 할 수 있는 과제였던 것 같아요. 어떻게 하면 더 많은 성장을 할 수 있을지 계속 고민했고, 덕분에 마지막 날까지도 계속 코드에 대해 생각, 수정하며 몰입할 수 있었던 것 같습니다. 제 스터디 모집글에도 썼지만, 완벽한 코드란 있을 수 없기 때문에 지금도 제 코드에 계속 눈이 가는 것 같아요.

더 좋은 코드를 쓸 수 있지 않았을까? 하는 아쉬움이 남지만, 그런 아쉬움이 남을만큼 프리코스 기간동안 즐겁게 성장한 것 같습니다.

프리코스를 진행하면서, 전에 비해 자바와 더 돈독해지고, 친해진 것 같습니다. 물론 아직 자바에 대해서도, 테스트 코드에 관해서도 갈 길이 멀다고 생각하지만요ㅎㅎ...

앞으로의 공부를 함에 있어도 큰 도움이 될 것 같습니다. 좋은 개발 방식에 대해 고민해보고, 적용해 본 행복한 경험이기도 했고요.

그런만큼 더 우테코에 끌리게 되버렸는데...1차 합격하고, 최종 코딩테스트까지 합격했으면 좋겠네요...!

profile
하하

0개의 댓글