4주차 다리 건너기 후기 + 프리코스 후기

[다리 건너기] 신현호 미션 제출합니다. by SWARVY · Pull Request #29 · woowacourse-precourse/javascript-bridge (github.com)

 

[다리 건너기] 신현호 미션 제출합니다. by SWARVY · Pull Request #29 · woowacourse-precourse/javascript-bridge

4주차 소감 많이 고민 한 부분 MVC 패턴의 적용 모델, 뷰, 컨트롤러를 나누어 mvc 디자인 패턴을 따르도록 노력했습니다. (MVC 패턴 참고 자료) 화살 함수와 this 일반 함수를 사용했을 때 this가 계속 u

github.com

 

머리털나고 처음 들어보는 MVC 패턴, 그리고 까다로운 조건들이 괴롭혔지만, 어떻게 완성을 해서 제출을 했습니다.

 

가장 까다로웠던 조건은 함수 10줄 이내, 그리고 각 파일에 붙어있던 제약들..

의외로 indent 2는 어렵지 않았습니다. 적당히 생각하고 파일 분리하면 indent 2는 어렵지 않기에..

 

각설하고, 이번 4주차를 하면서 생각했던 것들을 적어보도록 하겠습니다.

 

1. MVC 패턴 너무 어렵다

 

MVC란 Model View Controller의 약자로 에플리케이션을 세가지의 역할로 구분한 개발 방법론이다. 아래의 그림처럼 사용자가 Controller를 조작하면 Controller는 Model을 통해서 데이터를 가져오고 그 정보를 바탕으로 시각적인 표현을 담당하는 View를 제어해서 사용자에게 전달하게 된다. 
출처 - MVC 디자인 패턴 - 생활코딩 (opentutorials.org)

 

라고 설명을 하고있습니다. 모델은 비즈니스 로직을, 뷰는 입/출력을, Controller는 이 모델과 뷰를 조작한다고 생각하시면 편합니다.

MVC에 대한 더 자세한 설명은 하단의 영상을 참고해주시면 좋습니다!

 

(53) [10분 테코톡] 🧀 제리의 MVC 패턴 - YouTube

 

먼저, 이번문제에 추가된 요구사항을 한번 보겠습니다.

BridgeGame 클래스에서 InputView, OutputView를 사용하지 말라는 말은, BridgeGame을 Model로, InputView와 OutputView를 View로 사용하라는것을 암시한다고 생각했습니다.

 

그렇다면, 결과적으로 문제에서 요구하는 것은 Controller를 구현하라는 것과 같았고,

그래서 저는

Model과 InputView, OutputView를 Controller에서 불러와주고,

InputView에는 입력 요청을 받아오고, 이를 컨트롤러에서 Model에 송신 -> Model에서 값을 받아 값 업데이트

OutputView에 출력 요청을 하기위해 컨트롤러에서 Model의 값을 요청 -> 받아와서 OutputView에 송신 후 출력

을 기본 틀로 잡고 작성했습니다.

 

const BridgeGame = require('../Model/BridgeGame');
const { readBridgeSize, readMoving, readGameCommand, exit } = require('../View/InputView');
const { printMap, printResult } = require('../View/OutputView');
const { isPlayerPassed, isPlayerCleared } = require('../CheckPlayerStatus');
const { INPUT_RETRY } = require('../Constants/InputValues');

/**
 * BridgeGame(모델) 과 InputView, OutputView(뷰)를 조작하는 컨트롤러
 */
class BridgeController {
  #Game;

  constructor() {
    this.#Game = new BridgeGame();
  }

  /**
   * 뷰에 생성될 다리의 길이 입력을 요청하는 메서드
   */
  requestBridgeSizeToView = () => {
    readBridgeSize(this.verifyBridgeSize);
  };

  /**
   * 입력받은 다리의 유효성 검사여부에 따라 다시 입력을 요청하거나 다음단계로 진행시키는 메서드
   */
  verifyBridgeSize = (size, isError) => {
    if (isError) this.requestBridgeSizeToView();
    if (!isError) this.sendBridgeSizeRequestToModel(size);
  };

