IT/SSAFY

[SSAFY 7기] 특화 프로젝트 '여행조각' 회고

무녈 2022. 10. 31. 02:07

SSAFY 협업 프로젝트 2번째, 특화 프로젝트를 무사히 마무리 한지 3주가 지났다. 블록체인 NFT 기술을 활용한 프로젝트를 진행하며, 이전과 다른 성장 또는 퍼포먼스와 기능을 보여주기 위해 어떤 노력을 했는지, 아쉬웠던 점들은 어떤 것들이 있는지에 대해 회고로 작성해서 글을 남겨보자 한다.

여행조각 로고

NFT를 활용한 서비스를 기획하는 것에 생각보다 많은 어려움을 겪었었다. 처음 기획 당시에는 유서를 활요한 유서 꾸미기를 할까라는 식으로 접근을 했는데, 막상 서비스로 구현을 하려고 하니 법적인 효력부터 실제 서비스가 나왔을 때 너무 어두운 분위기일 것 같아서 최초 기획을 엎어버렸다. 막상 NFT 서비스로 구현할 수 있는 것들이 너무 한정적이라 뒤늦게 해당 주제를 선정한 것에 아쉬움을 느끼긴 했지만, 또 다른 팀원의 적극적인 아이디어로 "여행 조각"이라는 서비스를 만들어 낼 수 있었다.

 

해당 서비스에서 나는 프론트엔드 개발로 참여하였고 아래의 기능을 직접 구현하게 되었다.

🧑🏻‍💻 담당 역할

  • 여행 일정 등록 · 수정 · 삭제 · 조회 기능
  • 여행 다이어리 작성 · 수정 · 삭제 · 조회 기능
    • GPS 기반 위치 정보 조회, 날씨, 다이어리 글씨, 다이어리 글 작성, 사진 업로드
    • NFT 스티커로 다이어리 꾸미기
    • 스티커 프레임 스크린샷 및 프레임 공유
  • 공유 프레임 조회 기능
    • 전체 및 지역별 조회
  • 공유 프레임 상세 페이지 스티커 렌더링
    • 스티커 위치에 따른 tooltip 방향 제어
    • 스티커 tooltip 클릭 시 마켓 연결
  • 'Recoil', 'React-Query'를 이용한 상태 관리
  • 'Mock Service Worker'를 이용해 목업 API 구현 및 API 테스트 진행

📌 다이어리 작성 & 수정 기능

다이어리 작성 및 수정 기능에 정말로 많은 기능과 시간이 투자되었지만, 어디서도 말할 수 없었기 때문에 회고에서 자세하게 어떤 기능들이 있었는지 남겨야겠다.

  • 최초 여정 등록 시 해당 가능한 날짜에만 다이어리 작성이 가능하다.
  • 여정 등록은 등록 당일 기준부터 가능하며, 과거는 등록되지 않는다.
  • 다이어리 작성은 미리 되지 않으며, 여행 당일 또는 이후에만 작성이 가능하다.
  • 다이어리 목록 페이지 진입 시, 당일이 여행일이면 오늘 날짜의 일기를 가장 먼저 보여주어야 하며, 여행 기간이 아닐 경우 일기를 작성할 수 없다는 화면을 보여주어야 한다. (URI로 인위적으로 접근할 경우까지 모두 고려하였다)
  • 다이어리 작성 시 다이어리 목록 페이지에서 자동으로 가져오며, URI로 접근할 경우 이전 페이지로 보내야 한다.

  • 다이어리 작성 기능
    • 날씨를 선택할 수 있다.
    • 글씨체를 선택할 수 있다.
    • 다이어리 배경 색상을 선택할 수 있다.
    • 다이어리 작성 시 글자수를 한정하지 않는다.
    • 반응형으로 viewport에 맞추어 글씨 크기가 바뀌어야 한다.
    • 하나의 이미지를 업로드할 수 있다.
    • 이미지 업로드 경우 jpg, jpeg, png로만 한정한다.
    • 업로드 이미지 용량을 제한하지 않고, 서버 저장 시 클라이언트에서 이미지 리사이징을 통해 2MB 이하의 이미지로 리사이징 한 것을 저장한다.
    • 반응형으로 viewport에 맞추어 이미지 비율이 바뀌어야 한다.
    • 다이어리 작성 시 현재 위치를 보여준다.

 

 

 

  • 다이어리 꾸미기
    • 본인의 meta mask에 보유한 NFT 스티커 목록만 가져온다.
    • 보유한 스티커 사용 개수의 제한은 없다.
    • 목록에서 스티커를 클릭할 경우 다이어리에 추가된다.
    • 드래그를 통해 쉽게 이미지 위치 변경이 가능해야 한다.
    • 스티커 위치는 다이어리 작성 범위 내(일기 내용 + 사진)에서만 가능하다.
    • 반응형으로 viewport에 맞추어 스티커 크기가 바뀌어야 한다.
    • 반응형으로 viewport에 맞추어 스티커 위치가 바뀌어야 한다.
    • 스티커 삭제가 가능해야 한다.
  • 스티커 프레임 공유
    • 스티커 프레임 공유를 선택할 수 있다.
    • 프레임 공유를 선택하고 다이어리 작성 완료를 누르면 일기 내용과 사진을 제외한 스티커만 캡처가 되어야 한다.
    • 캡처를 위한 모달 페이지에 스티커 크기가 모달 크기에 맞게 변형되어야 한다.
    • 스티커 위치가 모달 크기에 알맞은 위치에 해당해야 한다.
  • 다이어리 작성 완료 후 다이어리 목록 페이지에서 작성한 다이어리를 보여준다.
    • 작성한 글씨체, 다이어리 배경, 일기, 사진, 스티커가 나타난다. 
    • 반응형으로 viewport에 맞추어 글씨 크기, padding, 사진 크기, 스티커 크기가 동일한 비율로 변경되어야 한다.
    • 반응형으로 viewport에 맞추어 스티커 위치가 바뀌어야 한다.

 

