티스토리 뷰

프리코스 4주차

3주차와 동일한 부분

3주차와 동일한 부분이 있어서 해당 부분은 3주차 글로 참고 하도록 하겠습니다.

  • 진행방식
  • 미션 제출 방법
  • 과제 제출 전 체크리스트 - 0점 방지
  • 프로그래밍 요구 사항(추가된 요구사항은 아래에 적어 두었습니다.)

https://takim0070.tistory.com/27

 

우테코 프리코스 3주차 회고 - 로또

프리코스 3주차 2주차와 동일한 부분 2주차와 동일한 부분이 있어서 해당 부분은 2주차 글로 참고 하도록 하겠습니다. 진행방식 미션 제출 방법 과제 제출 전 체크리스트 - 0점 방지 프로그래밍

takim0070.tistory.com

기능 요구 사항

위아래 둘 중 하나의 칸만 건널 수 있는 다리를 끝까지 건너가는 게임이다.

  • 위아래 두 칸으로 이루어진 다리를 건너야 한다.
    • 다리는 왼쪽에서 오른쪽으로 건너야 한다.
    • 위아래 둘 중 하나의 칸만 건널 수 있다.
  • 다리의 길이를 숫자로 입력받고 생성한다.
    • 다리를 생성할 때 위 칸과 아래 칸 중 건널 수 있는 칸은 0과 1 중 무작위 값을 이용해서 정한다.
    • 위 칸을 건널 수 있는 경우 U, 아래 칸을 건널 수 있는 경우 D값으로 나타낸다.
    • 무작위 값이 0인 경우 아래 칸, 1인 경우 위 칸이 건널 수 있는 칸이 된다.
  • 다리가 생성되면 플레이어가 이동할 칸을 선택한다.
    • 이동할 때 위 칸은 대문자 U, 아래 칸은 대문자 D를 입력한다.
    • 이동한 칸을 건널 수 있다면 O로 표시한다. 건널 수 없다면 X로 표시한다.
  • 다리를 끝까지 건너면 게임이 종료된다.
  • 다리를 건너다 실패하면 게임을 재시작하거나 종료할 수 있다.
    • 재시작해도 처음에 만든 다리로 재사용한다.
    • 게임 결과의 총 시도한 횟수는 첫 시도를 포함해 게임을 종료할 때까지 시도한 횟수를 나타낸다.
  • 사용자가 잘못된 값을 입력할 경우 IllegalArgumentException를 발생시키고, "[ERROR]"로 시작하는 에러 메시지를 출력 후 그 부분부터 입력을 다시 받는다.
    • Exception이 아닌 IllegalArgumentException, IllegalStateException 등과 같은 명확한 유형을 처리한다.

입출력 요구 사항

입력

  • 자동으로 생성할 다리 길이를 입력 받는다. 3 이상 20 이하의 숫자를 입력할 수 있으며 올바른 값이 아니면 예외 처리한다.
3
  • 라운드마다 플레이어가 이동할 칸을 입력 받는다. U(위 칸)와 D(아래 칸) 중 하나의 문자를 입력할 수 있으며 올바른 값이 아니면 예외 처리한다.
U
  • 게임 재시작/종료 여부를 입력 받는다. R(재시작)과 Q(종료) 중 하나의 문자를 입력할 수 있으며 올바른 값이 아니면 예외 처리한다.
R

출력

  • 게임 시작 문구
다리 건너기 게임을 시작합니다.
  • 게임 종료 문구
최종 게임 결과
[ O |   |   ]
[   | O | O ]

게임 성공 여부: 성공
총 시도한 횟수: 2
  • 사용자가 이동할 때마다 다리 건너기 결과의 출력 형식은 실행 결과 예시를 참고한다.
    • 이동할 수 있는 칸을 선택한 경우 O 표시
    • 이동할 수 없는 칸을 선택한 경우 X 표시
    • 선택하지 않은 칸은 공백 한 칸으로 표시
    • 다리의 시작은 [, 다리의 끝은 ]으로 표시
    • 다리 칸의 구분은 |(앞뒤 공백 포함) 문자열로 구분
    • 현재까지 건넌 다리를 모두 출력
  • 예외 상황 시 에러 문구를 출력해야 한다. 단, 에러 문구는 "[ERROR]"로 시작해야 한다.
