[우아한테크코스 4기 프리코스] 3주차 후기

rat8397·2021년 12월 15일
2

배달의민족

목록 보기
3/6
post-thumbnail

3주간의 회고와 그간 나의 성장 및 3주차에 아쉬웠던 점, 더 수정해야하는 지점들을 정리해보려고 합니다.

프리코스 회고록 (장점과 단점)

생선을 잡아서 주는 것이 아닌 생선 잡는 법을 알려준 프리코스

✅ : 풀리퀘로 과제를 제출한다.

우선 가장 좋았던 점은 풀리퀘로 과제를 제출한다는 점인 것 같다. 본인 같은 경우 3주간의 학습효과 대부분은 풀리퀘에 올라온 다른 사람들의 코드 및 아이디어, 리뷰를 통해 얻었다. 특히 MVC 패턴을 적용하게 될 때에도 이미 이 디자인 패턴(혹은 아키텍처)에 대해 지식으로는 알고 있었으나, 적용해볼 생각은 못하고 있었는데 이미 적용해본 다른 사람의 코드를 보고 아이디어를 얻어 적용하게 되었다.

✅ : 공통 피드백 문서를 제공한다.

물론 각자의 코드를 리뷰해준다면 더할 나위 없겠지만, 프리코스에 참여하는 인원이 많은 만큼 공통 피드백으로 리뷰가 제공된다. 하지만 불만이 없을만큼 '나에게 하는 말'인 것처럼 리뷰들이 와닿았고, 개선점을 비교적 쉽게 찾을 수 있었다.

🙏 : 3주차에 난이도가 좀 확 올라간 느낌 ?

물론 이는 장점이자 단점인 것 같다. 클래스의 분리가 어설펐음을 느끼고, 좀 더 심화된 클래스의 분리를 해보고 싶었던 나에겐 이는 장점이었지만, 아직 클래스의 분리가 어려운 사람들에겐 정말 확 올라간 난이도라 느껴져 힘들었을 것 같다.

장점이자 단점인 부분같다.

정리하자면

많은 것을 배울 수 있었다기보단( 실제로 배운 점이 없다는 것이 아닙니다 ), 프론트엔드 개발자가 되기위해 많은 것을 느낄 수 있었던 프리코스였다.

프리코스는 지식을 가르쳐 주는 것이 아닌 본인이 지식을 빼먹어야 하는 것처럼 느껴졌고, 그러기 위해 이번 프리코스는 나혼자 성장하는 법에대해 깨닫게 해준 것 같다.

누군가 리뷰해주는 것이 아니라, 남의 코드를 보며 배우고

등장하는 이슈를 어떻게 해결해나갈지 고민해보고

클래스의 분리를 어떻게 해야 하나의 일을 잘하는 클래스를 만들 수 있을지 판단해보고

등의 과정들은 나에게 혼자서 성장하는 법을 알게 해준 것 같다. 우아한 테크코스 과정조차도 지식의 전파가 아닌 남과 의논하며 성장해나가는 과정이므로 프리코스라는 이름에 알맞았다고 생각한다.

성장

그 간의 성장했다고 느낀 지점 및 3주차 아쉬운 점, 배운 점들을 간략하게 코멘트로 정리해보았습니다.
PULL request

더 개선해야 한다 리팩토링 과정을 기록중인 포스팅

이번 주차에서 가장 아쉬웠던 점은 컨트롤러가 하는 일에 대해 명확히 정의하지 못한 점인것 같다. 코드가 단순한 뷰나 모델의 경우 '하는 일'을 명확히 하여 코드가 복잡해지지 않았으나, 컨트롤러의 경우 '하는 일'이 많아 코드가 복잡해지게 되었다.

1. 함수는 하나의 일만 하도록 한다.

MVC를 적용해보는 것이 처음이라 컨트롤러에서 동전을 넣는다는 함수 하나가 하나의 일을 한다고 생각하여 복잡한 함수가 만들어졌다. 이 때문에 어디서 모델이 업데이트시키고, 뷰를 업데이트 시키는지 명확하지 않게되어 가독성이 떨어지고, 유지보수가 힘들어지게 되었다.

데이터를 만드는 일, 모델을 업데이트 하는 일, 뷰를 업데이트 하는 일을 서로 다른 일이라 인지하지 못해서 생긴 코드이며 자세한 내용은 다음과 같다.

자판기에 금액이 입력되어 제출되면 일어나는 핸들러 함수는 다음과 같다.

  onSubmitVendingMachineChargeForm(e) {
    e.preventDefault();
    this.executeAddChargeProcess();
  }

이 함수는 세 개의 일을 트리거 한다.

  1. 올바른 금액이 입력되었다면, 동전 데이터를 만들어낸다.

  2. 동전을 통해 Model을 업데이트한다.

  3. 동전을 통해 View를 업데이트한다.

위와 같이 세 개의 작업을 하는 함수를 만들어 낼 수 있는데, 세 개의 일이 서로 다른 일이라고 인지하지 못하여 다음과 같은 함수가 작성되었다.

// VendingMachineManageController.js

// 컨트롤러가 해야하는 일을 구분하여 함수를 작성하기 보단, 자판기에 금액을 집어넣는 행위에 집중하여 함수를 구분하였다.