📍 프로젝트에서 시도한 것 또는 배운 것

  1. web 3.0
    이번 프로젝트에서는 metamask 기반의 NFT를 활용해야 했기 때문에 web3.0js를 반드시 활용해야 했다. 클라이언트에서 블록체인을 활용하기 위해서는 web3.0이 기본이 되어야 한 다는 것을 알게 되었고, 해당 부분을 학습하며 web3.0이 어떤 것인지 알게 되었다.
  2. React-Draggable
    스티커 꾸미기 기능을 사용하기 위해 스티커를 화면에 띄우고 자유자재로 위치시켜 사용자가 마음대로 다이어리를 꾸밀 수 있게 해야 했다. 예전에 react-draggable이라는 라이브러리를 본 적이 있었기 때문에, 이번 프로젝트에서 사용해보면 되겠다고 생각했다. 해당 기능을 구현 및 적용해야 하는 것들이 기능을 구현함에 따라 정말로 많았다. 이미지 드래그에 따른 좌표 위치를 기록해야 하며, 뷰 포트에 크기에 따라 위치를 변경시켜야 했기 때문에 온전히 기능을 구현하는 데 많은 시간이 들었다.
  3. useSize custom hook (useLayoutEffect, resizeObserver API)
    다이어리 작성 또는 꾸미기 시 viewport에 맞추어 글씨 크기와 이미지의 좌표가 변경되어야 했다. 해당 기능을 구현하기 위해 useRef로 다이어리 DOM을 관찰하는 방식을 통해 해당 기능을 구현하려 했으나, 반응을 즉각적으로 감지하지 못해 해당 기능을 구현하지 못하게 되었다. 그다음 시행착오를 통해 window.addEventListener("resize", handleResize)를 통해 viewport가 resizing 될 때 DOM의 크기를 변형시키는 방식으로 변경했을 때 width의 변화는 잘 일어났으나 height가 비율에 맞게 위치 및 크기가 변하지 않는 문제가 있었다. 그러다 구글링을 통해 useLayoutEffectresizeObserver API를 발견하게 되었고, 해당 기능을 조합한 useSize라는 커스텀 hook을 만들어 view 크기 변화에 따른 위치 및 크기 변화 기능을 구현할 수 있었다.
    이번 프로젝트를 수행하며 다양한 커스텀 
  4. 스크린숏 (html2 Canvas)
    다이어리 작성자의 사생활 보호를 위해, 다이어리 내용 및 사진을 제외한 스티커 프레임만 공유를 하기로 결정했다. 해당 기능을 구현하기 위해서는 우선 스크린샷을 찍어야할 필요가 있었다. 기존 다이어리 꾸미기 페이지 자체를 캡쳐했을 때 글자와 업로드한 사진을 제외할 수 없었다. 그래서 프레임 공유 버튼을 클릭했을 때 모달에 스티커를 렌더링 시키고 해당 DOM을 캡쳐하려고 했다. 문제는 이미지가 IPFS에서 가져왔기 때문에 스크린샷을 찍으면 외부 이미지가 찍히지 않는 문제가 발생했다. 우여곡절 끝에 html2Canvas라는 라이브러리를 활용해서 공식문서에서 방법을 찾아 해결하게 되었다...
  5. 이미지 리사이징 (browser-image-compression)
    예전에 본 면접에서 이미지 핸들링과 관련된 질문을 받은 경험이 있었다. 사용자의 이미지를 별도로 핸들링함으로써 이미지 서버와 클라이언트 렌더링 시 최적화를 위한 경험이 있는지 물어본 것이었다. 그 당시까지만 해도 사용자가 업로드한 이미지 용량 및 확장자만 제어했다고 대답했었다. 그렇다면 클라이언트에서 별도로 이미지 리사이징이 가능할 것이라는 생각이 들어 찾아보게 되었다. "여행조각" 서비스 자체는 모바일 크기에 최적화했기 때문에 굳이 큰 용량의 이미지가 필요 없었고, 용량 제한을 두어 사용자가 이미지 크기를 변경해서 올리는 등의 번거로움을 해소하는 것이 서비스를 사용하는 사용자 경험이 더 좋을 것이라 생각했다. 이미지 리사이징을 위해  browser-image-compression 라이브러리를 사용하게 되었고, 리사이징을 통해 이미지 서버 자체에 부담을 줄일 뿐만 아니라, 용량을 줄여 이미지 렌더링 시 퍼포먼스를 측정한 결과 LCP를 크게 감소시킬 수 있었다.
  6. 코드 스플리팅
    '더민트' 프로젝트에서 역시 퍼포먼스 점수를 크게 향상하지 못해 아쉬웠던 경험이 있었다. 그렇기 때문에 이번에 더욱 퍼포먼스 성능 향상을 위해 다양한 시도를 해보게 되었다. 우선 다양한 라이브러리를 활용한 파일을 하나의 파일로 빌드를 했기 때문에 파일의 크기가 상당히 컸었다. 이번에는 router의 페이지 별로 React.lazy를 사용하여 코드 분할 처리를 해주었다. 번들을 분할하여 최초 로딩 시 빌드 파일의 크기를 줄일 수 있었다. 
  7. 공유 프레임 스티커 위치에 따른 tooltip 방향 제어
    공유 프레임 상세 페이지를 들어갔을 경우, 각각의 스티커 정보를 얻을 수 있고, 마켓으로 이동이 가능하도록 구현하였다. 스티커를 클릭할 경우 tooltip을 통해 마켓으로 바로 이동할 수 있도록 설계를 했다. 처음에는 스티커를 클릭하면 스티커 바로 위에 tooltip이 나타나게끔 구현을 했으나, 스티커의 위치에 따라 다이어리 최상단에 위치할 경우 tooltip이 다이어리 범위를 벗어나고, 좌 또는 우측에 위치할 경우 tooltip이 잘리는 문제가 발생했다. 이러한 것을 방지하기 위해 각각의 이미지 위치에 따라 tooltip의 방향을 제어하도록 구현했다.

 

