[Project] DDYY market 개발 회고

yooni·2022년 4월 18일
0
post-thumbnail

처음으로 진행해본 프로젝트였다! 화려한 기능을 가진 화려한 사이트를 구현한 것은 아니었지만, 처음으로 협업하며 개발을 해보았다는 점에서 나에겐 큰 의미가 있는 프로젝트였다.




✏️ 역할 분담

  • Front-end (내가 담당한 🙋🏻‍♀️)
    클라이언트 웹페이지 및 web3 일부 로직 구현
  • Back-end
    모랄리스 사용을 위한 api 개발 및 web3 로직 구현
  • Smart Contract
    ERC-721 발행 및 조회, 전송을 위한 컨트랙트 개발 및 배포




1. DDYY NFT market

DDYY NFT market 링크
github 레포지토리 링크

우리 팀은 필수적으로 필요한 최소 기능만을 빠르게 구현한 뒤, 배포까지의 전 과정을 경험해 보는 것을 목표로 하였다. 우리 사이트는 검색어를 통해 rinkeby 테스트넷 상에 발행된 NFT를 조회할 수 있고, 메타마스크 지갑을 연결하여 직접 NFT를 발행 하고 특정 주소로 전송할 수도 있다.



📦 truffle-react-box 라이브러리

이 라이브러리를 사용하면리액트 클라이언트 개발, 스마트 컨트랙트 개발 및 배포, web3 연동까지 통합된 하나의 프로젝트 안에서 개발할 수 있어 매우 편리하다! 간단한 토이 프로젝트 개발에는 무조건 사용하는 것이 좋을 것 같다. (truffle-react-box tutoral page)

truffle-react-box 깃헙 페이지에서는 아래와 같이 소개하고 있다.



Pages 상세

📃 explore

'dog' 라는 키워드로 검색하면, Token 이름에 'dog'가 포함되는 NFT들이 리스팅된다.


📃 create - NFT minting

NFT name, description을 입력하고 원하는 파일을 선택하면 민팅을 할 수 있다. 메타마스크를 통해 지갑에 서명까지 하면 NFT가 성공적으로 발행되었다는 메시지와 함께 해당 발행 트랜잭션에 대한 정보를 확인할 수 있는 이더스캔 링크를 제공한다.


📃 mypage - NFT transfer

현재 로그인된 지갑 계정이 소유하고 있는 NFT들을 확인할 수 있다. 각 NFT 하단에 수신인의 지갑 주소를 입력하고 transfer 버튼을 누르면 NFT를 전송할 수 있다. 이 때도 역시 메타마스크를 통한 서명이 필요하다. NFT가 성공적으로 전송되면 해당 트랜잭션에 대한 이더스캔 링크가 제공된다.




2. Frontend 개발 회고

리액트로 개발되었으며, 매우 간단한 사이트이기 때문에 truffle-react-box 외에 특별한 라이브러리나 기술스택은 사용하지 않았다.


🖥 client 코드 구조



🖥 통신 결과에 따른 메시지 출력

블록체인과 통신하는 것은 비동기이며, 일반적인 클라이언트와 서버의 통신보다 훨씬 오래 걸린다. 사용자 경험을 위해 loading indicator의 구현은 필수적이었다.

또한 message라는 state를 정의하고, 통신 결과에 따라 달라지는 message state에 따라서 적절한 결과 메시지가 노출되도록 하였다. 이러한 내용이 구현됨으로써 사용자 경험이 크게 개선될 수 있었다. 매우 간단하고 또 당연한 로직이지만 앞으로 또 다른 클라이언트를 개발할 때에도 세심하게 신경써야할 부분이라고 생각한다.


통신 결과 메시지 출력 example - NFT minting

NFT를 민팅하는 컴포넌트에서 해당 내용을 구현한 전체적인 흐름은 다음과 같다.

