📌 프리코스 마지막 세 번째 과제
(데모 찍다가 오류 두 개 발견해서 바로 수정했음)
드디어 대망의 마지막 마지막 주차 과제가 나왔고 구현을 완료했다.
역시나 수요일 3시 정각에 메일이 왔다.
3주 차 과제는 자판기를 만드는 것이었다.
과제의 양만 봐도 1, 2주 차와는 확실히 수준이 많이 달라 보였다.
수요일에는 인턴 일을 해야 돼서 요구 사항 정리만 했다.
목요일과 금요일도 인턴 일이 있어서 밤에 6시간 정도 진행을 했다.
토요일에는 하루 종일 했고 일요일에도 하루 종일 했다.
현재 이 글을 쓰는 시점에도 리팩토링 할 것이 많지만,
우선은 기능 구현을 완료했고 최소한의 요구사항들은 만족시켜서 회고글을 먼저 쓰고
이번 주 토요일 날 있을 최종 코딩 테스트를 계속 준비를 해야 할 것 같다.
최종 코딩 테스트는 5시간인데 어떻게 구현을 할지... 전략을 정말 잘 짜야할 것 같다.
📌 들어가기 전
3주 차 과제의 목표는 "여러 개의 클래스로 분리하기"였다.
2주 차 과제에서 클래스를 최대한 분리시키려고 했다.
변화하는 부분들을 큼지막하게 컴포넌트로 분리를 시켰다.
근데 이번에 2주 차 피드백 중에서 "비즈니스 로직과 UI 로직을 분리해라"라는 피드백을 보고
바로 MVC 패턴이 떠올랐다.
사실 MVC 패턴을 어디서나 적용을 시킨 적이 없고 바닐라 자바스크립트로는 더더욱 해본 적이 없다.
Model - View - Controller로 분리되어 각각의 역할을 맡는다는 것만 알고 있지 코딩을 어떻게 진행해야 하는지 모르고 있었다.
그래서 우선 MVC 패턴에 대해서 먼저 찾아보았다.
Model
모델은 데이터를 관리하는 컴포넌트이다.
모델은 뷰와 컨트롤러에 대해 알고 있으면 안 된다.
모델이 가지고 있어야 하는 것은 데이터 값과 데이터와 직접적으로 관련된 로직뿐이다. 어떠한 이벤트 헨들러, 뷰 템플릿과 로직도 허용되지 않는다. 컨트롤러가 서버로부터 데이터를 불러와서 새로운 것을 생성할 때, 이 모든 것이 모델 인스턴스에서 마무리된다.
View
인터렉션을 위해 모델을 적합한 형태로 랜더링 한다. 유저 인터페이스 부분이다. MVC는 주로 웹 애플리케이션에서 나타낸다. 뷰는 HTML 페이지이다. 그리고 페이지에서 다이나믹 데이터를 수집한다. 뷰는 어떠한 로직도 가지고 있으면 안 되며 컨트롤러와 모델을 알아선 안된다.
Controller
이벤트에 반응한다. 일반적으로 사용자의 행동이다. 아마도, 모델에 변화를 가하며 뷰에 영향을 끼친다. 페이지가 로드되었을 때, 컨트롤러는 이벤트 리스너를 뷰에 추가한다. 사용자가 어떠한 행동을 했을 때, 컨트롤러 안에 있는 이벤트 트리거가 실행된다. 이것을 위하여 딱히, 특별한 라이브러리나 프레임워크가 필요하지는 않다.
출처: JavaScript MVC 디자인 패턴 개념 이해
📌 과제 진행
시행착오
사실 맨 처음부터 MVC 패턴으로 구현을 시작한 것은 아니다.
1, 2주 차까지는 간단한 스켈레톤 HTML이 주어져서 뷰 쪽은 크게 할 것이 없었는데
이번에는 아예 주어진 것이 없었다.
그래서 뷰를 만드는 것을 먼저 시작했다.
처음에는 createElement를 이용해서 하나씩 만들어 갔는데
후에는 template 생성 함수를 이용해서 innerHTML을 이용해서 템플릿을 박았다.
template이 조금 더 직관적이고 구조가 어떻게 되어있는지 한눈에 보기 쉬운 것 같다.
그리고 template을 그려주는 render 함수가 데이터들을 가공하는 로직과 함께 있으니까
이것을 분리해야 되겠다고 느끼고, 자연스럽게 MVC 패턴을 찾게 되었던 것 같다.
폴더 구조
📦src
┣ 📂constants
┃ ┣ 📜common.js
┃ ┣ 📜key.js
┃ ┣ 📜message.js
┃ ┣ 📜selector.js
┃ ┗ 📜style.js
┣ 📂controllers
┃ ┣ 📜ProductAddMenuController.js
┃ ┣ 📜ProductPurchaseMenuController.js
┃ ┣ 📜VendingMachineController.js
┃ ┗ 📜VendingMachineManageMenuController.js
┣ 📂models
┃ ┣ 📜ProductAddMenuModel.js
┃ ┣ 📜ProductPurchaseMenuModel.js
┃ ┣ 📜VendingMachineManageMenuModel.js
┃ ┗ 📜VendingMachineModel.js
┣ 📂templates
┃ ┣ 📜common.js
┃ ┣ 📜productAddMenu.js
┃ ┣ 📜productPurchaseMenu.js
┃ ┗ 📜vendingMachineManageMenu.js
┣ 📂utils
┃ ┣ 📜dom.js
┃ ┣ 📜index.js
┃ ┗ 📜store.js
┣ 📂validators
┃ ┣ 📜productAddMenu.js
┃ ┣ 📜productPurchaseMenu.js
┃ ┗ 📜vendingMachineManageMenu.js
┣ 📂views
┃ ┣ 📜ProductAddMenuView.js
┃ ┣ 📜ProductPurchaseMenuView.js
┃ ┣ 📜VendingMachineManageMenuView.js
┃ ┗ 📜VendingMachineView.js
┗ 📜index.js
각각에 대해서 간단히 설명을 하자면
constants: 상수 값들을 정리해놓은 폴더
controllers: 컨트롤러를 모아놓은 폴더 (이벤트 핸들러, 뷰와 모델을 조종)
models: 모델을 모아놓은 폴더 (데이터 불러오기, 저장하기)
templates: 화면에 그려줄 템플릿을 생성하는 함수들을 모아놓은 폴더
utils: 각종 유틸리티를 모아놓은 폴더 (dom seletor, local storage,... )
validators: 검증 함수들을 모아놓은 폴더
views: 템플릿 생성 함수로 화면을 그려주는 뷰를 모아놓은 폴더
컴포넌트 도식화
내가 만든 프로젝트의 구조도 파악할 겸 조금 더 한눈에 보기 쉽게 도식화를 해보았다.
컨트롤러는 총 4개를 생성했다.
하나는 메뉴를 변경하고 각각의 메뉴를 그릴 지 말지 결정하게 해주는 로직이 있는 VendingMachineController가 있다.
그리고 그 아래에는 각각의 메뉴에 대한 컨트롤러를 생성해서 큼지막한 틀을 잡았다.
그리고 각각의 컨트롤러는 해당하는 메뉴의 뷰에서 렌더링 하는 로직을 생성해서 구현을 하였고,
또한 입력값에 대한 검증 또한 컨트롤러에서 진행을 했다.
그리고 뷰는 템플릿 폴더에서 템플릿 생성 함수를 가져와 그림을 그려준다.
그리고 각각의 컨트롤러에서 각각의 모델에 접근해서 데이터를 가져오거나 저장을 하는 로직을 구현했다.
그리고 utils, constants 같은 경우는 모든 컴포넌트에서 필요할 때마다 불러서 사용한다.
이렇게 MVC 패턴을 이용해서 컴포넌트 구조화를 진행했다.
MVC 패턴을 이용할 때 꼭 지켜야 하는 것들은 다음과 같다.
1. 뷰는 모델에 대해서, 컨트롤러에 대해서 알아선 안된다.
2. 모델은 뷰에 대해서, 컨트롤러에 대해서 알아선 안된다.
각각의 컨트롤러들은 뷰에 접근해서 그림을 그리도록 구현을 했고,
로컬 스토리지에 저장되어야 하는 값들은 전부 모델에서 저장, 가져오기를 진행했다.
📌 어려웠던 점 & 해결 방식
❓ MVC 패턴에 대해서
MVC 패턴으로 애플리케이션을 처음 만들어봐서 어려움을 많이 겪었다.
특히 내가 각각의 메뉴에 대한 컨트롤러를 따로 만들고, 그 아래에 모델과 뷰를 두었는데
처음에 헷갈렸던 부분이 "해당 컨트롤러는 다른 메뉴의 모델에 접근을 하면 안 된다."
라는 이상한 생각이 박여서 코드를 짜는데 시간이 꽤나 걸렸다.
그러니까 지금 메뉴가 3개가 있다. 상품 추가, 잔돈 충전, 상품 구매 이렇게 3개가 있는데
상품 추가 메뉴에서는 잔돈 충전의 모델에 접근을 하지 말자 라는 이상한 생각이 박여있었다.
해당 모델은 해당 컨트롤러에서만 접근을 하자는 생각이 박여있었다.
(맨 처음 3개의 컨트롤러를 만들고 그 아래 모델과 뷰를 두면서 그렇게 생각이 됐던 것 같다.)
근데 상품 구매 메뉴에서 상품 추가 모델,잔돈 충전 모델에 접근을 하는 것은 불가피했다.
왜냐하면 상품 추가 모델에 추가된 상품들 리스트를 받아오는 로직이 있고,
상품 구매 메뉴에서는 상품 리스트가 필요했다.
근데 생각해보면 모델에서 뷰를 접근했다거나 뷰에서 모델에 접근을 한 것이 아니라서 상관없는데
MVC 패턴이 처음이라서 미숙했던 것 같다. 그리고 MVC의 규칙들을 꼭 지키고 싶었던 마음이 커서
그런 생각이 나왔던 것 같다.
결론: 컨트롤러는 원래 뷰와 모델에 접근할 수 있다.
❓ MVC 구조에 대한 고민
또 MVC에 대한 고민인데, 내가 컨트롤러를 4개 생성하고 각각의 컨트롤러에 대한 모델과 뷰를 또 생성했다.
다른 사람의 코드를 보다가 하나의 컨트롤러, 하나의 뷰, 하나의 모델로 생성한 코드를 보아서
내가 코딩한 구조가 최적인가? 하는 생각에 빠졌다.
프로그래밍에 정답은 없어서 내가 한 것이 최적인지 다른 분이 하신 방법이 최적인지는 알 수 없지만
내가 생각하기로 각각의 메뉴에 따라서 컨트롤러를 따로 생성한 것은 잘한 것 같다.
만약 하나의 M, V, C로 구현을 한다면 vendingMachineController, vendingMachineView, vendingMachineModel
로 구현이 될 것인데, 생각만 해도 코드가 길어질 것이 뻔하다. (내가 짠 방식으로 짜면?..)
남은 기간 동안 어떤 구조로 짜면 될 것인지 전략을 잘 세워야 할 것 같다.
❓ Validator는 클래스로 구현할 것인가 단순 모듈로 구현할 것 인가에 대한 고민
이건 정말 정답이 없는 것 같은데 우선 나는 단순 객체로 구현했다.
왜냐하면 Validator는 상태 값을 가지는 것이 아니라서 따로 내부 변수가 필요하지 않고
함수만 실행하면 되기 때문에 단순 모듈로 구현을 했다.
❓ 컨트롤러의 코드 양이 비대해지는 문제
이 문제는 MVC 패턴의 고질적인 문제라고 나오기도 했는데,
내가 겪어보니까 진짜 그렇더라.
컨트롤러에서 뷰와 모델을 직접 조종을 해야 하고
이벤트 핸들러와 같은 묵직한 메소드들이 들어있으니 어쩔 수 없는 것 같다.
그 안에서 어떻게 깔끔하게 짜는가가 문제인데
최대한 메소드들을 분리하고 해도 메소드가 많아지는 MAGIC...
제출 전까지 최대한 메소드들을 정리를 해서 가독성을 높여야겠다.
📌 프리코스가 끝나고
프리코스가 이렇게 끝이 났다. (아직 제출 하루가 남았지만)
매주 나오는 과제들을 잘 해결하려고 고민하고 후기글 쓰고, 과제 나오면 고민하고 후기글 쓰고
하니까 3주가 그냥 순식간에 사라져 버렸다.
최종 코딩 테스트까지 본격적인 준비는 지금부터 시작인 것 같지만
그래도 3주 동안 진행하면서 개발에 대한 좋은 접근 방식이라던가 좋은 사고방식을 많이 주입받은 것 같다.
학습 방법
매주 전달해주는 피드백에서 힌트를 얻어서 해당 키워드를 공부를 했다.
함수 분리, 메서드 분리, 클래스 분리에 대한 언급이 정말 많아서
클래스 분리에 대한 생각을 정말 많이 했는데 대표적으로 나왔던 것이
바닐라 자바스크립트로 리액트 컴포넌트처럼 구현하기 vs MVC 패턴으로 구현하기
인 것 같은데 나는 MVC 패턴이 View로직이 분리가 되어있고 데이터 가져오는 로직도 분리가 되어있고
하나의 컨트롤러에서 뷰랑 모델만 신경 쓰면 된다는 것이 조금 더 편리하게 느껴졌던 것 같다.
그리고 코드도 조금 더 깔끔하고 폴더 구조도 더 깔끔한 것 같았다.
그리고 예전에는 무턱대고 구현을 시작했는데 요구사항을 먼저 생각하고 정리하고 들어가는 것을 배운 것은 정말 좋은 것 같다.
요구사항을 정리하는데에 약 한, 두 시간을 사용하는데 이후에 정리된 요구사항 덕분에
줄어드는 개발 시간을 생각한다면 앞에 요구사항을 위해서 사용하는 시간이 더 짧을 수도 있을 것 같다는 생각이 들었다.
이번 기능 개발이 끝나면 뭐 구현해야 하지? 이런 생각을 하지 않아도 된다.
사실 그렇게 되려면 완벽한 기능 목록을 만들어야 하는데 그렇게 하기는 정말 어려운 것 같다.
구현을 하다가도 기능 목록은 수시로 바뀌기 때문이고, 생각지도 못한 예외 상황들이 정말 많다.
그래도 처음에 기능 목록을 정리하고 들어가는 것과 아닌 것은 차이가 많이 나는 것을 느꼈기 때문에 앞으로 애용할 것 같다.
피드백에서 말했듯, 살아있는 기능 목록을 만들기 위해서는 처음에 너무 완벽한 기능 목록을 생각하지 말고
요구사항에 나와있는 것들을 잘 정리하고, 순서를 맞추는 데에 신경을 써야 할 것 같다.
내가 얼마나 성장했는가
개발자에게 깔끔한 코드를 짜기 위한 생각을 계속 주입을 해주는 것은 정말 좋은 것 같다.
완벽한 코드는 없지만, 많은 사람이 쉽게 이해하고 알아볼 수 있는 코드는 짤 수 있기에
우리는 거기에 계속 도달하려고 해야 하는데 평소에 코딩을 하다 보면 사실 그게 무시되기 쉽다.
메서드나 함수를 15줄 이하로 구현해야 하고, 변수명 함수명은 줄이지 말고 최대한 의미를 담아야 한다.
띄어쓰기와 커밋 메시지 또한 컨벤션을 맞추어야 한다.
프리코스는 3주 동안 어떻게 하면 깔끔하게 코드를 짤래?라는 질문을 계속 던지게 해 준다.
요구사항을 맞추려고 하다 보면 자연스럽게 떠오르게 되어있다.
이런 생각들을 계속하면서 3주 동안 프리코스가 나에게 습관을 만들어준 것 같다.
프리코스 이후에도 진행하는 프로젝트들은 위와 같은 컨벤션을 지키려고 노력할 것 같고
아닌 것들을 보면 조금 불편해지는... 그런 상황이 오지 않을까?
"깔끔하고 읽기 좋은 코드"에 대한 것이 어떤 것인지 살짝 힌트를 주었고
나는 거길 향해서 방향을 잘 잡고 이후에도 잘 달릴 수 있을 것 같다.
마무리
이제 화요일 자정까지 코드를 조금 더 다듬고 최종 코딩 테스트를 준비를 해야 한다.
5시간 시험이라는 압박이 조금 나의 가슴을 웅장하게 만드는데
작년까지는 그래도 3주 차 과제와 비슷하지만 조금 쉬운 유형이 나오는 것을 봐선
3주 차 과제를 정말 많이 들여다봐야 할 것 같다.
다른 사람의 코드도 많이 읽어보고
미리 만들 수 있는 모듈이나 MVC 패턴에 더 익숙하게 할 것 같다.
최종 코딩 테스트가 벌써 이번 주 토요일로 다가왔는데
벌써 조금 떨리는 것 같고 내가 다 구현할 수 있을까 하는 생각도 벌써 들지만
지금은 내가 할 수 있는 것에 최선을 다하기로 생각했다.
프리코스에 참가하게 해 준 우테코에게 정말 감사의 말을 드리고 싶다.
된다면 더 감사한 일이 내년에도 지속됐으면 좋겠다...!
'우테코 4기' 카테고리의 다른 글
[우아한테크코스 4기] 최종 결과 발표 (0) | 2022.01.01 |
---|---|
[우아한테크코스 4기] 프리코스 2주차: 자동차 경주 게임 회고 (0) | 2021.12.06 |
[우아한테크코스 4기] 최종 코딩테스트 준비 (0) | 2021.11.29 |
[우아한테크코스 4기] 프리코스 1주차: 숫자 야구 게임 회고 (0) | 2021.11.29 |
[우아한테크코스 4기] 1차 합격 및 프리코스 사전 준비 (0) | 2021.11.29 |