✅ 프로젝트에서 아쉬운 점

  • 메타 마스크의 앱의 문제점
    블록체인을 직접 구현하는 것이 아니었고, NFT를 활용한 플랫폼을 만드는 것이었기 때문에 이더리움 test coin을 사용하기 위해 반드시 metamask를 사용해야했다. 우선 프로젝트 기획 당시 여행 중 NFT 스티커 발급을 qr 형식으로 했기 때문에 모바일이 접근성이 더 좋을 것이라 생각하여 모바일 최적화 웹 뷰를 만들어야했다. 개발 중 첫번 째 문제는, SSAFY에서 제공해준 test coin을 상요하기 위해 SSAFY 네트워크에 접속을 해야 했는데, SSAFY에서 제공해준 네트워크는 "http"였고, 웹에서는 사용이 가능했으나 메타 마스크 앱에서는 "https"아니면 등록이 안되었다. 어쩔수 없이 우리는 자체적으로 테스트 코인을 더 모아야 했다. 여기서 멈췄어야 했나...개발이 더 진행이되며, 발표에서 갤럭시를 쓰기 위해 팀원의 갤럭시 휴대폰에 더욱 맞췄는데 안드로이드 메타마스크 앱에서는 gps를 허용하지 않는 문제를 뒤늦게 발견했다... 결국 이 문제는 해결할 수 없었기 때문에 아이폰을 사용할 수밖에 없었다. 메타 마스크 앱에 대해 조금 더 잘 알았다면 위와 같은 문제가 발생하지 않는 방향으로 기획 및 개발을 진행했을 텐데 결론적으로는 아쉬움이 남았다.
  • 이미지 캐싱 미처리
    NFT 스티커 목록에서 스티커를 클릭하면 다이어리 페이지에 클릭한 스티커가 나타난다. 렌더링 이슈에 시간을 많이 쏟아부어 조금 더 최적화를 하고 싶었지만 결론적으로 매번 이미지 렌더링 시 네트워크 탭 확인 결과 새롭게 ipfs에 이미지를 요청하고 있었다. 해당 이미지는 이미 사용자가 보유한 이미지이기 때문에 이미지 캐싱을 한다면 새로운 요청이 발생하지 않을까 하는 아쉬움이 나는다.
  • 테스트 코드 미적용
    다이어리 페이지를 구현하기 위해 거의 800줄 이상의 코드를 작성했다. 그리고 백엔드 개발팀에서 프론트엔드 개발로 넘어와서 코드 작업을 도와주었다. 추후 프로젝트 기간이 끝났을 때 리팩터링을 해보려고 헀는데, 어디서부터 건드려야하며 코드를 바꾸려고 하면 에러가 나서 리팩토링을 마져 진행하지 못한 채 프로젝트를 끝내야만했다. 예전 코드 리뷰 스터디할 때 읽었던 리팩토링 책에서 테스트 코드에 대한 중요성을 알게되었고, 리팩토링할 때 엄청나게 큰 도움을 줬던 기억이 남는다. 다음 프로젝트에서는 사전에 테스트 코드를 작성해둔 다면, 리팩토링 시간을 단축하고 효율적으로 코드 작업이 가능할 것이라 생각된다.

