25~29.Nov.2020

25_ notification, Pub/Sub pattern

1. notification

notification (알람) 기능을 구현중이다. 메시지가 왔다는 알람(실시간으로 유저에게 전달해주는) 종류의 것이 아니고 로켓펀치 사이트에서의 알람 정도만 구현하면 된다. 실시간 알람이 아니므로 시간순서대로 쿼리해서 보여주면 된다. 중요한 것은 Publisher/Subscriber 패턴을 이용한다는 것이다. Node.js 자체의 'Events'에서 필요한 모든 기능을 제공해주기 때문에 document만 잘 읽고 진행하면 어렵지 않다. (events도 한번 번역하고 넘어가야겠다.!) 이벤트를 .on 함수를 이용해서 세팅하고 .emit함수를 이용해서 세팅된 이벤트를 실행시키면 끝이다. 생각했던 것보다 아주 간단한데 더 계속 보다보면 어렵고 재미있는 내용이 나오지 않을까 싶다.
여기서 궁금한건 비동기로 작동하는 event loop가 어떻게 안정성을 가지느냐.

Q1. event loop의 안정성이 궁금하다.

아직 notification이 Subscriber로 작동할때의 상황이 명확하지 않아서 어떠한 event들에 작동해야하는지만 세팅해둔 상태고 어떤 callback이 작동하는지는 정의하지 못했다.

notification subscriber를 emit해야 하는 api를 작동할때 callback을 채울 예정이다.

TODO

Node.js의 events api를 자세히 봤다.
일을 시작하기전, 프로젝트 진행할 때는 JS의 비동기, Node의 event loop를 제대로 알지 못하고, 감도 제대로 못잡고 지내왔는데 관련 글들을 여러번 읽다보니 어느새 익숙해지고 이해해가고 있다. 이번에 제대로 글로 정리하고 넘어가면 아주 좋다.

TODO_1: JS 비동기 글로 정리,
TODO_2: event loop 글로 정리.



26_ Unit TEST(jest) / banner CRUD

1. banner CRUD

홈화면에서 보여줄 대표적인 이미지들을 어떻게 처리해야할까?
대표 이미지들의 상황: 관리자 페이지에서 관리자들이 간간히 정기적으로 이미지를 바꿀 예정이다. 개수는 5개.
홈화면으로 들어올 때마다 똑같은 query를 해줘야하는 건데 5개만을 위한 collection을 만들어두는게 좋을까?
혹은 새로 만들지 않고 이미 이미지가 저장되어 있는 collection에 '대표 이미지'라는 필드를 추가해서 관리할까?

TODO

Q2. DB의 query하는 과정을 자세히 알아봐야한다.
TODO_3: query 속도 측정해보기.

2. test와 db 연결

문제 상황: "model을 import 해서 바로 쓰면 되겠지?" 했다. 이유는 서버를 따로 켜놓은 채로 test를 진행하니깐 ! 당연히 되겠지 했다.

해결: endpoint로 api를 직접 실행시킨게 아니고 test환경안에서 스크립트를 실행시킨 것이기 때문에 test 코드에 따로 DB연결을 시켜줘야 한다.
참고: Connecting Jest and Mongoose

3. 개별 테스트는 다른 테스트에 영향을 주면 안된다.

내가 한 테스트는 단위테스트가 아니었다. 개별 테스트가 다른 테스트에 영향을 주면 안되는데 다른 테스트 들에 영향을 주고 있다.
그런데 같은 DB안에서 테스트 하는데 영향을 안줄 수 있나..?

지금 문제 상황
1. banner collection에 document 갯수를 5개로 제한한다.
2. 에러 테스트를 하기 위해 5개의 document를 만들어둔다.
3. banner를 하나 더 새로 만드는 작업을 실행시킨다.
4. 예상한 에러가 발생하게 된다.

그런데 테스트들이 비동기로, 순서없이 진행되기 때문에 다른 테스트에서 베너를 만들고 삭제하고 하는 작업들이 같은 데이터베이스에서 진행된다. 미리 만둘어둔 5개의 베너가 다른 테스트 작업으로 인해 4개가 될수도 있고. 5개를 미리 만둘어뒀기 때문에 에러가 나면 안되는 테스트에서 에러가 나기도 한다.

해결책
비동기로 돌아가는 환경에서 + 같은 DB를 쓰는 상황에서 이걸 제어하기는 거의 불가능하다. 테스트를 모두 동기방식으로 실행시킬수도 없는 노릇이다. 프로덕션 상황에서도 비동기로 돌아갈터이니 테스트만은 동기로 짠다? 는건 말이 안된다.

document에 갯수 제한을 두지말자. 일단은 프론트에게 경고문구가 뜨게 해달라고 하자. 다른 작업이 더 시급하다.

그리고 document 갯수 제한을 두는 상황이 뭐가 있을까 생각해봐도 딱히 떠오르지 않는다. 그러니 갯수 제한을 포기하는 걸로.


27_ Unit TEST(jest)

1. endpoint 테스트에서 service 계층 테스트로 변경.

request를 테스트 하는 것은 의미가 크지않다고 한다. 이것도 third party인거니깐.(내가 짠 코드가 아닌거니깐)

