기업 협업 프로젝트 회고

Bik_Kyun·2022년 5월 26일
0
post-thumbnail

시작하기에 앞서,
"어느 기업에 갔는지"와 "어떤 사이트를 프로젝트로 진행했는지"는 밝히지 않겠습니다.
코드 또한 일부분만 공개가 가능합니다.
아무래도 좀 민감한 부분이니까요.

1. 협업 프로젝트 진행

인원

  • FE - 1명
  • BE - 2명

사용 기술

  • Node.js
  • Express.js
  • MongoDB
  • Mongoose

목표

NFT 거래 사이트입니다.
저희가 파견되었을 때 배포가 진행중이었고 서비스 출시는 하지 않은 상태였습니다.
웹 사이트 기능 작동을 위해 빠르게 구현된 상태였고 Testing, Error Handling 모두 구현되어 있지 않은 상태였습니다.

BE의 목표는 구현된 API를 이해하고 Layered Pattern으로 분리 및 모듈화였습니다.
프로젝트는 한 달간 진행되었습니다.

결과

BE팀은 총 6개의 API를 리팩토링하였고 저는 3개의 API를 리팩토링하였습니다.

News - 최신소식, 뉴스를 보여주는 API
Search - NFT 및 제작자를 검색하는 API
Wishlist - NFT의 장바구니 API

Controller에 모두 구현된 API를
DB에 접근하는 부분인 Action,
Error Handling 부분인 Exception,
response만 보내는 부분인 Controller
그리고 유효성 검사를 위한 Validator
이렇게 4부분으로 분리하였습니다.

시간이 부족하여 JUnit을 활용한 Testing은 실시하지 못하였고 Postman을 활용하여 Integration Testing을 실시하였습니다.

느낀점

  1. Django를 통해 서버 구축, API 구현하는 법을 배웠고 Javascript에 대한 학습이 부족하여 내가 생각한 것을 구현하는 데에 시간이 너무 오래 걸렸다.
    Python이든 Javascript든 언어에 대한 이해의 중요성을 뼈저리게 느낀 프로젝트였다.
  2. 비동기/동기에 대해서도 Django를 사용할 때는 생각할 기회가 없었는데 이 개념을 처음 사용하려 하니 이해하는 데에 시간이 오래 걸렸다.
  3. 타인이 구현한 코드를 볼 기회가 그리 많지 않은데 전체적인 서비스를 구현해 놓은 코드를 보고 "앞으로 내가 어떻게 뒷단을 구현해야 할 까"에 대한 Tip을 얻을 수 있었다.
  4. 리팩토링은 끝이 없다. 관련 도서를 꼭 읽자.
  5. 앞으로 회사에 지원할 때 사수의 유무를 꼭 물어봐야 할 것 같다. 사수와의 소통을 통해 방향성을 잡아가는 것이 프로젝트 진행 시에 큰 도움이 되었다.
  6. 소규모 스타트업에서 TDD는 생각보다 쉽지 않다.
  7. 내가 생각한 기능의 API를 만들어 볼 기회가 없어서 아쉬웠다.
  8. Node.js를 배운지 얼마 되지도 않았는데 리팩토링 한다는 것 자체가 좀 어불성설인 것 같기도...

2. 삽질들

1) .env

MongoDB에 연결할 때 localhost DB의 경로를 추가하려면 authSource=admin을 추가해야 한다.

MONGODB=mongodb://(ID):(PASSWORD)@localhost:27017/(DB)?authSource=admin&authMechanism=DEFAULT

2) MongoDB ObjectId cast error

mongoosefind() 메소드로 MongoDB에서 해당 id의 객체를 검색할 때 objectId castError가 발생한 경우가 있었다.
Document의 _idObejctId 자료형인데 req.params.idstring 자료형으로 받아와서 비교하다보니 에러가 발생한 것이었다.

const mongoose = require('mongoose');
const ObjectId = mongoose.Types.ObjectId;

const id_obj = ObjectId(req.params.id);

이렇게 간단히 해결!

3) MongoDB ObjectId length error

MongoDB의 ObjectId는 BSON 자료형으로 binary serialization format이며 12bytes 혹은 24hex의 character이다.

path parameter로 해당 nft를 검색하는 api에서 잘못된 id값을 넘길시 발생했는데, objectIdLength라는 Validator를 만들어 해당 Error를 Handling 하였다.

module.exports = {
    assertion : (string) => {
        if (string.length !== 24){
            throw new ObjectIdLengthError(
                'NEWS_ID_VALUE_ERROR'
            );
        }
    }
}

4) return res.json

한 개의 response만 보낼 수 있는데 두 개 이상의 response를 보내게 되면 HTTP Error가 발생한다.
Scope 문제인 경우가 많은데 나도 그 경우에 해당되었다.
return res.json으로 해결

5) .catch() VS catch

promise 객체의 .catch() 메소드의 Scope는 해당 객체이다.
따라서 .catch() 메소드로 잡은 error를 throw해도 해당 function 전체가 exit되지 않는다.(이렇게 되면 res.json을 두 번 보내는 경우도 있기 때문에 또 HTTP error가 발생한다.)
error를 잡았을 때 해당 function을 탈출하는 것이 목표였기 때문에 async/await 방식으로 구현한 뒤, try-catch문을 사용하였다.

6) MongoDB Duplicate key error

wishlist API에서 update 함수를 구현할 때 발생한 에러이다.

condition이라는 인자를 통해 해당 Document를 update하는 부분인데 이미 존재하는 ObjectId를 계속 생성하려고 해서 발생한 error이다.

초반에 구현할 때에는 "...(spread syntax)를 활용하여 condition을 합치면 되지 않을까?"라고 생각해서 그렇게 구현했는데 두 개로 나뉘어야 할 condition의 객체들이 합쳐져서 정상적으로 작동하지 않았다.

//wishlist action
const updateWishlist = async(wallet, cond) => {
    try{
        const updatedWishlist = await db.wishlist.updateOne({wishlist_wallet : wallet}, cond);
        return updatedWishlist;
    }catch(error){
        throw new DatabaseError('DB_ACCESS_ERROR');
    }
}

module.exports = {
    Update : async(wallet, art_id) => {
            return updateWishlist(wallet, {wishlist_updated: Date.now(), $push:{wishlist_arts:{ $each: [art_id], $position : 0} }});
}

구현 로직을 변경해서 위의 코드와 같이 변경하니 정상작동하였다.

7) Mongoose find() VS findOne()

  • findOne() - if query matches, first document is returned, otherwise null.
  • find() - no matter the number of documents matched, a cursor is returned, never null.
profile
비진

0개의 댓글