// 함수가 해야하는 하나의 일을 금액을 집어넣는 일, 동전을 만드는 일이라고 만 생각하여 아래와 같이 작성하게 되었다.
executeAddChargeProcess() {
    const newChargeAmount = Number(
      this.$model.getVendingMachineChargeInputValueByInputId(DOM.VENDING_MACHINE_CHARGE_INPUT)
    );
    try {
      if (isValidChargeAmount(newChargeAmount)) {
        const newCoins = Coin.getRandomCoins(newChargeAmount);
        this.$model.addChargeAmount(newChargeAmount, DATA_MODEL_KEYS.VENDING_MACHINE_CHARGE);
        this.executeAddCoinsProcess(newCoins);
      }
    } catch (error) {
      alert(error);
    }
  }

  executeAddCoinsProcess(newCoins) {
    this.$model.addCoins(newCoins);
    this.$model.setVendingMachineChargeInputsValue(() =>
      defaultValueGenerators[DATA_MODEL_KEYS.VENDING_MACHINE_CHARGE_INPUTS_VALUE]()
    );
    this.$view.mainView.renderCoins(
      this.$model.getCoins(),
      this.$model.getVendingMachineChargeInputsValue(),
      this.$model.getVendingMachineChargeAmount()
    );
  }

좀 더 Controller가 해야하는 일이라 생각하고 코드를 작성한다면 onSubmitVendingMachineChargeForm은 다음과 같이 개선할 수 있을 것 같다.

...
onSubmitVendingMachineChargeForm(){
  
  const newCoins = Coin.getNewCoins(인풋에 입력된 금액)
  
  this.triggerMutateModelByNewCoins(newCoins);
  
  this.triggerRenderViewByNewCoins();
}
...

아래와 같이 개선한다면, 기존의 함수보다 컨트롤러가 하는 일이 명확해질 거라고 생각한다.

2. 모델의 구조

현재는 하나의 VendingMachineModel 이라는 클래스가 앱 전반의 데이터를 모두 관리하고 있다. 그렇기 때문에 수정해야 하는 부분을 찾기가 어렵고, 하나의 클래스가 무거워져 개발자인 나조차도 수정하기가 두려워졌다.

Coin의 경우 Coin을 만들어내거나 수정, 관련 유틸리티 기능들을 제공해주는 static 한 클래스가 되었는데, 이를 자신의 데이터를 갖고 메서드를 통해 조작하도록 살아있는 모듈로 만들어주는 것이 더 좋을 것이라 판단하였다.

(이 클래스의 정적 메서드로 들어오는 인자값이 잘못되어 버리면 제대로 동작하지 않는다. 자신만의 변하지 않는 데이터 구조를 만들어 이를 멤버로 갖고, 이 멤버를 수정하는 메서드들을 갖게 한다면 좀 더 독립적인 모듈이 될것이라 생각한다)

정리하자면 Model에서 관리하는 데이터들을 각자 독립적으로 동작할 수 있도록 하고, 또 가독성을 높여 유지보수 및 개발에 들어가는 시간을 줄이고자 모델의 구조를 세분화하려고한다.

1. 사용되는 데이터

Product Model

  • 프로덕트의 리스트 데이터

vending machine

  • 동전 데이터
  • 현재 가지고 있는 금액 (이는 멤버로 필요하지 않다. 동전을 통해 구한다)

user

  • 현재 넣은 금액
  • 현재 구매한 상품 (이는 어플리케이션의 명세상 필요하지 않다)
  • 반환받는 동전 (이는 수시로 바뀌므로 멤버로 필요하지 않다)
    아래 처럼

input

  • input에 입력되는 데이터가 저장된다. (프로덕트를 만들때, 자판기에 돈을 넣을때, 유저가 돈을 넣을때)

3. 이벤트 핸들러를 Main Section이 렌더링 될 때 마다 바인딩한다.

다음은 ProductAddView의 렌더함수이다.

  renderProductAddView(productAddInputsValue, productList) {
    this.$app.innerHTML = this.generateProductAddMenuTemplate(productAddInputsValue, productList);
  }

위 함수는 tab이 눌러져 변경되면, tab 이 상품 추가의 경우 실행된다. 실행되면 template를 만들어 이를 삽입하여 렌더링 되는데 문제는 template 내부 돔에 바인딩 하였던 이벤트 핸들러도 제 기능을 못하게 된다는 것이다

이 문제점을 해결하고자 간이적으로 새로이 Main Section이 렌더링 될때마다 그에 맞는 이벤트를 핸들링 하는 것으로 하였다.

  executeRenderProductAddMenu() {
    // 탭이 변경되어 ProductAddMenu`를 렌더링하게 되면
    this.$view.renderProductAddMenu(
      this.$model.getProductAddInputsValue(),
      this.$model.getProductList()
    );
    // ProductAddView가 갖는 돔 요소에 이벤트를 등록하는 함수를 실행시킨다.
    this.$productAddController.registerEventHandler();
  }

문제는 이미 이벤트가 한번 바인딩 되었음에도 또 바인딩 한다는 점이다. 이를 이벤트가 이미 바인딩되어있으면 바인딩되지 않도록 하고 싶다.

✅ 여기서 정말 궁금한거

// 상록은 나의 친구이다. 오해 금지
현재 돔 구조 - <div id="상록요소의부모태그"><div id="상록" /></div> 

$('상록요소의부모태그').innerHTML = '';

1. 돔이 화면에서 사라진다 -> 돔 객체도 메모리상에서 사라지나? 

2. 사라진다면 -> 달려있던 이벤트 핸들러도 메모리상에서 사라지나?

error message를 보여주는 모델

잘못된 입력에 에러를 보여주는 코드를 하나로 모으고자한다. 여러 곳에 뿌려져있으니, 통일감이 없어 유지보수에 힘이 든다.

모델에 새로운 데이터를 set할 때만 입력 데이터를 점검하고 에러를 throw 해주는 코드가 나중에 유지보수 혹은 새로운 기능을 짤 때 더 편할 것이라 생각되어 이점을 수정하고자 한다.

profile
Frontend Ninja

0개의 댓글