  /**
   * 모델에 입력받은 다리의 길이를 전달하는 메서드
   */
  sendBridgeSizeRequestToModel = (size) => {
    this.#Game.initializeBridge(size);
    this.requestMoveToView();
  };

  /**
   * 뷰에 이동 입력을 요청하는 메서드
   */
  requestMoveToView = () => {
    readMoving(this.verifyMove);
  };

  /**
   * 입력받은 이동의 유효성 검사여부에 따라 다시 입력을 요청하거나 다음단계로 진행시키는 메서드
   */
  verifyMove = (move, isError) => {
    if (isError) this.requestMoveToView();
    if (!isError) this.sendMoveRequestToModel(move);
  };

  /**
   * 모델에 입력받은 이동 입력을 전달하는 메서드
   */
  sendMoveRequestToModel = (move) => {
    this.#Game.move(move);
    this.sendOutputRequestToModel();
  };

  /**
   * 생성된 게임 정보와 입력을 비교하여 모델에 값 변경을 요청하는 메서드
   */
  sendOutputRequestToModel = () => {
    const { bridge } = this.#Game.getStatus();
    const input = this.#Game.getStatus().Input;
    const isPassed = isPlayerPassed(input[input.length - 1], bridge[input.length - 1]);
    const isCleared = isPlayerCleared(bridge.length, input.length, isPassed);
    this.#Game.setMoveOutput(isPassed, isCleared);
    this.sendOutputRequestToView();
  };

  /**
   * 변경된 모델 값을 바탕으로 뷰에 현재 상황 출력을 요청하는 메서드
   */
  sendOutputRequestToView = () => {
    const { output } = this.#Game.getStatus();
    printMap(output);
    this.checkMoveOption();
  };

  /**
   * 게임 진행을 관리하는 메서드
   */
  checkMoveOption = () => {
    const { isPassed, isCleared } = this.#Game.getStatus();
    if (isPassed) this.requestMoveToView();
    if (!isPassed) this.requestCommandToView();
    if (isCleared) this.finishControl();
  };

  /**
   * 뷰에 종료, 재시작 여부를 묻는 입력을 요청하는 메서드
   */
  requestCommandToView = () => {
    readGameCommand(this.checkGameOption);
  };

  /**
   * 입력받은 종료,재시작여부의 유효성 검사여부에 따라 다시 입력을 요청하거나 다음단계로 진행시키는 메서드
   */
  verifyCommand = (command, isError) => {
    if (isError) this.requestCommandToView();
    if (!isError) this.checkGameOption(command);
  };

  /**
   * 입력받은 값을 바탕으로 게임을 종료, 재시작시키는 메서드
   */
  checkGameOption = (command) => {
    if (command === INPUT_RETRY.restart) {
      this.#Game.retry();
      this.requestMoveToView();
    }
    if (command === INPUT_RETRY.quit) this.finishControl();
  };

  /**
   * 뷰에 최종 결과 출력을 요청하는 메서드
   */
  finishControl = () => {
    const { count, isCleared, output } = this.#Game.getStatus();
    printResult(count, isCleared, output);
    exit();
  };
}

module.exports = BridgeController;

덕분에 코드가 이렇게 길어졌네요 ㅎㅎ.. 완벽한 코드는 아니고 수정할 점도 있습니다. 피드백도 많이 받았구요

피드백 받고 든 생각은, MVC 디자인패턴 적용에 신경을 너무 많이 쓴 나머지 세부적인걸 좀 많이 놓쳤다는 생각이 들었네요

 

그래도 MVC 패턴이 어떤거구나~ 라는 공부는 확실히 됐던 것 같습니다.

MVC 패턴을 통해서 모델-뷰-컨트롤러를 나눠서 작성하는 방식이 상당히 효율적임을 깨달았고 (코드 리뷰하기도 편하더라구요)

앞으로도 이렇게 계속 코딩을 해보려고 합니다!

 

2. 화살 함수는 좋은 친구였다

 

저 컨트롤러 로직을 작성하는데, 처음에 계속 this로 참조해온 값이 undefined가 나와서 굉장히 당황했었네요

관련해서 찾아봤었던 좋은 자료 공유합니다.

