안녕하세요. 지난 글에 이어 지적 덕후생활 공동체(지덕체)개발기를 연재하고 있는 ryukim입니다.
지난 글에서는 1주차 과제였던 파일 검증 클래스 구현, 큰 용량의 파일 업로드 방법, 환경 변수 파일 분리 과정과 피드백에 대해 다뤘는데요.
오늘은 2주차 과제를 해결하면서 겪었던 시행착오와 피드백에 대해 이야기 해볼까합니다.

파일 관리 운영 정책 설계하기

휴지통이 존재하는 이유

2주차 첫번째 과제는 ‘파일 관리 운영 정책 설계하기’였습니다.
멘토님이 이 과제를 주신 이유는 저의 기존 파일 관리 정책이 굿즈 정보를 삭제할 경우 해당 굿즈의 이미지도 바로 삭제하는 방식이었기 때문입니다.
이렇게 정책을 구성할 경우 서비스 도중 오류 혹은 실수 파일이 삭제된 경우 대응할 수 있는 방법이 없다는 문제점이 있다는 것을 알려주셨습니다.
그래서 이런 문제점을 해결할 수 있는 파일 관리 운영 정책을 나름대로 짜보았습니다.

이렇게 손으로 직접 써본 후 본격적으로 디렉토리 구조를 적용했습니다.

S3로 이주하기

지난 시간 과제였던 용량이 큰 파일 업로드에 대응할 수 있는 방법 중 제 서비스에 가장 적합하다고 판단한 ‘정적 파일 서버와 클라이언트가 직접 통신하는 방식’을 구현하기로 결정한 상태였기 때문에 디렉토리 구조도 기존 로컬 대신 정적 파일 서버에 바로 적용하기로 했습니다.
어떤 서버를 사용할지 고민하던 중 배포에 사용하기로 결정한 EC2와 함께 AWS에서 제공하는 S3라는 서비스가 있다는 것을 알게 되었고 쉽게 사용할 수 있고 EC2와 추후 다른 작업을 연동하기에도 편리하다는 장점이 있어 정적 파일 서버로 사용하기로 결정했습니다.
presigned url을 발급 받기 위해 aws-sdk 라이브러리를 사용했고, 이렇게 발급받은 presigned url을 클라이언트로 전달하면 클라이언트에서 axios를 통해 파일을 바로 S3서버로 보내줍니다.
이 과정에서 HTTP PUT 메소드를 사용하였는데요. 이 때 Restful API의 원칙 중 메소드와 주소만 보고 어떤 동작을 할지 명확하게 알 수 있어야한다는 원칙이 있고, 제가 GET과 POST 메소드만 사용하고 이 마저도 혼동해서 사용하고 있다는 것을 알게 되었습니다.
이후 대대적으로 백엔드 코드와 프론트엔드 코드에서 HTTP 메소드를 수정하는 과정을 거쳤습니다.

사람이 할 일을 컴퓨터에게 미루자

오류 등에 따른 파일 삭제 시 복구를 위해 trash 디렉토리에 30일간 보관 후 삭제하는 정책을 만들었고, 이를 위해 aws-sdk 라이브러리에서 제공하는 listObject 메소드와 deleteObject를 사용하여 API를 제작했습니다.
하지만 매일 30일이 지난 파일을 삭제해주는 기능을 어떻게 구현할지 고민하다가 일단 제가 직접 Postman을 이용해 API를 호출하는 것으로 하고 멘토님께 갔습니다.
멘토님은 이런 동작을 대신 해주는 배치 프로세싱 툴이 있다며 대표적으로 AWS의 lambda를 이용하는 방법을 찾아보라고 하셨습니다.
이후 집으로 돌아와 멘토님이 알려주신 lambda, 스케줄링 등의 키워드 검색을 통해 https://docfriends.github.io/DevStrory/2019-05-21/lambda-scheduler/ 다음 블로그를 발견했고, lambda로 기존 API를 옮겨 주었습니다.
이 과정에서 수차례 에러에 직면했는데, lambda에서 nodejs 코드를 동작시킬 때 외부 라이브러리를 사용하는 부분에서 오류가 발생했습니다.
이 문제는 https://medium.com/signal9/aws-lambda-layer-사용하기-node-js-8c299a1d0a6f 다음 블로그를 통해 layer를 추가하는 방법으로 해결할 수 있었습니다.
에러를 모두 수정한 후에 지속적으로 모니터링한 결과 에러는 나지 않지만 파일이 삭제되지 않고 있는 것을 확인할 수 있었습니다.
이에 대한 해결책은 검색하기도 어려웠고, 아무리 로그를 찍어봐도 해결책이 생각나지 않아 어떻게할지 고민하다가, 일단 콜백 지옥부터 해결하고 나서 다시 생각해보자고 결론 내리고 async/awiat을 이용한 비동기처리를 적용했습니다.
그리고 다시 테스트해보니 갑자기 잘 작동되기 시작했습니다(?)
혹시 다음 코드를 보시고 무엇이 문제였는지 아시는 분은 댓글 남겨주시면 감사하겠습니다. (개인적으로는 대괄호를 이용한 객체 접근법이 lambda에서 제대로 작동하지 않는 것이 아닐까하는 추측을 하고 있습니다.)

개발자의 숙명, 로그

일단 있어보이는 걸 만들었다…