[ERROR] 다리 길이는 3부터 20 사이의 숫자여야 합니다.

실행 결과 예시

다리 건너기 게임을 시작합니다.

다리의 길이를 입력해주세요.
3

이동할 칸을 선택해주세요. (위: U, 아래: D)
U
[ O ]
[   ]

이동할 칸을 선택해주세요. (위: U, 아래: D)
U
[ O | X ]
[   |   ]

게임을 다시 시도할지 여부를 입력해주세요. (재시도: R, 종료: Q)
R
이동할 칸을 선택해주세요. (위: U, 아래: D)
U
[ O ]
[   ]

이동할 칸을 선택해주세요. (위: U, 아래: D)
D
[ O |   ]
[   | O ]

이동할 칸을 선택해주세요. (위: U, 아래: D)
D
[ O |   |   ]
[   | O | O ]

최종 게임 결과
[ O |   |   ]
[   | O | O ]

게임 성공 여부: 성공
총 시도한 횟수: 2
다리 건너기 게임을 시작합니다.

다리의 길이를 입력해주세요.
3

이동할 칸을 선택해주세요. (위: U, 아래: D)
U
[ O ]
[   ]

이동할 칸을 선택해주세요. (위: U, 아래: D)
U
[ O | X ]
[   |   ]

게임을 다시 시도할지 여부를 입력해주세요. (재시도: R, 종료: Q)
Q
최종 게임 결과
[ O | X ]
[   |   ]

게임 성공 여부: 실패
총 시도한 횟수: 1

 

프로그래밍 요구사항(추가된 요구사항만 있음)

  • 함수(또는 메서드)의 길이가 10라인을 넘어가지 않도록 구현한다.
    • 함수(또는 메서드)가 한 가지 일만 잘하도록 구현한다.
  • 메서드의 파라미터 개수는 최대 3개까지만 허용한다.
  • 아래 있는 InputView, OutputView, BridgeGame, BridgeMaker, BridgeRandomNumberGenerator 클래스의 요구사항을 참고하여 구현한다.
    • 각 클래스의 제약 사항은 아래 클래스별 세부 설명을 참고한다.
    • 이외 필요한 클래스(또는 객체)와 메서드는 자유롭게 구현할 수 있다.
    • InputView 클래스에서만 camp.nextstep.edu.missionutils.Console  readLine() 메서드를 이용해 사용자의 입력을 받을 수 있다.
    • BridgeGame 클래스에서 InputView, OutputView 를 사용하지 않는다.

InputView 클래스

  • 제공된 InputView 클래스를 활용해 구현해야 한다.
  • InputView의 패키지는 변경할 수 있다.
  • InputView의 메서드의 시그니처(인자, 이름)와 반환 타입은 변경할 수 있다.
  • 사용자 값 입력을 위해 필요한 메서드를 추가할 수 있다.
public class InputView {

    public int readBridgeSize() {
        return 0;
    }

    public String readMoving() {
        return null;
    }

    public String readGameCommand() {
        return null;
    }
}

OutputView 클래스

  • 제공된 OutputView 클래스를 활용해 구현해야 한다.
  • OutputView의 패키지는 변경할 수 있다.
  • OutputView의 메서드의 이름은 변경할 수 없고, 인자와 반환 타입은 필요에 따라 추가하거나 변경할 수 있다.
  • 값 출력을 위해 필요한 메서드를 추가할 수 있다.
public class OutputView {

    public void printMap() {
    }

    public void printResult() {
    }
}

