배울 때는 다 잘 이해했다고 생각했는데 막상 프로젝트 들어가니까 생각보다 모르는 게 너무 많아서 당황스러웠다. 모르는것도 모르는거지만 안다고 생각했던 것들이 사실 알고있는 것이 아닌 게 더 충격이었다.
원래는 모로 가든 작동만 하면 된다고 생각했는데 효율적이지 못해서 코드를 통채로 갈아엎는 걸 몇 번 하고 나니까 구현이 된다고 끝나는 게 아니구나 싶었다. 앞으로는 왜 이게 돌아가고 어떻게 하면 더 좋은 방법이 있을까 고민해야 한다.
팀 프로젝트였기 때문에 혼자서 공부할 때는 배울 수 없는 점이 있었다. 서로 코드를 유기적으로 맞추면서 마찰이 생길 때 어떤 방법이 좋을까를 고민하게 되었고 이 과정이 발전에 많은 도움이 되었다.
이번에는 내가 약간 뒷 부분의 역할을 맡아서 다른 사람이 가공한걸 받아서 쓰느라 나의 생각과 다르게 초기 설정이 된 부분들이 있었는데 다음에는 처음부터 참여해서 그런 충돌이나 아쉬운 점이 없게 해야겠다.
혼자 배울 때는 딱 한 파일이나 한 기능에 집중해서 전체적인 흐름은 모르고 나무에 집중해 있었다면 조금이나마 규모가 커진 프로젝트를 하니 숲이 보여서 신기했다. 링크와 파일과 라우터가 어떤 식으로 연결되는지의 유기적인 흐름이 흥미로웠다.
이 방법이 좋을까 저 방법이 좋을까 고민했을 때 딱 떨어지는 명확한 정답은 잘 없었다. 모든 코드에는 장단점이 있고 특징을 잘 활용해야 좋은 코드를 짤 수 있다. 특히 프론트는 눈 깜짝하면 코 베이듯 빨리빨리 바뀌는 경향이 있어 조심해야 한다.
장바구니의 수량버튼을 구현할 때 분명히 잘만 했는데 버튼이 작동을 안했다. 완전히 안 하는 것도 아니고 됐다 안됐다 했다.
뭐가 문제일까 삽질을 엄청나게 하다가 DOM 로딩 순서의 문제인가 하는 생각이 퍼뜩 떠올랐다(유레카!)
해결하는 데에도 많은 삽질을 했다.
처음은 window.onload와 document.ready를 생각했다. window.onload는 모든 콘텐츠가 로드된 후에 실행되기 때문에 로딩 시간이 너무 길어졌고 document.ready는 jquery를 사용하지 않아서 도입이 불가능했다.
찾다보니 document.ready를 바닐라 자바스크립트로 구현하는 방법을 찾아서 Domcontentloaded를 적용하려고 했다. 그러나 이것도 순서 문제로 골머리를 앓던 중 코치님께 .then 체인으로 바꾸라는 조언을 받았다.
맙소사 이렇게 돌고 돌았는데 최종 해결책은 제일 기본으로 알고 있던 .then이었다니! 이틀 내내 고민하던데 무색할 정도로 금방 해결돼버렸다. 역시 이래서 기본이 탄탄한게 제일 중요한가 보다.
(+추후 이것도 기능은 잘 작동하나 체이닝이 길어져서 가독성이 떨어진다는 평가를 받고 async-await으로 리팩토링 하였다.)
장바구니 수량 조절 버튼이랑 삭제 버튼을 작동시키는 것이 꽤나 큰 문제였다. 내 머리로 할 수 있었던 생각은 조절 버튼들을 하나씩 다 가져와서 parentnode로 해당 상품 행을 찾고 addeventListener를 일일이 다는 하드코딩 뿐이었다.

코드가 말도 안되게 복잡해지고 가독성이 떨어져서 이건 아닌 것 같았다. addeventListener가 많아지면 브라우저의 성능이 떨어진다는 이야기도 생각났다.
구글링과 조언 수소문 끝에 이벤트 위임이라는걸 알았다. 부모 element(여기서는 내가 찾으려던 상품 행)에 이벤트를 위임하고 내가 원하는 버튼을 제외하고는 비활성화 시켰다.

이렇게 보니 코드 양이 크게 줄진 않았지만 퀄리티는 훨씬 올라간게 확실하다!
(+이벤트 위임/버블링/캡쳐링은 공부한 걸 따로 올릴 예정이다.)

