이번에 테오 스프린트 14기에 참여하며 구글 스프린트(커스텀 by 테오)라는 협업 방식이 어떤 것인지 맛 볼 수 있었다. 새로운 아이템을 서비스로 만들어내는 데는 내가 접해본 방식들 중 최고라고 생각할 만큼 효과적이었다. 어떤 점이 좋았는지, 다음에 보완해야 할 점은 무엇인지 등의 스프린트 자체에 대한 회고는 피그잼과 개인적인 일기에 적었다. 때문에 오늘은 기술적으로 복기할 만한 점들을 회고해보도록 하겠다.
맡았던 부분
우리 아이디어는 벚꽃 시즌에 맞춰 초대장을 작성하고 꾸며 그것을 공유할 수 있는 웹 서비스다. 최근에 간단한 CRUD 말고 색다른 기능을 개발해보고 싶다는 생각이 들어 Interactive Developer의 코드를 따라해보는 등의 시도를 했었다. 같은 이유로 캐릭터/스티커를 드래그앤드롭해서 초대장을 꾸미는 기능을 하고 싶다고 어필했고, 해당 기능을 맡게 되었다. 데모 버전에는 MVP만 넣기로 하면서 드래그앤드롭 기능 대신 클릭한 좌표를 계산해 거기에 캐릭터/스티커를 렌더링하는 기능을 개발하게 되었다.
기여한 부분
크게 보면 맡았던 부분인 클릭 좌표 이미지 렌더링
기능을 완성했다. 세부적으로는 관련된 여러 로직을 생각해내고 대부분 완성했다.
첫 번째로, 클릭한 아이템 종류에 따라 textarea readOnly 여부를 다르게 하는 로직을 생각해냈다. 기획 단에서 생각 못했던 문제인데, 현재 선택한 아이템에 따라 textarea 편집 가능 여부를 다르게 해야했다. 현재 배경 카테고리를 선택하고 있거나, 캐릭터/스티커 카테고리여도 선택한 아이템이 없으면 textarea를 편집해도 상관 없다.
그러나 캐릭터/스티커 카테고리인데 어떤 아이템을 선택하고 나면, 초대장 영역을 클릭하는 유저의 행위는 곧 아이템을 생성한다는 의도이다. 그런데 textarea 영역 내부를 클릭했다고 해서 아이템이 생성되면서 동시에 textarea 커서가 focus 된다면 명백한 오류 상황이 되는 것이다. 유저의 의도는 아이템 생성이었기 때문이다. 그러므로 카테고리와 아이템 클릭 여부에 따라 textarea의 readOnly 속성의 boolean 값을 다르게 주는 로직을 작성했다.
두 번째로, 세션에 현재 상태를 저장하고, 완성한 이후 초대장 재작성 버튼을 클릭하면 다시 복구하는 코드를 작성했다. 선택한 배경의 종류와 캐릭터/스티커의 위치 좌표들을 세션에 저장해 놓는다. 컴포넌트가 렌더링 될 때 세션을 불러와 저장된 것이 있으면 화면에 표시하도록 했다.
textarea의 경우가 애매했는데, 매번 유저가 텍스트를 입력할 때마다 세션에 저장하기가 애매했다. 디바운싱을 적용할지, 초대장 생성하기 버튼이 클릭됐을 때 저장할지 고민하다가 텍스트는 세션 저장을 아예 하지 않는 방향으로 갔다. 그 당시에는 텍스트는 굳이 저장하지 않아도 되겠다고 생각해 그랬는데, 지금 생각해보니 반드시 필요한 기능 같다. 다음 주에 개발할 때 이 기능을 추가해야겠다.
세 번째는, 좌표 계산이었다. 여기가 가장 시간이 많이 들었던 부분이었다. DOM 요소의 좌표에 대한 것은 top, left 정도만 알고 있었지 다른 API는 몰랐기 때문이었다. getBoundingClientRect, event.clientX/Y 등 구글링으로 좌표에 대한 API들이 금방 나오긴 했는데, 유저가 지정한 위치 좌표가 초대장을 받는 사람의 디바이스에서도 같은 위치에서 보여야했다. 초대장 자체는 고정 px 만들어 크기가 동일한데, 초대장의 시작 좌표가 디바이스마다 다르게 보였다. 그러므로 디바이스마다 클릭한 위치의 좌표가 달라지는 것이다.
결국 화면 기준의 좌표가 아니라, 초대장 영역 기준에서의 offset을 구해야했다. 화면 기준 클릭한 좌표에서 초대장 영역의 시작 좌표를 빼서 초대장 영역 기준의 offset X, Y를 구했다. 간단한 발상이지만 당시엔 잘 떠오르지 않아 제법 머리를 쥐어 뜯게 만들었었다.
아쉬웠던 부분
드래그앤드롭 보다 쉽다고 생각한 클릭 기능으로 MVP를 잡았지만 그것도 쉽지만은 않았다. 애초에 Element의 offset, left, top 등 좌표를 다루는 개발을 해본 적이 없기 때문에 모든 것이 생소했기 때문이었다. 많은 시행착오를 거쳐 어떻게든 기능을 구현하긴 했지만, React를 사용하면서 DOM을 직접 붙혔던 것이 가장 아쉽다. DOM 요소를 직접 가져오지는 않고 ref를 사용해 리액트 DOM을 가져오는 것까지는 생각했다. 거기까지 생각했으면서 캐릭터/스티커를 동적으로 만들어 초대장에 붙힐 때 별 생각 없이 document.createElement로 진짜 DOM 요소를 만들어 React DOM 트리에 붙혀버렸다. React스럽게 DOM 조작을 하지 못한 것 같아 아쉽다.
배포해서 직접 사용해보니, 배경/캐릭터/스티커의 카테고리를 바꿀 때마다 이미지를 새로 불러와 로딩이 길었다. 다시 작성하기 혹은 새로고침으로 기존 설정을 다시 불러와 리렌더링을 할 때도 에셋들을 불러오는 시간이 길게 느껴졌다.
이번에 프론트엔드 스터디에서 useEffect를 공부하며, React 공식 홈페이지에서 관심사가 다른 effect는 분리하는 것이 좋다는 문구를 봤다. 하나의 useEffect Hook 안에 모든 업데이트 로직을 다 넣어뒀었는데 가독성이 좋은 것 같지 않다. 마찬가지로 내가 작성한 Display 컴포넌트 안에 모든 코드가 다 몰려있다. JSX 자체는 짧아서 분리할 것이 없지만, 컴포넌트 안에서 선언한 함수들이 너무 많아 가독성이 좋지 않다.
개선/추가할 부분
- DOM 조작 React스럽게 바꾸기
- 컴포넌트 에셋 로딩 최적화
- DOMuseEffect 관심사에 맞게 분리
- 현재 코드가 Display 컴포넌트에 몰려있는 코드 분리
- 캐릭터/스티커 생성 방식 클릭 -> 드래그앤드롭 방식으로 바꾸기
- 캐릭터/스티커 clear 버튼
- 디테일한 디자인 수정
후기
기획 3일 + 개발 3일, 총 6일의 짧은 시간 안에 데모 서비스를 만들어냈다. 유저가 클릭한 좌표를 찾고 거기에 이미지를 렌더링하는 작업을 맡게 되었다. 해본 적 없었기 때문에 도전해보고 싶어 자진해서 이 작업을 맡았고, 여러 시행착오를 겪은 후 결국 시간 내에 해냈다. 그 과정에서 몰입해서 무언가를 하는 기분을 오랜만에 느낄 수 있었다. 평소에 취준을 할 때는 오래 집중하지 못해 시간을 허비하는 경우가 많았는데, 이번 개발 과정에서는 오로지 개발에만 집중했다. 잡념은 아예 들지 않았고 시간 가는줄 모르고 개발했다.
무엇이 이런 차이를 만들어 냈는지 고민해봤다. 취준 할 때와 이번 스프린트와의 차이점은 목표가 확실했고 데드라인이 있었다는 점이다. 눈에 보이는 확실한 목표와 시간 제한이 내가 몰입하기 위한 요소라는 것을 알게 되었다. 당연한 말이긴 하지만 다시 한번 새기고 이 요소들을 활용해 앞으로 어떤 작업이든 몰입하는데 적용해봐야겠다.
'개발 > 프로젝트' 카테고리의 다른 글
Technical challenges in Teo Sprint (0) | 2023.04.03 |
---|