제로하우스
Project 1: OpenSea 클론 코딩 회고 본문
Intro
블록체인 부트캠프에서 첫 프로젝트로 OpenSea 클론 코딩
을 진행하였다. OpenSea와 같이 간단한 NFT 마켓플레이스를 만드는 것이었는데, 생각했던 것 같이 똑같이 클론 코딩을 하는 것은 아니었다. 제공되는 Contract 코드를 재가공하여 사용하는 것 외에는, 프로젝트 구조 설계, 클라이언트 개발, IPFS 연결 등 모든 것을 직접 해야했다.
확실히 개념을 학습하고 실습을 하는 것보다, 직접 프로젝트를 해보니 전체적인 구조 파악이나, 문제 해결 등에서 블록체인에 대해서 더욱 잘 알 수 있는 기회가 되었다.
1. 기획 과정
1.1 문서
프로젝트가 기간이 길지 않았기 때문에(weekday 기준 약 6주일) 기획은 반나절 정도에 다 마쳤다. 노션을 활용하여 빠르게 개발을 하기 위한 최소한의 문서를 정리하였다.
처음에는 DB를 구축하기 위해서, Express.js로 서버를 구축하고 ERD도 간단하게 작성하였다. 하지만, 프로젝트를 진행하며 DB가 없이도 크게 문제가 되지 않으며, 데이터 로딩 속도도 redux 등의 상태 관리 라이브러리로 개선할 수 있다고 판단하였기 때문에, 중간에 Server와 DB를 구축하지 않기로 하고 resource를 다른 중요한 부분에 더 투입하기로 했다.
1.2 요구사항 & 기능명세서
이전에 여러 프로젝트를 해보면서, 또 회사에서 일을 해보면서 제대로 정리된 기획서가 없으면 커뮤니케이션 비용도 많이 발생하고, 개발자들도 혼동에 빠지는 경우가 많기 떄문에 간단하게라도 다함께 요구사항을 정리하고 기획문서를 작성했다.
요구 사항을 먼저 정리하고, 이를 바탕으로 기능을 정리하며 Page, Component를 구분하였으며, 그리고 그 기능을 바탕으로 React 폴더 구조를 잡았다.
1.3 Mockup
팀원 분 중에 디자인 업무를 수년간 하셨던 분이 계셨는데, 빠르게 개발하기 위해서 mockup이 있으면 좋을 것 같다는 의견을 제안해주시며, 본인이 바로 1시간 만에 figma로 mockup를 제작해주셨다. 이전에 간단한 toy project를 하며 그리던 wireframe이나 mockup과는 달랐다. 실제로 개발 프로젝트를 하면서 제대로된 mockup을 활용하는 건 처음이었는데, figma에 작성해둔 color hex 값이나, border radius 값을 바로 가져와 사용할 수 있다는 것이 너무 편리했다. 그러니깐 개발자는 개발만 할 수 있어서 좋았다.
1.4 Naming Convention
프로젝트를 시작하여 각자 기능별로 작업을 진행하다 보면, 다양한 작명(作名)을 하게 된다. 예전에 프로젝트를 하면서 일부 팀원들이 너무나 창의적인 변수명이나 파일명을 작성해 코드 리뷰를 할 때 알아보기가 어려웠던 적이 있다. 그래서 본격적으로 프로젝트를 시작하기 전에, 간단하게 변수, 함수, 그리고 git branch에 대한 naming rule을 정하였다. 그리고 최대한 직관적으로 naming을 할 수 있도록 이야기를 나누었고, 그 덕분인지 이번 프로젝트에서는 naming 때문에 코드 리뷰가 어렵거나 했던 부분은 없었다.
2. 개발 과정
2.1 주요 기능
서비스의 주요한 기능은 다음과 같다.
- Minting: 자신의 이미지 파일을 NFT로 제작
- Collection: 자신이 소유하고 있는 NFT 컬렉션 확인
- Marketplace: 플랫폼에서 다른 사용자의 NFT를 확인하고 거래
2.2 업무 분배
우리 팀은 총 4명으로 구성되었다. 처음에는 front-end, back-end, contract 등 파트 별로 업무를 나눌까도 생각했지만, 처음 프로젝트인만큼 기간이 짧더라도 각자가 기능 단위로 수직적 개발을 경험해보면서 front-end 및 blockchain에 대해 폭넓게 공부해볼 수 있다는 의견이 많아서 기능 단위로 업무를 분배하게 되었다.
확실히 파트 별로 업무를 나눈 것보다는 비효율적이기는 했던 것 같다. 하지만, 학습 효과는 좋았던 것 같다. 내가 맡은 기능은 다음과 같았다.
- Navbar: 지갑을 연결하고, 다른 페이지로 이동할 수 있도록 도와주는 컴포넌트
- Profile: 사용자의 정보와 소유하고 있는 NFT 컬렉션을 확인할 수 있는 기능 페이지
하지만 하루, 이틀만에 개발이 끝나 추가적으로 NFT를 민팅하는 Create
기능도 개발하였다.
- Create: 이미지를 NFT로 민팅할 수 있는 기능 페이지
Create 기능을 개발하면서, IPFS에 메타데이터를 저장하는 로직을 개발하였다. 이와 함께 부수적으로는 Contract를 Remix IDE를 통해 배포하고, abi 코드로 react로 가져왔으며, 또한 마지막 날에 GitHub Pages를 활용해 개발한 서비스를 배포하기도 하는 등을 하기도 했다. 팀원들 모두 본인에게 배정된 업무가 아니더라도, 할 일들을 찾아서 적극적으로 제안하고 수행해오고 했던 점이 이번 프로젝트에서는 너무 좋았던 것 같다.
2.3 폴더 구조
React 프로젝트의 폴더 구조는 다음 그림과 같다.
- 페이지 단위의 기능은
pages
폴더에 위치한다. - 컴포넌트 단위의 기능은
components
폴더에 위치한다. pages/index.js
에서는 router를 정의하고 있다.redux
폴더에서는 redux state를 관리한다.abi
폴더에서는 배포한 contract abi 코드를 관리하며,global_variables.js
파일에서 이를 받아서 처리해준다.- css는 관심사 분리의 법칙을 적용하여, react 파일 내부에서는 작성하지 않았으며, 모두
scss/style.scss
파일에서 작성하여 관리한다. - 이외에도
.env
등의 파일로 환경변수를 관리하며, 중요한 API KEY 등은 .gitignore하여 git repository에서도 노출되지 않도록 했다.
2.4 스크럼
우리 팀은 매일 10시와 17시에 30분 - 1시간 정도 스크럼을 진행했다. 팀원들마다 작업하는 시간이 일과시간 혹은 새벽 등으로 달라서 스크럼 시간을 적절히 조정하여 개발에는 몰두할 수 있도록 하는 한편, 중간중간 공유를 통해 서로 간의 이해를 돕고자 했다. 스크럼 시간에는 각자가 작업한 내용, 현재 직면한 문제 상황 등을 공유하며 협업을 강화하였다.
3. 서비스
개발된 서비스는 LeeSea 페이지에 접속하면 확인할 수 있다.
개발한 서비스 페이지는 다음과 같다.
1. Home:메인 페이지
2. Explore: 다른 사용자들이 발행한 NFT 작품을 확인할 수 있다.
3. Detail: NFT 작품을 클릭하면, 해당 작품의 상세 정보를 확인할 수 있으며, 작품을 거래할 수 있다.
4. Create: 이미지를 NFT로 제작할 수 있다. NFT는 web3.js를 통해 이더리움 블록체인(ropsten 네트워크) 상에 배포되고, 메타데이터는 NFT Storage를 통해 IPFS에 저장된다.
5. Profile: 자신의 계정 정보와 소유한 NFT 작품을 확인할 수 있다.
4. 기술적 메모
4.1 기술 스택
기술 스택은 다음과 같다.
프론트엔드: React, node.js, SCSS
블록체인: Etehreum(Rinkeby Testnet), Ganache
기타: web3.js, NFT Storage, MetaMask
4.2 작동 구조
개략적인 작동 구조는 다음과 같다.
- Remix IDE를 통해 Ethereum 컨트랙트를 배포한다.
- web3.js를 통해 React 프로젝트에서 Ethereum 블록체인과 통신한다.
- NFT Storage를 통해 IPFS에 NFT의 metadata를 저장 및 통신한다.
- Chorme MetaMask 플러그인을 통해 지갑에 연결한다.
- redux를 활용해 데이터 상태를 관리한다.
4.3 작성 코드
작성 코드는 github repository에서 확인할 수 있다.
4.4 redux 사용
새로고침해도 지갑 연결이 끊어지지 않도록 하는 방법 (redux-persist를 사용한다.)
처음에는 setState
로 데이터를 관리하고 있었는데, 지갑을 연결한 후 새로고침을 하면 지갑 연결이 끊어지는 현상이 발생했다. 이를 해결하기 위해 redux와 redux-persist를 사용하였다.
react의 상태 관리 라이브러리 redux에 redux-persist를 연결하여, 새로고침을 해도 state가 유지될 수 있도록 한다.
1. redux-persist를 설치한다.
npm install redux-persist
2. index.js를 수정한다.
...
import persistedReducer from './_reducers'; // 추가
import { persistStore } from 'redux-persist'; // 추가
import { PersistGate } from 'redux-persist/integration/react'; // 추가
import store from './redux/store'; // redux
const persistor = persistStore(store) // 추가
root.render(
<Provider store={store}>
<PersistGate persistor={persistor}> // 추가
<BrowserRouter>
<App />
</BrowserRouter>
</PersistGate>
</Provider>,
);
3. redux 폴더에 정의된 store.js를 수정한다.
// redux/store.js
...
import persistedReducer from '.'; // redux-persist
...
const store = createStore(persistedReducer, composeEnhancers(applyMiddleware(thunk))); // rootReducer를 persistedReducer로 변경
...
4. redux 폴더에서 rootReducer가 정의된 index.js를 수정한다.
// redux/index.js
...
import { persistReducer } from 'redux-persist'; // redux-persist
import storage from 'redux-persist/lib/storage'; // redux-persist
const persistConfig = {
key: 'root',
storage,
} // redux-persist
const rootReducer = combineReducers({
accountReducer
});
const persistedReducer = persistReducer(persistConfig, rootReducer); // redux-persist
export default persistedReducer; // redux-persist
여기서, 저장하고 싶은 위치에 따라 다르게 import 해주어야 한다.
import storage from 'redux-persist/lib/storage' // localstorage에 저장하고 싶은 경우
import storageSession from 'redux-persist/lib/storage/session // sessionstorage에 저장하고 싶은 경우
4.5 IPFS 연결
IPFS 연결하는데 제법 시간이 오래걸렸다. 원래는 infura
를 통해서 연결하고 있었는데, 프로젝트 진행 기간 중 해당 서비스가 갑자기 중단되게 되었다. 대안으로 처음에는 Alchemy를 검토했으나, 개발하고 보니 Alchemy와 연결된 IPFS인 Filebase는 javascript에서 api 요청을 통해 이미지를 저장하는 방법이 없었다. 그렇게 infura, alchemy로 개발한 코드를 전부 엎고 NFT Storage를 이용해 최종적으로 IPFS와의 연결 코드를 구현하였다.
NFT Storage는 우리가 사용하던 webpack 버전에서 모듈 에러가 발생했는데, webpack 버전 업그레이드를 진행하는 것도 고려했지만, 현재 코드에 영향도가 너무 큰 것으로 파악되어 webpack 업그레이드를 진행하지는 않았다. 그 대신 최소한의 기능을 사용하는 방식을 채택하여 결국에는 모듈 에러를 해결하고 NFT Storage를 통해 IPFS 연결에 성공하였다.
import { NFTStorage } from "nft.storage/dist/bundle.esm.min.js";
5. 회고
이번 프로젝트를 통해서 블록체인, 그리고 그와 관계된 서비스 개발에 대해서 폭넓게 이해하고 학습할 수 있는 시간이었다. 특히, 이전 개발 프로젝트 때보다 배경지식이 넓어져 오류를 해결하는데 걸리는 시간이 획기적으로 많이 줄어든 것을 발견하며 스스로 뿌듯했던 부분도 있었다. 짧은 기간 안에 하나의 서비스를 개발하느라 시간에 쫓기며 정신 없이 개발을 했던 것 같지만, 너무너무 재밌어서 아쉬움이 없는 것 같다.
다만 팀장으로서 조금 아쉬움이 남는 부분이 있다.
- 프로젝트 혹은 코드를 제대로 이해하지 못한 팀원이 적절한 업무를 할 수 있도록 하지 못 했다.
처음 시작할 때부터 팀원 중 일부가 프로젝트 전반에 대해서나, 각 파트 간의 interaction, contract와의 통신 등에 대해서 제대로 이해하지 못한 부분이 있었는데, 그것을 제대로 해결해주지 못 했다. 짧은 기간 때문에 시간 상 어쩔 수 없는 부분이 있었다고 합리화 하더라도 아쉬운 부분은 어쩔 수 없다.
이에 대해서 내가 생각한 대응 방안은 다음과 같다.
- 처음에 프로젝트나 기술 스택 전반에 대해서 함께 더 이야기해보며 이해를 맞추기
- 할 일에 대해서 기능 단위가 아닌 더욱 더 구체적인 요구사항을 정리해서 전달해주기
- 스크럼 시 코드 리뷰를 하는 시간을 더 할애하기
- 질문이 왔을 때 적절히 ZPD를 건들이기
다음 프로젝트에는 생각한 대응 방안을 적극적으로 적용해보며 문제를 해결해봐야겠다.
6. 링크
- Github Repository: https://github.com/codestates/BEB-05-LeeSea
- 서비스 페이지: https://codestates.github.io/BEB-05-LeeSea
'기타 > 코드스테이츠 블록체인 부트캠프' 카테고리의 다른 글
Project 2: Incentive Community 클론 코딩 회고 (0) | 2022.08.29 |
---|---|
[JavaScript] Underbar 라이브러리 구현하기 (0) | 2022.05.19 |
[블록체인 부트캠프][회고록] Day16 (0) | 2022.05.19 |
[비동기 예제] fetch API를 이용한 네트워크 요청 (0) | 2022.05.19 |
[비동기 예제] fs 모듈을 활용한 파일 읽기 (0) | 2022.05.19 |