티스토리 뷰
🎬 프로젝트 개요
목표
- NFT Marketplace OpenSea Clone Coding
기간
- 2023.06.23 ~ 2023.06.30
역할
- 팀장
- 백엔드
요구 사항 및 달성 여부
요구 사항
달성 여부
대실패...!!
Github
💻 백엔드 상세 정보
🔧 기술 스택
1. node.js
- 원래는 go 언어를 사용하려 하였으나, web3 환경과 연동하여 사용할 수 있는 패키지를 사용해 본 경험이 없어서 확신이 서지 않음
- node.js는 그나마 익숙한 web3.js나 ethers.js를 사용할 수 있지만, javascript를 사용하여 백엔드를 구성해 본 경험 자체가 손에 꼽음
- 부트캠프에서 주로 javascript를 사용하는 만큼 다른 팀원들에게도 익숙한 방향으로 백엔드를 구성하는 것이 나을 것이라고 판단하여 선택
2. mongodb
- mongodb atlas로 무료 클러스터를 생성하여 쉽고 빠르게 시작할 수 있으므로 선택
- opensea api를 사용해 가져온 collection 정보와 nft 정보를 저장
📖 주요 라이브러리
1. express
- node.js에서 웹 서버를 구성하고 실행할 수 있게 도와주는 웹 프레임워크
- node.js 기본 라이브러리만으로는 웹 서버를 구성하기가 너무 어려우므로 프레임워크를 채용
2. winston
- 구조화된 로그를 출력할 수 있게 도와주는 라이브러리
- 굳이 구조화된 로그를 사용할 필요는 없었지만 개인적으로는 구조화된 로그가 더 직관적이므로 좋아하는 편
- 참고할 만한 글
3. mongoose
- node.js에서 mongodb를 연결하기 위해 사용한 라이브러리
- mongodb에서 제공하는 공식 라이브러리가 따로 존재하지만 일전에 node로 서버 실행하는 실습을 하면서 사용해 본 경험이 있어서 선택
4. jsonwebtoken, cookie-parser
- jsonwebtoken은 토큰 방식으로 로그인 로직을 구현하기 위해 사용한 라이브러리
- cookie-parser는 보다 쉽게 사용자 브라우저에 refresh token을 쿠키로 저장하기 위해 사용한 라이브러리
5. cors
- cors 옵션을 설정하기 위해 사용한 라이브러리
- 참고할 만한 글
6. dotenv
- '. env'파일에 설정값을 저장하고 node.js에서 불러오기 위해 사용한 라이브러리
7. nodemon
- 로컬에서 live reloading을 사용하여 변경 사항을 바로 적용해 보기 위해 사용한 라이브러리
💣 프로젝트를 완성하지 못한 이유에 대한 고찰
1. 첫 단추를 잘못 끼우다
- 처음 opensea를 클론 코딩하라고 들었을 때 opensea라는 거대한 서비스의 구조와 로직을 있는 그대로 이해해 보기 위해 고민을 했습니다.
- 그러나 제대로 된 프로젝트 경험도 없는 풋내기가 그러한 것을 단기간에 이해하는 것은 당연히 불가능. 도대체 어디서부터 시작해야 할지 감도 잡히지 않아서 있는 대로 다 덜어내고 만들 수 있어 보이는 부분들만 손을 대기 시작했습니다. 팀원들은 저와 마찬가지로 거의 처음 프로젝트를 경험하다 보니 선두를 따라 뒤따라가는 기러기처럼 팀장이 하자는 대로 따랐을 것입니다.
- opensea라는 서비스 그 자체에 초점을 맞춰 어려워 보이는 것들을 덜어내기보다는 opensea와 유사한, 새로운 무언가에서 시작하여 살을 붙여 나가는 것이 더 나은 결과를 끌어낼 수 있지 않았을까? 다른 관점에서 문제를 바라보는 시각을 길러야 함을 간절하게 느꼈습니다.
2. 속전속결이 필요한 전장에서 토성을 쌓다
- 주어진 시간은 단 일주일. 빠르게 UI를 구현하고 로직을 추가해야 하는 긴박한 기간이었습니다. 이 또한 팀장인 제가 인지하고 팀원들에게 강조했어야 했는데 그러지 않았습니다.
- 특히 프로젝트 구상 단계에서 빠른 UI 구현을 위해 bootstrap이나 mui 같은 프레임워크를 사용하자고 강하게 나갔어야 했는데 팀원들의 의견을 존중한다는 명목하에 styled-component라는 조금은 어려운 길을 선택했습니다.
- 전장에서 지휘관의 잘못된 판단은 무고한 병사들을 사지로 내몰 수 있습니다. 비록 팀원 개인의 역량적인 성장은 이루었을지 몰라도 팀장인 저의 오판으로 인해 그들의 포트폴리오의 한 자리를 공백으로 만들어 버리지 않았나 하는 죄책감도 듭니다. 리더의 선택이, 리더라는 자리의 무게가 얼마나 무거운지 다시 한번 느끼게 되었습니다.
📈 해결한 문제들
1. xmlhttprequest.handleerror
# 원인
- react 앱 딴에서 axios를 사용하여 백엔드로 요청을 보낼 때 발생하는 cors 오류
# 해결
1. frontend
- package.json 파일에 proxy 값으로 node 서버의 주소를 추가
2. backend
- cors 옵션의 origin 값으로 react 앱의 주소를 추가
참고 자료
- https://zinirun.github.io/2020/11/03/react-cors-proxy/
- https://velog.io/@kimhr08/CORS-%EC%97%90%EB%9F%AC%EC%99%80-%EB%A7%88%EC%A3%BC%ED%95%98%EB%8B%A4
2. destroy is not a function
# 원인
useEffect(async () => {
await simpleExample();
}, []);
- useEffect 훅의 첫 번째 인자로 들어가는 함수는 clean up 함수를 제외하고는 어떠한 값도 반환해서는 안됨
- 그런데 async 함수는 Promise를 반환하므로 useEffect의 첫 번째 인자로 async 함수를 전달할 경우 useEffect 훅과 충돌이 발생
# 해결
useEffect(() => {
simpleExample().
then().
catch((err) => {});
}, []);
- async, await 대신 then, catch 블록을 사용
참고 자료
- https://chandlerbong.tistory.com/178
- https://medium.com/geekculture/react-uncaught-typeerror-destroy-is-not-a-function-192738a6e79b
3. TokenExpiredError: jwt expired
# 원인
- 만료된 jwt access token을 요청 헤더에 담아 보내면 검증 과정에서 오류가 발생하여 node 서버가 중지됨
- 정상적으로 동작한다면 401 코드와 함께 토큰이 만료되었다는 오류 메시지가 응답으로 전달되어야 함
- 정확한 원인을 규명하기 어려워 일일이 코드를 살펴봄
# 해결
- async 함수 내부에서 토큰 검증을 비동기로 실행하지 않아 충돌이 발생한 것이므로 await 키워드를 추가
4. git 브랜치 충돌
# 원인
- 팀원들 각자 자신의 이름으로 된 브랜치에서 작업을 하고 dev 브랜치로 병합하는 과정에서 충돌 방생
# 적용해 본 방법들
- 충돌이 발생한 부분 일일이 확인 및 수정
- 충돌이 발생한 브랜치를 버리고 새로운 브랜치를 생성하여 변경 사항 적용
- 충돌이 발생한 브랜치의 로그를 살펴보고 충돌이 발생하기 전으로 강제 리셋, 변경 사항 적용하여 강제 푸시
📉 해결하지 못한 문제
1. React 빌드 파일 실행 시 아무것도 출력되지 않는 문제
$ npm run build
$ serve -s build
2. form-data로 받은 이미지를 readable stream으로 변형하기
https://docs.pinata.cloud/pinata-api/pinning/pin-file-or-directory
- pinata api를 사용해서 요청으로 받은 form-data에 들어있는 이미지를 IPFS에 업로드하려고 했는데 readable stream만 받는다고 함
- form-data로 받은 이미지를 readable stream으로 변형하는 방법을 찾지 못했다.
🎓 프로젝트를 통해 배운 것들 & 느낀 점
1. 협업 흐름에 대한 이해
- 이번에 처음으로 git과 github를 사용하여 단일 리포지토리에서 여러 명이 협업하는 과정을 경험했습니다. 이렇게 사용하는 게 맞나 싶은 의문도 계속 들고 브랜치 병합 과정에서 충돌 때문에 우왕좌왕하기도 했지만, 팀원들과 충분히 소통하고 함께 고민하면서 문제를 해결할 수 있었습니다. '타인들과 의사소통 역량을 기르고 협업 프로세스를 이해하는 것'이 부트캠프에 지원한 주된 이유인 만큼 이번 프로젝트를 통해 소정의 목적을 달성했다고 생각합니다. 또한 남은 두 개의 프로젝트를 모두 경험하고 나면 더 세련된 방식으로 git과 github를 활용할 수 있지 않을까 하는 기대를 하게 됩니다.
2. 나는 천하를 저버리지 않겠다
- 나름대로 자신의 역량에 대한 자기 객관화가 잘 되어 있다고 생각해서 주변의 기대나 올려치기가 부담스러울 때가 많습니다. 이번 프로젝트를 진행하는 중에도 '정말 내가 하자는 대로 해도 괜찮은 걸까?' 하는 의문을 수도 없이 가졌습니다. 그런데 한편으로는 그분들 나름의 평가 기준에 제가 부합하여 좋은 평을 받을 수 있었다는 것에 감사할 따름입니다. 이번 프로젝트에서 팀장으로서 역량의 부족함을 많이 느낀 참에 다음 프로젝트의 팀 구성 단계에서 새로운 팀원들의 추천으로 다시 팀장을 맡게 되었습니다. 새로운 프로젝트에서는 팀원들의 지지를 기꺼이 받아들이면서 자기 자신을 의심하지 않고 부족함을 느낀 부분들을 확신으로 채울 수 있도록 부단히 노력할 것입니다.
3. Not my tempo
- 제 경험상 좋아하는 것을 할 때와 비교해서 하기 싫은 것을 할 때는 작업 효율이 반의반에 반의반도 안 나옵니다. 이번에 Javascript로 백엔드를 구성하면서 뼈저리게 느꼈습니다. 나는 정말 Javascript를 싫어하는구나. 싫어하는 이유에 대해서는 기회가 된다면 구구절절 적어보려고 합니다마는 한 가지만 들어보자면 어차피 타입 신경 써줘야 하는데 동적으로 타입을 할당해 버려서 코드 에디터에서 자동 완성도 어렵고 컴파일 에러로 바로바로 에러를 보여주지 않고 런타임에 가서야 에러 났으니까 잡아봐라 하는, 고담시의 범죄자들보다 악질인 빌런 중의 빌런이 Javascript라는 것이죠. 그래서 프로젝트 두 개나 남았는데 Javascript는 안 쓸 거야? 네! 가능하면 Golang으로 백엔드 포지션 고정해 놓고 큐 돌릴 생각입니다. 제 템포대로 가겠습니다.
🎬 마치며
- 만약 CODESTATES BEB 다음 기수분들이 이 글을 보게 된다면...
- 프로젝트에 돌입하게 되면 가능한 한 빠르게 적재적소에 배치할 수 있도록 함께하는 동기분들의 역량을 충분히 파악하시길 바랍니다. 그리고 프로젝트를 출제한 엔지니어분들의 의도를 고민해 보시길 바랍니다. 저는 지난 금요일에 프로젝트 발표가 끝나고 엔지니어분의 피드백을 듣고 탈주 닌자가 될 결심을 잠깐 했습니다. 마음의 준비도 조금은 필요할 것 같네요.
- 어찌 되었든 첫 번째 프로젝트가 이렇게 마무리되었습니다. 첫 번째 프로젝트 회고는 감상 위주로 작성해 보았는데 이렇게 글로 마음에 담아 놓은 것들을 털어놓으니 조금은 편해지는 기분입니다. 긴 글 읽어주셔서 감사합니다!
'교육 과정 > 코드스테이츠' 카테고리의 다른 글
CODESTATES 블록체인 부트캠프 9기 수료 후기 (0) | 2023.08.21 |
---|---|
CODESTATES BEB 9기 두번째 프로젝트 회고 (0) | 2023.07.14 |