const MintForm = () => {

	// message state 정의
  const [message, setMessage] = useState('');

	// NFT 발행을 위한 정보를 메타데이터 생성 서버에 제출하는 함수
  const handleSubmit = async (event) => {

		// 입력된 정보가 올바르지 않으면 📌message = 'formError'
    if (nameRef === '' || descRef === '' || imgFile === undefined) {
      setMessage('formError');
      return;
    }

		// 서버에 정보를 제출하고 응답을 기다리는 동안 📌message = 'loading'
    setMessage('loading');

		...
  }

	// 생성된 메타데이터로 NFT를 민팅하는 함수
  const mintNFT = async (metaData) => {

		...

    try {
	        ...
        setTxAddress(txHash);
				// 거래가 성공하면 📌message = 'success'
        setMessage('success');
    } catch (error) {
      ...
			// 거래가 실패하면 📌message = 'failure'
      setMessage('failure');
    }
  }

  return (
			...
			// message의 상태에 따라, 아래 div에 표시되는 내용이 달라진다.
      <div className="mintfomr-alert-message-wrapper">
        {
          message === 'formError' &&
          <div className="mintform-filling-error-message">
            All fields must be filled in.
          </div>
        }
        {
          message === 'success' &&
          <div className="mintform-success-message">
            NFT has been successfully issued!<br />
            Check your Transaction&nbsp;
            <a target="_blank" href={'https://rinkeby.etherscan.io/tx/' + txAddress}>HERE!</a>
          </div>
        }
        {
          message === 'failure' &&
          <div className="mintform-failure-message">
            Something wrong! Try again
          </div>
        }
        {
          message === 'loading' &&
          <div className="mintform-loading-message">
            Please wait...&nbsp;
            <img className="loading-indicator2" alt="now loading..." src="loading2.gif" />
          </div>
        }
      </div>
    ...
  )
}



🖥 useRef

이번 프로젝트 이전까지는 거의 사용해보지 않았던 hook인데, 사용법이 너무 간단해서 이걸 왜 이제야 활용하게 되었나 싶다. 리액트를 한참 배울 때에는 useRef를 사용하지 않고, 각 input에 해당하는 state를 새로 생성하여 input 태그의 event.target.value를 새로운 state의 값으로 setState 하는 방법을 이용했었는데, useRef를 이용하는 것이 비교도 안 될 정도로 간단하다.

컴포넌트 안에서 아래처럼 정의하면 input에 입력되는 값을 nameRef로 손쉽게 접근할 수 있다.

const nameRef = useRef();

return (
	<input ref={nameRef} type="text" />
)



🖥 CSS

postCSSstyled-components를 이용할 수도 있었지만, 간단한 프로젝트이기 때문에 app.css에 모든 css를 몰아 넣었다. 정리되지 않은 무식한 방법일 수 있지만 주석만 잘 달아놓으면 단 하나의 css 파일만 이용하기 때문에 이 방법도 나름 괜찮기는 했다. 하지만 개선이 필요하다.




3. 기타 이슈 사항

Moralis

Opensea는 api 키 발급에 오랜 시간이 걸린다. 우리팀은 오픈씨와 비슷한 Moralis라는 플랫폼의 api를 이용하여 rinkeby 테스트넷에 접근하기로 했다.



Metamask Signature 기능 구현

NFT를 민팅하거나 전송할 때, 사용자가 메타마스크를 통해 서명할 수 있도록 구현해야 했다. 이를 구현하는 과정에서 어려움이 있었고, 구글링을 통해 솔루션을 찾아 아래와 같이 적용하여 해결하였다.

우리 컨트랙트에 eth_sendTransaction이라는 methodrequest를 날리는 방식이다. MetaMask Docs에서 이 내용이 안내되고 있는 걸 보니 아마 메타마스크에서 제공하는 기능인 것 같다. 이곳에서 관련 내용을 참고할 수 있다.

docs 내용을 참고하여 우리 사이트에서는 아래와 같이 구현하였다.