BridgeGame 클래스

  • 제공된 BridgeGame 클래스를 활용해 구현해야 한다.
  • BridgeGame에 필드(인스턴스 변수)를 추가할 수 있다.
  • BridgeGame의 패키지는 변경할 수 있다.
  • BridgeGame의 메서드의 이름은 변경할 수 없고, 인자와 반환 타입은 필요에 따라 추가하거나 변경할 수 있다.
  • 게임 진행을 위해 필요한 메서드를 추가 하거나 변경할 수 있다.
public class BridgeGame {

    public void move() {
    }

    public void retry() {
    }
}

BridgeMaker 클래스

  • 제공된 BridgeMaker 클래스를 활용해 구현해야 한다.
  • BridgeMaker의 필드(인스턴스 변수)를 변경할 수 없다.
  • BridgeMaker의 메서드의 시그니처(인자, 이름)와 반환 타입은 변경할 수 없다.
public class BridgeMaker {

    public List<String> makeBridge(int size) {
        return null;
    }
}

BridgeRandomNumberGenerator 클래스

  • Random 값 추출은 제공된 bridge.BridgeRandomNumberGenerator의 generate()를 활용한다.
  • BridgeRandomNumberGenerator, BridgeNumberGenerator 클래스의 코드는 변경할 수 없다.

사용 예시

  • 다리 칸을 생성하기 위한 Random 값은 아래와 같이 추출한다.
int number = bridgeNumberGenerator.generate();

 

 

우테코 프리코스 종료 안내

  • 프리코스 회고하면서 다음 단계 목표 설정해 보기
  • 프리코스 커뮤니티 참여 및 코드 리뷰 경험해 보기
  • 2주 차 ~ 4주 차 미션 다시 구현해 보기

 

4주차 회고 및 우테코 프리코스 전체 회고

프로그래밍 요구 사항에 대한 고찰

우테코 프리코스를 진행하면서 궁금 했던 부분이 있습니다.

 

왜 함수 라인 15라인 이라든지 10라인으로 제한을 하는 것인가?

함수 라인 10라인이라고 한다면 함수 시그내처와 범위를 나타 내는 { } 중괄호도 포함 되는 것인가?

그렇다면 실질적으로 8라인으로 함수를 만들어야 하는가?

이런 의문들이 들었습니다.

 

슬랙 방에서도 많은 분들이 의문을 가지고 있었고 나름대로 여러 생각들을 가지고 있는 것을 봤습니다.

저는 10라인으로 제한 될 때 함수 시그내처와 중괄호도 포함을 했습니다.

public void doSomething() {
	// do Something
}

이런 함수가 있다고 한다면 3줄이라 하기로 했습니다.

이유는

  1. 함수의 행위만 함수라고 보기 힘들다(시그내처와 scope도 함수라고 보는 게 나아 보임)
  2. 시그내처와 scope을 포함하지 않고 함수 라인을 제한할 경우 시그내처 포함하는 경우 제가 작성하는 함수는 제한 사항을 위반하기 때문에 위반하지 않는 방향으로 가는 게 옳다
  3. 함수 라인 제한하는 이유는 함수에게 한 가지 일을 하는 것에 대한 훈련이라 생각하면 더 어려운 쪽을 택하는 게 훈련 효과가 더 클 가능성이 있다(물론 오버 트레이닝이 되면 안 좋겠지만 2줄 정도 차이는 오버 트레이닝이 될 가능성이 적어 보임)

위와 같이 생각하면서 만들다보니 여러가지 생각을 하게 되었습니다.

입력 값을 검증할 때입니다. 함수는 이렇게 만들게 되었습니다.

입력값이 정수 인가요?

입력값이 유효한 크기 사이에 있나요?

 

이런 식으로 한 가지 일을 하게 만들 수 있게 되었습니다. 그러면서 클래스, 메서드 분리하는 훈련이 정말 잘 되었습니다.

