상당히 오랜만에, 약 3개월만에 글을 업로드하는데, 그동안 굉장히 바빴다.
운좋게 인턴을 시작하기도 했고, 복학을 슬슬 준비하기도 하고, 무엇보다 피키팜일로 굉장히 바빠졌다.
그 와중에 설날 즈음에서 새로운 기능을 도입했는데, 5일만에 설계에서 배포까지 완료한 아주 지옥의 스케쥴을 회고해보면서 어떻게 빠르게 달렸는지를 다시한번 떠올려보려 한다.
1월 초였던가,,, 설날을 준비하면서 새로이 "선물하기" 기능을 추가하자는 얘기가 솔솔 들어왔다. 사실 주문하기 시스템은 개발을 한번도 안해본 초기에 작성해둔 코드에 요구사항에 의해 새로운 코드를 덧붙이는 식으로 붙여나가다 보니... 가독성은 물론이고 버그 찾기도 더럽게 어렵고... 근데 거기에 새로운 기능까지 추가하자니 이거 머리가 참 아팠다. 과연 이거 가능한 일인가...
결제에 새로운 코드를 집어넣자니 사실 중요한건 클라이언트단의 코드보단 서버사이드의 코드였다. 결제 시스템의 코드는 상당히 더럽고 복잡한 상태인데,,,
그리하여 새로운 기능 개발에 앞서 기존의 코드부터 리팩토링하고 가는것이 우선이라 생각이 들었다.
현재 피키팜의 결제 시스템은 주문 정보를 생성 -> 갱신 -> 검증 하는 3개의 단계를 거친다.
그러니 그 말은 곧 함수가 3개가 만들어지는 것 인데, 주문 모델 객체에 대해 정보를 업데이트하고, 유효성을 검증하는 등의 코드가 상당히 많은 부분에 대해 중복되어 있었다.
주문 시스템의 프로세스를 정리하고, 중복되는 로직을 통합해서 하나의 함수로 묶기 시작했다.
이런 식으로 Django의 모델 클래스 메서드를 통해 기존 views에 파편화되어 있던 특정 로직들을 모델로 위임함으로서, 조금 더 각 모델의 역할을 명확히 정의할 수 있게 되었다.
이번 프로젝트에 있어, 나는 전체 프로젝트의 총괄을 맡음과 동시에 프론트엔드를 총괄하여 담당하였다.
기존 결제하기 페이지의 프론트엔드(라고 하기도 뭐할정도로 조잡했었다. 난 그래서 개인적으로 "프론트엔드"라는 단어가 굉장히 낯간지럽다. 클라이언트 사이드라고 말하는편)는 이런식으로 동작했었다.
querySelector()
를 통해 DOM에 직접 접근해서 값을 바꾼다.JS를 잘 몰랐던 시절엔 저게 최선인줄 알았더만, SPA에 대해 조금만 공부해도 2번같은 방식이 얼마나 충격적일정도로 무식한 행동이었는지 깨달았던 경험이 있다. 다만 결제 페이지를 바꾸는건 큰 리팩토링이니 감히 손을 못댔었는데, 이번에 새로운 페이지 개발 수요에 맞춰 아예 결제 페이지를 프레임워크를 적용해서 개발하기로 결심한다.
결론부터 말하자면, 이 프로젝트의 클라이언트 사이드에는 Vue.js가 사용되었다.
리액트를 사용하는게 좋지 않나 생각했지만, Django 기반의 전형적 정적 웹 형태인 피키팜은 webpack, babel의 사용이 거의 필수인 리액트 생태계 특성상 빠르게 빌드 파이프라인을 구축할 시간도, (개발할 시점의)나의 node 생태계에 대한 이해도도 매우 부족했다.
그래서 대안으로 생각한것이 webComponent
였다. 컴포넌트 단위의 개발에 이미 익숙하고, 리액트의 생명주기 메서드의 기반이 되는 메서드들이 많았기 때문에 괜찮다고 생각했는데, 프레임워크가 아닌 바닐라인 특성상, 데이터의 갱신이 자동으로 리렌더링으로 이어지도록 하는 방법에 대해 빠르게 답이 나오지 않았다.
그때 마침, 인턴을 진행하던 회사에서 Vue.js를 이용한 프로젝트를 주셨는데, 정적 웹에 CDN으로 Vue를 불러와 빠르게 SPA를 개발할 것을 지시하였다. 기존의 리액트를 기초를 갓 뗀 정도의 이해도를 가지고 뷰의 공식 문서를 이해하는데는 처음 3일이 고비였고, 튜토리얼을 차분한 마음으로 따라하다 보니, 뷰의 특징으로 뽑히는 낮은 러닝커브가 어떤 의미였는지 바로 와닿게 되던 것이었다. 그래서 다음의 이유로 vue를 다음 프로젝트에 도입하기로 마음먹었다.
디렉티브란 아주 간단하게 말해서, HTML에 JS 표현식을 넣어 표현식의 값이 변경될 때 그 값을 DOM에 적용하는 것인데, 개인적으로 Vue의 러닝커브를 매우 낮추는 요인중에 하나라는 생각이 든다.
피키팜의 선물하기는 선물 받는 사람의 주소를 아는지에 대한 여부에 따라 입력창의 갯수가 달라진다.
번호만 알아요
를 클릭하면 주소 란이 사라져야 하는데, 기존의 개발 방식을 유지했더라면 단순히 css의 display
를 이용해 눈속임만 했을것이다. 하지만 v-if
디렉티브를 통해 주소입력 폼을 조금 더 효율적으로 관리할 수 있었다.
또한 여러명의 친구에게 보내고 싶을 때, 친구 더 추가하기
버튼을 클릭하여 선물을 받을 친구를 추가할 수 있다.
이 경우 원래 개발하던 방식이었다면, 저 추가되는 친구 부분의 전체 HTML 코드를 동적으로 기존의 HTML에 삽입하는,,, 아주 무식하기 그지없는 방식을 사용했었겠지만... v-for
디렉티브를 이용해, 친구 목록 배열에 새로운 엔트리를 추가하면, 뷰의 반응형 시스템에 의해 새로운 친구 row가 추가된다.
사실 프레임워크를 도입한 가장 큰 이유중 하나는 상태관리 때문이다.
개별 친구의 수량을 조정하면 개별 친구에 대한 금액이 자동으로 계산되고, 주문 갯수도 계산되고, 총 금액마저 자동으로 계산된다. vue의 computed
속성을 이용하여 상태 변경에 맞춰 값이 자동으로 계산되니 여간 편한게 아니다.
computed: {
numberOfFriend: function () {
return this.friends.length;
},
sumOfQuantity: function () {
// friend들의 quantity의 합계 구함
return this.friends.reduce(
(prev, next) => prev + (parseInt(next.quantity) || 1),
0
);
},
sumOfDeliveryFee: function () {
return this.friends.reduce(
(prev, next) => prev + parseInt(next.deliveryFee) || 0,
0
);
},
sumOfProductPrice: function () {
return this.sumOfQuantity * this.productPrice;
},
orderTotalPrice: function () {
return this.sumOfDeliveryFee + this.sumOfProductPrice;
},
},
이런식으로, quantity만 바꾸면 다른 값들이 자동으로 계산된다.
이전엔 이걸 어떻게 처리했었냐면,,,
불편
결국 Vue.js를 적용해서 불가능할것만 같았던 살인적인 계획에 맞춰 새로운 기능을 제때 배포할 수 있었다. 이 과정에서 Promise
의 적용 등 더 깊은 내용에 대해서는 다음에 다뤄보고자 한다.
리액트와 비교해보면, 확실히 SPA 개발을 새롭게 시작하는 사람들에게는 리액트보단 뷰가 훨씬 쉽게 시작할 수 있을것이라 생각이 든다. node.js 환경에서의 빌드가 익숙하지 않은 사람이라면 더욱이 CDN 방식으로도 편하게 개발이 가능한 뷰가 어떨까 싶다. 특히 JSX나 hooks같은 개념은 러닝커브가 살짝 있을 수 밖에 없다고 생각이 들고, v-model
디렉티브 덕분에 인풋 처리가 매우 간단해진다는 점이 리액트 대비 엄청난 장점이라고 생각한다.
프론트엔드 진영에서 이제는 더 이상 무시할수 없는 정도의 존재감을 가질 정도로 성장한 svelte 또한 뷰와 문법이 상당히 비슷하다. 이러한 점에서도 뷰의 영향력이 점점 커질것 같다는 생각이 든다.
프레임워크 아래 개발을 하다보니 상태관리를 이전보다는 조금더 제대로 할 수 있어서, 버그관리 측면에서 홀가분해진 기분이다. 다만 너무 급하게 개발을 하다 보니 놓친 몇몇 부분들이 있는데 꼭 리팩토링을 통해 적용해보고 싶은 것들이 있다.
vue-test-utils
와 Jest
를 사용해 유닛 테스트에 대해 좀 공부했었는데, 얼른 적용해보고 싶다는 생각이 든다.