선택 삭제에서 버그가 발생했다. 상품이 여러 개 있을 때 중간 제품을 삭제하고 남은 제품의 수량을 조절하면 수량조절이 안 됐다.
$quantityInput[quantity]로 수량 element를 선택했더니 전체 수량을 따르는 $quantityInput의 길이는 감소되었는데 개별 상품에 붙는 data-quantity는 원래의 번호로 고정돼 있어 undefined가 뜨는 것이 문제였다.

처음에는 forEach를 돌면서 해당 quantity 값을 속성값으로 가지고 있는 태그들을 일일이 골라내었다. 그러나 버튼을 한 번 클릭할 때 마다 forEach를 도는 것은 성능을 너무 떨어트렸다.
내가 저런 이상한 코드를 짰던 이유는 $quantityInput은 array가 아닌 HTMLCollection이라 find나 map같은 배열의 메소드를 적용시킬 수가 없었기 때문이었다. 그러나 rest operator(...)로 간단하게 HTMLCollection을 배열로 바꿀 수 있었다. (ES6를 적극 활용하라는게 이런 말이었나 보다!)
[...$quantityInput].findIndex(input => input.dataset.quantity === quantity);
최종적으로는 이렇게 quantity를 데이터 속성으로 가지고 있는 element의 index를 찾아서 해결했다.

위 사진에서 for 루프로 같은 내용을 찍으면 잘 보이는데 주석처리된 forEach로 했을 때는 뭔가 이상했다. incartList를 콘솔에 찍으면 내용물이 보이긴 하는데 [{...}, {...}]로 안나오고 [ ]로 빈 배열처럼 나오면서 length가 0으로 나왔다. 요소가 들어 있는데 길이가 0인 배열이 있다?! 세 명이서 머리를 맞댔으나 혼란 그 자체였다.
처음에는 forEach의 문제인 줄도 모르고 for로 할 생각은 전혀 못했다. 그러다 res와 incartList를 동시에 콘솔에 찍어보니 res가 더 늦게 출력되었다. forEach 내부의 문제인 것 같긴 한데 async-await을 잘 달아줬는데 왜 비동기가 제대로 처리되지 않는 모양일까?
이것 저것 고치다 for로 고치니 해결되었고 원인은 forEach의 병렬처리였다. (참고한 글) forEach는 배열 요소를 돌면서 callback을 실행하긴 하지만 내부에서 비동기 처리가 일어나는지 아닌지에는 관심이 없다. forEach 내부의 비동기 코드는 동기 코드가 모두 실행 된 뒤에야 태스크 큐에서 꺼내져 실행된다.

상품 상세페이지-장바구니-결제 페이지로 연결되는 흐름에 세션스토리지로 데이터를 옮겼는데 약간 애매하게 활용한 셈이 되었다.
원래는 카트에 담은 제품을 바로 세션에 각각의 field로 올리는게 아니라 따로 배열에 모았다가 세션에도 하나의 field에 배열로 올려서 관리해야 한다. 그러나 우리의 서비스는 상품 하나하나가 개별적으로 세션스토리지에 올라가게 되어있었다. 이렇게 넣고 나니 장바구니에서 전체삭제나 선택삭제를 할 때 또 루프를 돌아서 해당 상품에 대한 세션값을 삭제하게 되었다. (정석대로 했으면 장바구니 상품에 대한 배열 하나만 업데이트 하면 되었다.)
더 심각한 것은 원래 정보를 관리하는 주체는 세션이고 프론트는 그걸 시각화해서 보여주기만 하는 역할인데 지금 코드는 프론트에서 정보를 가져다 가공해서 세션에 업데이트 하는 방식이라 주객이 전도된 활용이었다. 그러나 마감이 이틀도 채 남지 않은 상황에서 거의 통채를 갈아엎을 수는 없었고 아쉽지만 기능은 잘 작동하니 그대로 두기로 결정했다.
그리고 맨날 듣기만 하던 애자일(agile) 방법으로 진행했는데, 최소 기능 단위인 MVP를 설정하고 단기간 내에 완성하는 방식이 너무 잘 맞았다!
나는 정확하고 구체적인 목표와 단기간의 시간 설정이 있어야만 집중이 잘 되고 늘어지지 않는 타입이라 빠른 시간 내에 완성해야 할 todoList를 정하고 완성하고 다시 정하고 완성하는 방식이 효율을 최고로 끌어올려 주었다.
다만 초반에 너무 빡빡하게 달리려고 하다가 마무리할 때 즈음에 지친 부분이 아쉬워서 다음에는 체력 분배를 더 신경써야겠다.