멋사 미니 해커톤을 진행하면서 많은 내 자신의 부족함을 많이 느꼈다. 그 덕에 팀원들도 고생이 많았을거다.
다음 미니 해커톤과 중앙 해커톤에서는 내 맡은 바를 충분히 해내고 싶었기에,
팀원 한 명과 같이 작은 프로젝트를 해보기로 했다.
이번 토이 프로젝트의 목적은, '해보고 싶은 거 다 해보자'이다.
미니 해커톤과 달리 시간 제한도, 결과물 발표도 없으니 그동안 궁금했지만 써볼 기회가 없었던 기능/서비스나 개인적으로 부진한 내용을 전부 시도해보자는 뜻이었다.
둘 다 API를 활용한 데이터 불러오기를 한번 더 해보고 싶었기에,
흥미로운 API들을 찾아 그에 맞춰 주제를 정하였다.
그리고 선정한 주제는 Billboard Hot 100이었다.
<사전설계>
당일 빠른 진행을 위해, 전 날에 회의를 통해 아이디어를 모으고,
페이지 구성, 페이지마다 필요한 요소 등을 정했다.
협업 툴인 노션을 그 동안은 단지 링크를 통해 열람하는 데만 써봐,
노션을 통해 동시에 회의록을 작성해보았다.
내가 해보고 싶다 말한 기능은 js와 canvas를 활용한 순위 이력(history)의 시각화이다.
마침 조금씩 하고 있는 개인 토이 프로젝트가 js와 canvas에 관련돼, 좀 더 써보고 싶었고,
텍스트로만 정보를 보여주는 것은 새로운 점이 없어보였다.
<1일차>
일단 django 상에서 기본작업을 마치고, 가장 첫 번째로 한 작업은 API를 다뤄보는 것이었다.
Rapi-API 에서 'Billboard'를 찾아 이를 사용하기로 했다.
rapid-api라는 사이트도, 해당 api도 정말 편리하고 퀄리티가 높았다.
rapid-api의 경우 한국 관련 api는 잘 없지만, 아주 많은 api들을 한 눈에 볼 수 있으며
api를 구독함과 동시에 키를 발급해주어 즉시 api를 활용할 수 있게 해주었다.
또한 api통신의 수많은 방식들에 맞춰 코드를 작성해 보여줘, 이를 복사해 실행하는 것 만으로
데이터를 띄울 수 있게 된다. 또 웹 상에서 test endpoint를 해 그 결과를 바로 살펴볼 수도 있었다.
내가 어떤 api들을 구독했고, 각각 몇 번의 요청이 있었는지 등도 한 눈에 관리할 수 있다.
'Billboard'라는 api 역시 상당히 필드 수가 많고, 그에 따라 다양하고 자세한 정보를 제공한다.
또 hot 100 외에도 global 200, artist 100 등의 테이블도 제공한다. 아주 최신의 날짜도 사용할 수 있다!
따라 하나의 api만 활용해 필요한 거의 모든 데이터들을 얻을 수 있었지만,
문제는 이미지 url의 형태가 이상했다는 것이다.
온전한 path가 아닌 일부만 주어져, 그 앞에 어떤 주소를 주어야하는지 찾는 데 꽤 걸렸다.
그 외에도 적당한 parsing 방법을 고민하느라 생각보다 시간이 지체되었다.
그 후에는 model을 작성하고 init_db 함수를 작성해 실제로 데이터를 띄워보려고 했다.
model이야 타입과 길이만 정해주면 되니 빠르게 작성했고,
init_db를 작성해 parsing해주는 것 역시 필드 수가 많아 시간이 걸렸을 뿐 문제는 없었다.
그렇지만 실제로 실행 시 parsing 과정에서 되게 많은 error를 겪었다.
100 개의 곡에 수많은 필드가 있다보니, 어떤 곡의 특정 필드는 null데이터가 들어가 있었기 때문이다.
null 값이 허용되지 않는 필드들에 null이 들어가는 경우가 산재했고, 이는 에러를 야기했다.
null값에 대해 처리해주고, 예외 처리를 해주는 데 아주 많은 시간이 걸렸다.
테이블 자체가 스키마가 복잡해 각 필드들의 parsing 방법 역시 상이했기 때문이다.
그 밖에도 api가 제공하는 무료 test 요청 횟수 역시 모두 사용해 그 문제도 해결해야만 했다.
결국에는 모든 에러를 해결하고 (어떤 건 주먹구구식으로 처리해두었다) home.html에서 1위부터 100위까지
곡들을 띄울 수 있게 되었다. css 및 배치 부분은 아예 반영하지 않은 상태이다.
이후에는 git 과 github를 통해 지금까지의 프로젝트를 팀원과 동기화하려 했다.
git에 대한 부분은 책도 빌려 읽어보며 웬만큼 익혔다고 생각했는데,
오늘도 git 관련해서 문제가 발생했다.
gitignore 및 requirements 에 대해 미숙했고 repository에서 clone 시 레포지토리 폴더가 생성되고 그 안에 모든 문서들이 있다는 점을 간과했다.
이 부분은 그래도 어렵지 않게 해결할 수 있었다. 충돌이 없어 큰 문제로 갈 일이 없었기 때문이다.
그런데 clone이후에 서버를 돌리자 init_db함수를 실행시키는 '/chart/db' url에서 계속 에러가 났다. clone 전에 팀원의 화면에서 잘 작동하는 걸 확인했고, clone을 했으니 당연히 나도 잘 돼야만 하는데, 알 수 없는 에러가 자꾸 생겨 많이 당황했다.
문제는 date 값을 이리저리 바꾸다 clone전에 '2021-11-06'이라는
미래의 날짜가 들어가 있어 api를 제대로 불러오지 못한 것이었다....
그래도 갈아엎기 전에 찾아서 다행이다ㅎ
git에 대한 작업을 마친 후엔 detail,home페이지의 구체적인 레이아웃 설계를 했다.
윗 부분의 history 그래프는 내가 맡고, 그 외 정보들의 구성은 팀원이 맡아
분업을 시작했다. 그러다가 저녁 시간이 돼 이 상태에서 1일차 작업을 마무리했다.
<2일차>
2일차에는 detail 페이지를 띄우고, 두 페이지에 대한 css 그리고 부가기능들에 대한 작업을 진행했다.
나는 1일차에 다 만들지 못한 순위 history graph를 마저 만들었다.
데뷔 일자, 저번 주, 오늘을 x 축으로 삼아 각각의 순위를 표시해주고, 이를 선으로 연결해 한 눈에 보이도록
하는 것은 사실 1일차때 만들어 두고, 집에 갔었다.
const canv = document.querySelector(".canv");
const context = canv.getContext('2d');
#데뷔일자, 지난주 일자, 오늘 일자 표시
const debut_date = "{{music.debut_date}}";
const last_date = "2021-07-29";
const current_date = "2021-08-05"
context.fillText(debut_date,30,370);
context.fillText(last_date,315,370);
context.fillText(current_date,595,370);
#수평선 긋기
context.moveTo(30,340);
context.lineTo(680,340);
context.stroke();
#각 주마다 랭크 표시
const debut_rank = "{{music.debut_rank}}";
const last_rank = "{{music.last_week}}";
const current_rank = "{{music.rank}}";
const debut_pos = 35 + (3*debut_rank);
const last_pos = 35 + (3*last_rank);
const current_pos = 35 + (3*current_rank);
context.font = "12pt twaysky";
context.fillText(debut_rank,60,debut_pos-20);
context.fillText(last_rank,360,last_pos-20);
context.fillText(current_rank,660,current_pos-20);
#랭크 점들 이어 그래프
context.moveTo(60,debut_pos);
context.lineTo(360,last_pos);
context.lineTo(660,current_pos);
context.stroke();
다음과 같은 형태였다. 이제 더욱 보기 좋게 다듬고, 예외 케이스에서의 오작동을 고치고, 차트에 머문 주차수와
가장 높았던 순위를 표시해주기로 했다.
일단은 각 랭크와 x축 선 사이에 연한 선을 그어 더욱 그래프처럼 보이게 만들었다.
100위에 가까운 하위권에서 그래프가 x축 밑까지 내려가는 것도 고쳐주었다.
이후에는 @font-face를 통해 폰트들을 가지고와 텍스트들의 폰트와 크기를 수정했다.
마지막으로 우측 빈 공간에 차트에 머문 주차수와 가장 높았던 순위, 그리고 그 일자를 표시했다.
주요 로직은 1일차에 다 짜놓아 수월할 줄 알았는데, 자잘한 조정에 생각보다 더 많은 시간이 걸렸다.
사실 프로젝트를 끝낼 때까지 해결하지 못한 문제가 있다.
처음 들어간 곡의 detail페이지에서는 canvs내에 폰트가 적용이 되지 않는 것이었다.
새로고침을 하거나, 두 번째 방문 시부터 제대로 폰트가 보였다.
아마 폰트의 로드가 끝나기 전에 canvas를 로드해 버려서 폰트가 적용이 안된 것 같은데,
해결방법을 끝내 찾지 못했다. 가능해 보이는 방법들을 몇 개 찾았으나 갈아엎을 여유는 없었기 떄문이다.
그래프를 제외한 detail 페이지는 팀원이 작업해 이를 합쳤고, 이후에는 아까의 못난 home 화면을
제대로 꾸몄다. <hr>을 통해 각 곡을 구분해주고, 순위, 커버, 제목, 가수, 발매일자의 위치를 세부 조정해주었다.
폰트를 가져와 이를 적용하고, 커버이미지에도 링크를 주었다. 팀원이 navbar와 footer를 만들어 주어 home 화면의 구성을 완성했다.
이후에는 detail 페이지에 대한 css를 했다. 사실 detail페이지에선 팀원이 위치를 알맞게 다 조정해두어,
폰트와 텍스트의 상세한 조정만 했다.
마지막에는 검색 기능을 구현했다. 미니 해커톤 때는 paginator를 이용해서 조금 더 복잡했는데,
이번에는 차트 형태라 paginator가 없었기에, 쉽게 구현할 수 있었다.
대신, 검색 결과만 띡 나오니 너무 허전한 것 같아 검색 결과 수를 위에 출력해 주도록 했다.
def home(request):
musics = Music.objects.all()
query = request.GET.get('query')
if query:
musics = Music.objects.filter(title__icontains=query)
return render(request, 'home.html', {'musics':musics, 'length':len(musics)})
return render(request, 'home.html', {'musics':musics})
코드는 위와 같다. 검색어가 있을 시 if문에 들어가 필터링 결과 및 결과의 수를 home.html로 전달해준다.
미니 해커톤때와 유사하다면 유사하고, 다르다면 다른 프로젝트였다. 한 번 더 진행하는 느낌이라
같은 시간 내에 괄목할 만한 성장을 보여주고 싶었는데, 두 명이서 진행했고 질문을 받아줄 운영진도
없었던 지라 그 정도까지 발전한 결과물을 내놓지는 못한 것 같기도 하다.
그렇지만 절대적으로 봤을 때 결과물은 만족스럽다. 요즘 음원 사이트들의 특징답게
디자인도 심플하고 깔끔하게 잘 뽑힌 것 같고, 훨 복잡한 api도 다뤄냈다. js 기반의 기능도 추가했고,
미니 해커톤 때와는 다르게 설계도 직접 진행했다. 덕분에 만드는 재미도 훨씬 있었던 것 같다.
부트스트랩이나 tailwind css 같은 서비스를 한 번 써보고 싶었는데 하다보니 그러지 못한 것은 조금 아쉽다.
이번 토이 프로젝트를 통해 배운 것을 내 개인 프로젝트에서도 적용하고, 또 추후에 많은 것을 배워와
이러한 팀 토이 프로젝트를 진행하고 싶다는 생각도 들었다.
'활동 후기' 카테고리의 다른 글
소프트웨어공학 우정퀴즈 팀프로젝트 (2021.09~2021.12) (0) | 2022.01.01 |
---|---|
멋쟁이 사자처럼 연합해커톤 (2021.10.30 ~ 2021.11.06) (0) | 2021.11.11 |
교내 코딩테스트 대비캠프 (2021.08.01 ~ 2021.08.14) (0) | 2021.09.03 |
멋쟁이 사자처럼 미니 해커톤 (2021.07.24~2021.07.25) (0) | 2021.07.26 |