[JavaScript] 화살표 함수와 this 바인딩 (velog.io)

 

[JavaScript] 화살표 함수와 this 바인딩

본래 JavaScript에서 함수를 선언할 땐 function 이란 키워드를 쓰죠. 하지만 ES6가 도입되면서 함수를 선언하는 새로운 문법이 등장했습니다. 바로 화살표 함수입니다.

velog.io

 

요약을 해보자면, 함수 호출 시 함수 내부의 this는 지정되지 않는다는.. 기묘한 정답을 알아냈습니다.

일반 function에는 this가 있으나 값을 지정하지는 않는데, 화살표 함수에는 this가 존재하지 않기에 상위 환경의 this를 참조한다고 하더라구요

 

사실 this라는 개념을 자바에서 먼저 학습했었기에, 당연히 비슷할거라고 생각했는데 전혀 아니어서 놀랐습니다.

역시 자바스크립트 호락호락하지 않아요.

 

3. 이전에 받았던 피드백을 최대한 반영하자

 

parksb/javascript-style-guide: Airbnb JavaScript 스타일 가이드

 

GitHub - parksb/javascript-style-guide: Airbnb JavaScript 스타일 가이드

Airbnb JavaScript 스타일 가이드. Contribute to parksb/javascript-style-guide development by creating an account on GitHub.

github.com

C언어를 공부할때부터 저와 항상 함께하던 for(i = 0...) 이터레이터 반복문.. 자바스크립트 컨밴션에 따르면 '지양'하라고 되어있어서 눈물을 머금고 다른 친구를 찾아나섰습니다.

 

근데 제가 생각을 못했던거지 사실 방법은 많았더라구요, for-of, for-in, for-each, array.map, array.from, array.filter.. 등등

고급함수를 사용하여 최대한 이터레이터 반복문을 피해야겠다 생각했습니다.

 

이 외에도 많았는데, 사실 위에 두개가 가장 컸어요 ㅎㅎ..


4주차가 마무리되면서 프리코스가 드디어 끝났는데 드는 생각을 몇자 적어본다면

 

프리코스 전에는 코드같이 생긴 무언가를 작성했다면, 최소한 지금은 코드를 작성하고 있다는 생각이 많이 듭니다.

저보다 잘하시는분들 사이에서 코드 리뷰를 받을 수 있었던 것도 운이고, 애초에 이 프리코스도 친구가 말 안해줬으면 신청도 안했을건데

어떻게 아다리가 잘 맞아 떨어졌다는 생각만 드네요 (막상 같이 하자고 소개해준 친구는 학교다니느라 바빠서 못했습니다)

 

4주차로 마무리될 줄 알았던 스터디도 2주차 리팩토링을 시작으로 스터디를 이어나갈거라고 하셔서, 끝났다고 시간이 남아돌지는 않겠네요

1차 테스트를 통과할지, 통과 못할지는 잘 모르겠지만 프리코스 그 자체만으로도 충분히 가치있는 시간이었습니다!

 

 

끝으로, 같이 스터디 하시는 멤버분들과 주차별 스터디 리뷰 또한 프리코스 커뮤니티에 올려놓고 있으니 읽어주시면 감사하겠습니다!!

 

3주차 : [FE] 우테코 피어리뷰 스터디 '가맹점 1호'! 정보 공유해요! · Discussion #1276 · woowacourse-precourse (github.com)

 

[FE] 우테코 피어리뷰 스터디 '가맹점 1호'! 정보 공유해요! · Discussion #1276 · woowacourse-precourse

📖FE 스터디 '가맹점 1호'📖 안녕하세요! 슬랙의 스터디 채널에서 처음으로 웹 프론트엔드 피어리뷰 스터디를 결성한 그룹 '가맹점 1호'입니다! 로또 미션 코드를 피어 리뷰 하면서 얻은 정보를

github.com

 

4주차 : 추후 업로드 예정입니다.

'우아한 테크코스' 카테고리의 다른 글

(또)매우 늦은 3주차 로또 후기  (0) 2022.11.22
2주차 숫자야구 후기  (0) 2022.11.09
늦은 1주차 온보딩 후기  (0) 2022.11.07