그리고 잘 못 설계된 것들을 리팩터링하게 될 때에도 미리 고민을 하면서 만들 수 있게 되었고 비교적 빠르게 할 수 있게 되었습니다.

 

객체를 객체스럽게 사용한다

깃허브 토론에 3주차 피드백 중 하나인 `객체를 객체스럽게 사용하다` 는 것에 대해 의견들이 있었습니다.

그 토론이 정말 도움이 되었습니다.

 

객체에게 어떤 메시지를 보내면 객체가 캡슐화를 해치지 않고 값만을 요청자에게 전달 해주는 방식에 대한 이야기 였습니다. 

 

3주차 미션에서 Lotto의 경우

저는 멤버 변수 List<Integer> numbers 가 있었는데 getNumbers 로 내부 멤버 변수를 반환 했습니다.

 

controller가 Lotto 번호를 확인해서 1등~꽝 까지 분류하기 위해 만들었는데 이게 캡슐화를 해치는 결과를 야기 할 수 있다는 점을 알게 되었습니다.

이런 식으로 getter 를 만들 경우 핵을 사용하게 내버려 두게 될 수도 있었습니다.

 

이 때, 피드백에서 이야기한 방식 대로 Lotto 클래스 내부에 로또 번호 체크하는 함수를 만드는 방식을 제안 했었습니다.

 

public LottoRank getLottoResult(Lotto winLotto) {

    // 로또 등 수를 체크하는 행위

}

 

LottoRank라는 enum을 반환하게 하면 캡슐화를 해치지 않고 로또 결과를 확인 할 수 있게 됩니다.

이 토론을 안하게 되었다면 `객체를 객체스럽게 사용한다`는 말이 너무 어렵고 캡슐화만 해치지 말자고 생각 했을 텐데 그러면 검증 코드가 Lotto 클래스 내부에 있는게 옳은가? 등과 같은 다른 생각을 안 해보았을 것 같습니다.

 

이런 토론들이 생각의 견고함을 유지 시켜주는 것 같습니다.

 

느낀점

우테코 지원할 때

우아한테크코스는 자기 주도적으로 학습해야 하며, 동료들과 공동으로 학습하고 같이 성장하는 방식으로 진행합니다.

 

'혼자서 공부 열심히 하고 동료들과 공유하면서 학습 하는 것이구나' 라고 피상적으로 생각 했었습니다.

프리코스를 하면서 해당 내용을 이해하는데 도움이 되었습니다.

자기 주도적으로 학습한다는 의미는 프리코스에서의 미션과 비슷했습니다.

미션을 수행할 때 필요한 학습 정보, 개념들을 제가 스스로 학습을 해야 했습니다. 그래야만 미션을 완료 할 수 있기 때문이었죠. 코치분들이 다른 분들과 같이 미션을 하는 걸 하지 말라고 한 것도 있었습니다.

 

동료들과 공동으로 학습하는 것은 미션이 끝나고 문제 해결 방법에 대한 공유와 피드백에 대한 토론이었던 것 같습니다.

그래서 우테코 합류하게 되면 이런식으로 학습하게 된다는 것을 알게 되었습니다.

왜 우테코 1기,2기,3기,4기 분들이 학습량 또는 깊이가 깊은지 이해하게 되었습니다. 자기 주도적으로 학습하지 않으면 완연히 체득되지 않고 동료들과 토론하거나 피드백을 하면 지식,개념의 확장이 일어나게 되어서 깊이가 깊어 지는 것으로 보입니다.

 

프리코스를 해보니 우테코에 합류하고 싶어지는데요.

안되더라도 이렇게 배운 것을 토대로 앞으로 어떻게 할지 어느정도 감을 잡았습니다.

 

일단은

  • 프리코스 회고하면서 다음 단계 목표 설정해 보기
  • 프리코스 커뮤니티 참여 및 코드 리뷰 경험해 보기
  • 2주 차 ~ 4주 차 미션 다시 구현해 보기

이것부터 해보도록 해야겠습니다.

댓글