멘토님께서 로그를 남기는 방법을 고민해오라고 하셨을 때 저는 어김없이 구글에 검색을 해봤고 nodejs 환경에서는 winston이라는 라이브러리와 morgan이라는 미들웨어를 혼용해서 사용하면 훌륭한 로그를 얻을 수 있다는 것을 확인했습니다.
그렇게 다음과 같은 있어보이는(?) 로그를 얻을 수 있었습니다.

또 하나 완성했다는 신나는 마음에 멘토님께 보여드렸고, 곧 저의 로그는 아주 일부분에 불과하다는 것을 알게 되었습니다.

로그에는 여러 종류가 있었다

멘토님께서는 제가 수집해온 로그들은 통신에 대한 로그라는 것을 알려주셨고, 그 외에 또 어떤 로그들이 있을지 말해보라고 질문하셨습니다.
조금 고민하던 저는 고객의 반응을 수집하기 위한 로그(action log)가 필요할 것 같다고 말씀드렸습니다. 그 외에도 예외상황을 파악하기 위한 동작 기록 로그가 필요하다는 것을 알게 되었습니다.

일단 조금 미뤄두겠습니다…

멘토님께서는 이런 동작 기록 로그나 액션 로그들에 대한 정보는 구글에 잘 나오지 않는 것이 당연하다고 말씀하셨습니다.
이런 로그들은 회사마다, 개발자마다 다 스타일이 다르기 때문이고, 따라서 저도 나름의 로그 기록 스타일을 고민해봐야 한다고 하셨습니다.
다만 이런 부분은 오랜 고민이 필요하고 많이 어려울 것이라고 말씀해주셨고 이를 일부 대체할 수 있는 구글 애널리틱스와 같은 툴도 있다고 말씀해주셨습니다.
로그 기록 방식에 대해 몇일 더 고민하고 서점에도 여러 번 다녀왔지만 적당한 결론을 내리지 못한 저는 일단 MVP 완성까지는 조금 더 개발에 집중하고 GA와 같은 툴을 이용하기로 결정했습니다.

신상품 페이지네이션

깔끔한 랜딩페이지라 쓰고 귀찮음이라 읽는다

2주차 세번째 과제는 랜딩 페이지에 신상품을 8개씩 페이지네이션하는 것이었습니다.
멘토님은 무한 스크롤이나 숫자 페이지네이션을 예로 드셨지만 개인적으로 랜딩페이지에 무한 스크롤을 만드는 것은 별로 깔끔하지 못하다는 생각이 들었습니다.
그렇다고 숫자 페이지네이션을 구현하려고 하니 생각보다 쉽지 않았고 저는 백엔드에 조금 더 집중하고자했기 때문에 따라하면서 배우는 웹개발 강의에서 학습했던 더보기 버튼을 활용했습니다.
하지만 그것도 별로 좋지 않다고 판단하여 이후 더보기 버튼을 만들어 신상품 페이지로 이동하면 그 안에서는 무한 스크롤로 상품들을 보여줄 수 있도록 했습니다.
무한 스크롤은 다음 블로그 (https://medium.com/@ghur2002/react에서-infinite-scroll-구현하기-128d64ea24b5)를 참고하여 구현하였으니 관심있는 분들은 참고하시면 좋을 것 같습니다.

과제에 숨어있던 깊은 뜻

멘토님께 가져가니 이 과제를 왜 내줬는지 알고 있냐고 물어보셨습니다.
저는 그 전까지 랜딩페이지에서 좋아요 수를 바탕으로 인기있는 상품들만 보여줬었는데 이럴 경우 처음 생성된 상품들은 영원히 노출되지 않는다는 문제점이 있었고 이를 해결해줄 수 있는 좋은 방안이라는 것과 멘토님 말씀처럼 허전했던 랜딩페이지를 채워줄 수 있다는 것을 이야기했습니다.
멘토님께서 새롭게 질문하셨습니다. 만약 처음 8개의 상품을 불러온 순간부터 더보기 버튼을 눌러서 8개의 상품을 더 가져오는 순간 사이에 새롭게 상품이 추가된다면 어떻게 될지 물어보셨고, 저는 새로고침이 될 때까지는 나타나지 않을 것이라고 말씀드렸습니다.
그리고 이것이 바로 이 과제의 핵심이라는 것을 곧 깨달았습니다. 혼자 개발하면서 더미 데이터를 만들 때는 절대 생각할 수 없는 상황이었지만 실제 서비스 과정에서는 충분히 발생 가능한 상황이고, 이럴 경우 고객들이 불만을 가질 수 있고 좋은 서비스가 아니라고 멘토님께서 말씀해주셨습니다.
이를 해결하기 위해 무엇을 이용하면 될지 생각해보라고 하셨고, 제가 쉽게 결론을 내리지 못하자 스택 자료구조를 이용하면 된다고 말씀해주셨습니다.
이것이 바로 저희가 알고리즘과 자료구조를 공부하는 이유였던 것입니다! 늘 알고리즘과 자료구조를 왜 배우는지 의문을 품고 있던 저는 그제서야 그 필요성을 이해할 수 있었습니다.
다음 주에는 신상품을 가져오거나, 상품을 어떤 기준으로 표시할지 이런 운영 정책적인 면들을 설계하고 스택을 이용해 실시간으로 추가되는 상품들을 가져오는 기능을 구현해오라고 하셨습니다.

다음 글에서는 3주차 과제를 해결한 과정과 시행착오 피드백에 대해 써보겠습니다.
긴 글 읽어주셔서 정말 감사합니다!