const mintNFT = async (metaData) => {

    window.contract = await new web3.eth.Contract(ABI, deploy_address);

    const transactionParameters = {
      to: deploy_address, // Required except during contract publications.
      from: window.ethereum.selectedAddress, // must match user's active address.
      'data': window.contract.methods.mintNFT(window.ethereum.selectedAddress, metaData).encodeABI() //make call to NFT smart contract 
    };

    //sign transaction via Metamask
    try {
        const txHash = await window.ethereum
            .request({
                method: 'eth_sendTransaction',
                params: [transactionParameters],
            })
        setTxAddress(txHash);
        setMessage('success');
    } catch (error) {
      console.log(error);
      setMessage('failure');
    }
  }




4. 이번 협업을 통해 배운 점


  • git을 사용한 협업
    git과 github에 대해서는 막연하게 알고 있었는데, 이번 프로젝트를 통해 git의 막강함을 느낄 수 있었다. git이 없을 때 개발자들은 어떻게 협업을 했을까...? 단, 충돌이 나지 않도록 팀원들과 잘 소통해가며 개발하는 것이 매우 중요한 것 같다. git 개념과 명령어가 아직 친숙하지 않아 별도로 더 공부해볼 예정이다.

  • 로딩 인디케이터 이미지 무료 제작 사이트
    서버와 비동기적으로 통신해야하는 사이트들은 로딩 인디케이터 구현이 필수적이다. 이 사이트에서 간단하게 원하는 대로 인디케이터 이미지를 손쉽게 제작할 수 있다.




5. 보완해야 할 사항들

NFT searcing, minting, tranfering 기능만을 간단하게 구현해본 사이트이기 때문에 실제로 서비스하기에는 부족한 부분이 많다. 다음 프로젝트에서는 더욱 완성도 높은 서비스를 개발하기 위해 이 내용들을 잘 기억해둬야겠다.


  • 로직 분리가 세분화되지 않아서 컴포넌트/페이지가 무겁고 똑똑함
    하나의 컴포넌트 코드가 100줄을 넘지 않게 작성하고 싶은데, Minform 컴포넌트의 경우 150줄이 넘어가고 있다. 서비스 로직은 따로 모듈화하여 구현하는 연습을 해야 하는데 아직은 한 파일에 몰아서 작성하는 것이 편하다..😭

  • 리덕스 등의 상태 관리 라이브러리 사용 안함
    하지만 가벼운 앱은 useState Hook으로도 충분할 듯 하다. 다음 프로젝트에서는 reduxuseReducer를 활용해볼 예정이다.

  • css 코드 작성이 비효율적
    App.css 파일에 모든 CSS 코드를 다 담았는데, 사이트의 규모가 좀 더 크거나 유지보수가 필요한 상황에서는 아마 크게 고생할 것이다. syled-Component나 postCSS를 적용해 보는 것도 좋았을 것 같다.

  • memo, useCallback 등을 통한 성능 최적화를 하지 않음
    성능 최적화를 아예 하지 않았다. 불필요한 리렌더링을 줄이는 최적화가 필요하다.

  • 브라우저 콘솔에 뜨는 수많은 warning들을 손보지 않음
    warning들은 사실 고쳐볼 엄두가 나지 않았다..

  • NFT 이미지가 잘 로딩되지 않음
    NFT를 검색하거나, mypage를 조회할 때 아래와 같이 이미지가 잘 로딩되지 않는 경우가 많았다. 새로고침을 반복하면 이미지가 뜨기도 한다. 아마 Moralis에서 제공하는 API가 불안정한 것이 아닐까? (뇌피셜)

  • 검색시 리스팅이 48개까지 밖에 되지 않음
    키워드를 입력하여 검색을 실행하면 검색 결과로 최대 48개의 NFT만 로딩된다. 무한 스크롤 기능을 통한 개선이 필요하다.



profile
멋쟁이 코린이

0개의 댓글