📌  향후 계획

  • 테스트 코드 작성단순히 기능 구현에만 집중할 것이 아니라 코드 리팩토링을 통해 고도화 작업이 필요하다고 느꼈다. 그렇기 때문에 테스트 코드를 작성해서 TDD 기반의 작업을 수행하고, 리팩토링 과정에서 기존에 작성해둔 테스트 코드를 통해 더욱 빠르게 리팩터링이 가능할 것이라 생각된다. jest, storybook 등의 testing tool을 적극적으로 도입해서 코드의 완성도를 높이고 싶다.
  • 이미지 캐싱
    네트워크 과목을 공부했을 때 캐싱을 통해 서버의 호출을 줄일 수 있다는 것을 배웠었다. 그렇기 때문에 반복되는 이미지는 새로운 이미지가 필요한 것이 아니기 때문에 캐싱을 통해 이미지를 효율적으로 요청하는 방법을 배우면 좋을 것 같다.

📌  프로젝트 후기

서비스를 개발하는 단계에서 가장 많이 고민하는 부분이 user-flow이다. 사용자가 이 페이지를 들어왔을 때 각각의 버튼을 클릭할 때 어떤 기대를 하고 누르게 되고, 어떻게 화면을 보여줘야 할지부터, 해당 기능을 수행하고 여기를 누르면? 다르게 행동하면? 등등 꼬리의 꼬리를 물기 때문에, 단순한 기능을 구현하다고 많은 시간을 들이게 되는 것 같다. 이번 서비스에서 매인 기능인 다이어리 기능을 맡으며, 기존에 기능 정의서에서 생각하지 못했던 다양한 문제점을 발견하게 되었다. 사용자가 스티커를 여기다가 배치한다면? 사용자가 확인 버튼을 누르고 뒤로 가기를 누른다면? 등등 이런 클라이언트에게 지나친 자유도를 제공할 수도 없고, 제공했을 때 렌더링 시 어떤 이슈가 발생할지 모르기 때문에 최소한의 제약을 줄 수밖에 없었다. 혼자서 이런 고민들을 하느라 많은 시간이 들었는데, 다음 협업 시에는 이러한 이슈들을 먼저 생각해보고 다 같이 의논을 해보는 시간을 가지면 좋을 것 같다.

 

서비스에 대한 접근성이 아쉬웠다. 메타 마스크를 앱을 반드시 깔고 등록을 해야만 서비스를 사용할 수 있었기 때문에 접근성이 지나치게 떨어졌다. 서비스 구현을 위해 약 7주라는 시간을 태웠지만 정작 실제로 사용해보거나 체험하는 사람들이 없었기 때문에 너무 아쉽게 마무리하게 된 것 같다. 새로운 도전을 잘 수행해 내었지만, 사용하지 않는 소프트웨어는 죽은 것과 다름이 없기 때문에 다음 프로젝트는 최대한 쉽고, 많은 사람들이 편하게 이용하기 좋은 서비스를 구현해본다면 좋을 것 같다.

고생한 유꾸팀원들 고생해씀니당 ^^

 

 

 


여행조각 프로젝트 이슈 및 해결 관련 글

반응형