endpoint를 직접 테스트해왔다. 진짜로 request를 보냈다. 점점 테스트가 느려져서 '아 이건 내 방식이 문제가 있는 거다.!' 라고 느끼고 단위 테스트를 다시 찾아봤다. endpoint를 직접 테스트 하는 사람들도 있지만 테스트마다 http통신을 하는 건 너무나 느려지기때문에 지양해야한다고들 한다. 그래서 이번에 도전할 것은

2. jest 테스트가 돌아가는 방식 제대로 알기.

describe를 async로 작성했다.
describe('CREATE banner', async () => { }); 요렇게.
했더니 아래 오류가 나왔따.

● Test suite failed to run
    Returning a Promise from "describe" is not supported. Tests must be defined synchronously.
    Returning a value from "describe" will fail the test in a future version of Jest.

describe안에서는 동기적으로 작동하는건가??

TODO: test가 돌아가는 방식 비동기? 동기? 수평?

https://github.com/facebook/jest/issues/6194
https://stackoverflow.com/questions/32751695/how-to-run-jest-tests-sequentially

3. service 계층에서 테스트할시 주의사항. - error catching

endpoint로 테스트를 하면 서버를 통째로 테스트하는 것이기때문에 대부분의 것이 세팅되어있다. 그러나 http 통신을 거치지않는, 특정 코드만을 테스트할 때는 서버에서 걸러주던 에러 처리 부분이 빠져버리게 된다. 나의 경우에선 서버를 작동시킬때 첫번째 미들웨어로 errorHandelr를 넣어둬서 모든 request에서 발생하는 error를 처리해준다. 서버 로드 과정이 없으니 errorHandler, error catch해주는 부분이 없다. 그러니 jest 테스트 코드에서 catch하지 못했던 것이다.

let res = await container.resolve('artistService').getArtists(queryParams);

expect(thrownError.code).toEqual(100006);

아래처럼 try.. catch를 넣어줬다. =>

try {
  let res = await container.resolve('artistService').getArtists(queryParams);
}
catch(error) {
  thrownError = error;
}

expect(thrownError.code).toEqual(100006);

29_ 기능 구현중

1. MongoDB의 장점

만들고 있는 서비스에서는 유저의 종류가 3가지가 있다. 이 유저들에 대해 모두 개별 Collection을 만들어줬었다. 이유는 개별 유저마다 'required'한 정보가 너무나 달랐다. 그런데 그렇게 진행하다보니 3가지 collection을 한번에 검색할때 query를 세번이나 해야했다.

문제 상황: 우리 서비스에선 세 종류의 유저가 있다. 그런데 유저를 같은 컬랙션안에서 field로 구별한 것이 아니라, 세 종류의 유저 모두를 개별 Collection으로 만들어뒀다. 그러다보니 귀찮은 일이 많아졌다.

  • 모든 유저를 한번에 검색해야할 때는 query를 3번이나 해야한다. 코드적으로도 귀찮고 성능적으로도 아주 찜찜하다.
  • 유저모두 사람이니, 사람에 대한 정보를 관리하는 API는 해야할 일이 비슷하다. 비슷한 수준을 넘어서 완전히 똑같은 코드일 확률이 높다. 그런데 세가지 Collection으로 나뉘어있다보니 거의 비슷하지만 아주 조금 다른 코드를 세번이나 만들어야 한다. 아주 귀찮다. 유지보수도 힘들어진다.
  • 최대 단점 ! 위 두가지의 귀찮음, 찜찜함이 아주 여러곳에서 나타나서 계속 찜찜함을 느끼게 한다.

해결: 그래서 한개의 컬랙션으로 합쳤다. 인생은 참 살기 좋다. 어렵게 살지말자..
개별 유저마다 required한 정보가 꽤 다르긴 하지만 최대한 required를 쓰지 않으려고 모델을 변경했다. 정말 필요하다면 프론트에서 강제성을 두게 할 예정이다. + middleware로 required를 체크하게 만들 수도 있다.

다시 한번 느낀 몽고DB의 장점!

  • Scalability
    모델의 구조를 개발 진행중에 바꾸기가 쉽다. 아주 쉽다. 그래서 MVP만들때 NoSQL이 좋다고~ 좋다고~ 인터넷에서 그러던 것이었다. 그냥 수정하면 끝이니 이 얼마나 편한가.



이번주 정산

정산:
하... 어쩌다보니 거의 나 혼자 백엔드를 만들어야 하는 상황이 되어버렸다.
시간도 촉박하고하니.. 일단 api부터 모든 기능 작동하게 만들려고 한다.
빈틈이 있어도 기능다 돌아가게 한다음에 TEST CODE작성하는 방향으로 바꿨다.
이삼주동안은 주말에 공부못하고 일을 해야할 상황 ㅜㅜ 밑의 해야할 것들은 다 못하게 돼버렸다. !...

이번주의 질문:

Q1. event loop의 안정성이 궁금하다.
Q2. DB의 query하는 과정을 자세히 알아봐야한다.


이번주의 TODO:

TODO_1: JS 비동기 글로 정리,
TODO_2: event loop 글로 정리.
TODO_3: query 속도 측정해보기.

좋은 웹페이지 즐겨찾기