항해 사전스터디 회고록

프로젝트 깃허브 레포지터리 주소
프로젝트 주소(linkgather.shop)

1. 사전강의 스터디

약 3주간의 사전강의 스터디, 그후 약 4주간의 미니프로젝트가 드디어 끝이났다.
처음 스터디를 진행했을때 5주간 사전강의에 대한 스터디를 진행한다고 해서 5주동안 사전강의 들으면서 깊숙히 하겠구나라고 생각을 했었지만 스터디 하시는 분들의 열정은 역시나 대단했다..

1주일에 2주차씩 해서 3주동안 사전강의를 끝내고 거기서 배운 내용을 바탕으로 미니프로젝트를 하자가 첫째주가 끝날때쯤 말이 나왔다.(첫째주는 나 포함 다른한분이 직장에 다니던 중이라 시간이 여의치 않아 1주차 수업을 바탕으로 스터디를 진행했다.)

사전강의에서는 javascript는 거의 조금나오고 대부분 jquery를 이용하여 작업을 하게되는데 우리 스터디에서는 vanila javascript를 이용해서 한번 해보자는 말이 나왔고, 나 역시 jquery보다는 바닐라 자바스크립트를 이용하여 하는 것이 실력향상에 조금 더 도움이 되겠다는 생각이 들어서 찬성하였고 수업에 나온 코딩을 자바스크립트로 풀어서 해보는 시간을 가졌다. 그리고 자신들이 찾아본 사이트들 중에 유용하다고 생각되는 링크들은 노션에 남기기로 하였고 그 결과 아래 사진처럼 모였다.

노션에서 스터디조원들이 공부하면서 모아두었던 유용한 사이트들

수업시간에 나오는 코딩은 하나인데 4명이 각자 다른 코딩, 각자 다른 방식으로 코딩을 하는것을 보고 정말로 자유롭고, 재밌다고 생각했다. 그렇게 3주간 5주차의 강의를 다 듣고 각자 어느정도 수업을 익히자 미니프로젝트 주제에대해서 슬슬 말이 나왔고 주제는 코딩을 시작하는 사람들을 위한 강의, 유용한 사이트의 링크를 모아두는 사이트 였다.

2. 미니프로젝트

2.1 git

미니프로젝트는 깃허브를 이용해서 협업을 했고 깃을 사용하기는 했지만 깃플로우를 사용하지 못해 아쉬웠다.

처음에는 깃을 다들 몰라서 하루이틀정도 각자 깃을 공부해보는 시간을 가졌고, 테스트 레포지터리를 만들어서 각자 깃을 연습해보고자 했었다.

테스트 깃허브 레포지터리 링크
엉망진창이지만 재밌었다.

2.2 기능 나누기

깃을 각자 연습해보고 먼저 기능을 어떤걸 쓸건지 논의를 했었다.

  • 추천 사이트를 등록, 보여주기, 수정, 삭제 (CRUD)하는 기능과 og이미지, 썸네일 등을 가져오는 크롤링
  • 검색기능
  • 게시글 추천, 찜기능
  • 마이페이지 기능
  • 리스트 최신순/추천순 정렬 기능

등등 많은 기능들이 나왔지만 일단은 시간이 한정되어 있는만큼 어느정도 타협을 하자라는 생각을 다들 하고 저정도 기능만 구현해보자라고 생각했다.(이때는 2주정도만 할줄 알고있었다...2주였으면 이정도도 못했겠지..)

그리고 각자 기능을 담당하고 우선 html/ css 작업을 첫주에, 기능은 두번째주에 시작해보자라고 하고 작업에 돌입했다.(당시 수요일인가 목요일이어서 html, css 뼈대잡는걸 2일정도로 잡았던 것 같다.)

당시 사용했던 프로젝트 기능

그리고나서 2주차.
기능을 나눴을때 내가 맡은 기능은 검색기능이었고, 검색기능을 할때 엄청나게 고생했다...
내가 생각했던 검색기능은 처음에는

  • 검색단어를 입력할때 자동으로 그 단어가 포함된 카드가 촤라락 실시간으로 리스트 되는 프론트단의 짝맞추기였다.

2.3 검색기능.. 시련..

하지만 검색기능을 찾아보려고 네이버, 구글같은데에 검색을 해봤을때도 쿼리스트링으로 서버로 보내고, 검색기능을 검색해봤을 때도 form 태그를 이용한 검색이 주로 사용된다는 것을 알고 그부분을 해결하려고 했다.
첫번째로는 익숙한 post방식으로 검색기능을 구현하려고 했고

위 사진처럼 post방식으로 어느정도 하긴 했었다. 그런데 검색기능은 다른사이트에서 해봐도 쿼리스트링에 나온 값으로 하는게 맞는것 같아 GET방식에 대해 찾아봤다.

하지만 여기서 큰 문제가 발생했다...

검색기능은 DB에서 find해서 뷰로 보내주는 것이라 우리가 사용하고 있는 mongDB 검색기능에 대해서 찾아봤어야 됐는데 flask를 서버단에서 사용하고 있다는 강박에 시달려서 flask 검색기능에 대해서 찾아봤으니 나오지않았다...

그렇게 한 2일~3일정도 찾다가 어떤 블로그에서 mongodb 검색기능 이라는 단어를 봤고 그 단어를 본순간 망치로 머리를 두들겨 맞은 느낌이었다..
아...이거.. DB기능이구나...그렇구나...
그렇게 form에서 서버단으로 보내주고 서버단에서는 그걸 받아서 찾아주는거 까진 완성을 했는데 이번에는 서버단에서 js로 보내주는것이 안되었다.. (실력이 부족해서 아직도 db를 form으로 받아서 다시 json 파일로 변환해서 ajax 통신을 하는것은 못하겠다... 이부분은 추후 더 공부를 해야 될 것 같다..) 찾아본 결과 form으로 받아서 그 데이터를 직접 서버에서 랜더링해서 html로 보내주는 기술(?)이 있었고 그걸 위해서 jinja2 template 구조를 가져야 했다. 그렇게 스터디 조장님, 조원분들을 게더에 부른 후 이러이러한 이유로 jinja2 템플릿을 사용해야 할 것 같습니다... 라고 말씀드렸고 팀원분들도 어차피 1주차 미니프로젝트때 써야 할 기능이니까 미리 해보는 것도 좋겠다라고 긍정적인 반응으로 흔쾌히 수락해 주셨다.

2.4 jinja2 template

진자 구조로 나누는 것은 생각보다 수월했다. base.html에

{% block content %}
{% endblock %}

을 통해서 컨텐츠를 넣을 블록을 설정해주고
컨텐츠에 해당되는 것들은 따로 html을 하나씩 만들어서

{% extends "base.html" %}

{% block content %}
해당 페이지에서 들어갈 내용
{% endblock %}

을 만들어주고 서버단에서

return render_template('해당 html이름.html', jinja에서 쓰일 변수명 = 서버단에서 쓰인 변수명)

으로 변수로 데이터를 담아서 보내주었다.

2.5 검색기능 완성..미숙한 완성..

내가 검색기능에 최종적으로 사용한 코드는

text = request.args.get('text')
    # text는 form으로 데이터를 받음
    splitted_keywords = text.split(' ')
    # text를 공백으로 나눠서 여러가지가 검색될수 있도록함 이때 split된 데이터는 리스트로 만들어짐
    pipelines = list()
    pipelines.append({
        '$sample': {'size': 1}
    })
    #랜덤으로 하나 뽑아줌
    search_R = list(db.posting.aggregate(pipelines))
	#위에 pipelines에 해당되는 것을 db에서 찾아줌
    sep_keywords = []
    for string in splitted_keywords:
        sep_keywords.append({'$or': [
            {'title': {'$regex': string}},
            {'desc': {'$regex': string}}
        ]})
	#title에 string이 포함되는 것과 desc에 string이 포함되는 것 모두.
    search = list(db.posting.find({"$or": sep_keywords}, {
                  '_id': False}).sort('uploadtime', -1))
                  #위에 조건들을 모두 찾아서 최신순으로 정렬
    if text == "":
        return render_template('search.html', keywords=splitted_keywords, search=search_R, token=tokenExist)
        #만약 text를 입력하지 않았다면 있던 카드들중 랜덤으로 하나를 데이터로 보내줌
    else:
        return render_template('search.html', keywords=splitted_keywords, search=search, token=tokenExist)
#text를 입력했다면 입력한 text가 포함되어있는 카드를 최신순으로 정렬해준 데이터를 보내줌

인데 처음에 구상했던 것들과는 많이 달라졌다.
처음에는 검색기능을 할때 검색을 하면 title, desc에 검색어가 포함되어있는 리스트들을 정확도 순으로 정렬하고 싶었다. 하지만 정확도 순으로 정렬할때 문제가 생겼는데 처음에는 find만 써서 하려다 보니 sort에서 정확도순을 어떻게 구현해야 할 지 몰랐고 찾아봤더니

텍스트 인덱스를 만들어야 됐고 인덱스를 만든 후에 $text, $search를 통해서 인덱스안에서 검색어를 찾고나서 $meta 'textScore' 표현식을 써서 정렬을 한다고 나와있었다.

위에 나온 방법대로 했을때 찾아지고 실행도 됐는데 검색어를 포함한 search가 아닌 검색어와 정확한 text만 찾아졌었다. 포함되게 검색을 하기위해서 string에 /"를 앞뒤에 붙여주면 된다고 해서 붙여줬는데 안되길래 이방법을 포기하고 최신순으로 정렬하는 방법을 택했다... 이방법이 왜 안되는지는 추후에 검증해봐야 될 것 같다. 분명 되는 방법이 있는데 내가 검색기능에 너무 지쳐있어서 넘어갔었던 것 같다.(변명 같지만 검색기능을 한 일주일동안 하루에 10시간 이상씩 찾아봤던 것 같다.)

그래서 결국 find를 사용하여 string이 title, desc에 포함되어있는 리스트를 뽑아주고 최신순으로 정렬하는 것으로 마무리했고 이를 jinja템플릿으로 데이터를 넘겨주어 for문으로 카드를 완성시켰다.

그리고 네이버에서 아무것도 검색하지않고 검색버튼을 눌렀을때, 즉, 입력값이 ""일때 랜덤으로 결과가 하나 나오길래 나도 그 기능을 구현하고 싶어서 db에서 랜덤으로 샘플을 뽑아주는 $sample 표현식을 사용했고 size는 1로 1개만 뽑아주는 것으로 구성했다.

2.6 반응형 디자인

스터디 조원분 중에 한분이 css에 굉장히 많은 지식을 가지고 계셔서 반응형 디자인을 할때 가장 어려운 부분들(작은 사이즈가 아닌 큰사이즈)을 도맡아서 해주셨다. 나는 width 421~767px부분을 맡았는데 생각보다는 반응형이 어렵지 않았다. 물론 정확하게 비율을 맞게하는 부분에 대해서는 생각하지 않았고 자연스럽게 줄어드는 것에 초점을 맡아서 수치를 위의 크기들과는 맞추지 않았지만 그래도 반응형디자인이라는 것을 하면서 크기에 따라서 자연스럽게 디자인이 바뀐다라는 것이 새롭고 신기하게 다가왔다.

2.7 서버구동

스터디원 4명중 나를 제외한 다른분들은 프론트 개발자를 희망하셔서 서버구동은 내가 담당해서 했다. 서버구동을 위해서 filezila, aws ec2, git bash(ubuntu)를 사용했다.
서버를 처음 구동시킬 때 나는 당연히 아무런 문제없이 진행 될 줄 알고있었다. 로컬에서 이미 많은 테스트를 했었고 모두 다 무리없이 돌아갈 수 있을거라고 예상했기 때문이다. 하지만 우리가 구동하는 서버의 os는 리눅스였고 테스트했던 서버는 윈도우여서 뭔가 다른 설정이 있었던 것 같다. 로컬에서는 잘만 돌아가던 것이 퍼블릭서버에서는 오류가 생겼었다.
처음에는 로그인, 회원가입이 문제였다. 로그인 회원가입기능을 담당하시는 조원분이 서버파일인 app.py가 아닌 따로 python 파일을 만들어서 app.py에서 불러오는 방식으로 하셨는데, 그부분에서 뭔가 문제가 생겨서 404에러가 생겼었다. 그래서 그 파일들에 있던 함수들을 app.py로 옮겼고, 그 후 500에러가 생겨서 확인한 결과, 함수 내부에서 인자를 받아오지 못하는 현상이 있었고, 함수인자를 받아오는 부분을
serialize대신 일일히 데이터에 값을 대입시켜주는 방법을 택했다. 그것을 해결하는 도중에 처음에는 서버 문제인 줄 알고 aws 인스턴스를 종료하고 다시 만들었었고, 서버환경을 구축하는 와중에 mongoDB에 문제가 생겼었다. mongoDB에 접근권한이 막혔었고 그 문제를 해결하기 위해서 mongoDB를 서버에 새로 설치하고(원래는 학원에서 제공해준 서버환경 한번에 구축하기 파일을 설치해서 한번에 구축했었는데, 여기서 몽고디비만 다시 설치했다.)실행했다.
몽고디비가 잘 설치되고 실행을 했을때 다시한번 문제가 생겼었던 것이 원래는 js ajax통신을 통해서 값이 서버로 넘어가야 하는데 html의 form을 통해서 서버로 바로 넘어가버려서 원하는 통신이 제대로 되지 않았다. 이를위해서 조원분이 js구문을 addEventListener로 바꾸어 주자 해결이 되었다. 그 후에 jwt가 문제였는데, jwt가 윈도우에서는 str타입으로 전송이 되던게 bytes타입으로 전송이 되어서 제대로 통신이 되지 않고있었다. 그래서 검색을 해서 ujson 모듈을 사용해서 제대로 통신이 되도록 만들었다.

3. 아쉬운점

  • 처음 설계의 부재
    설계를 하지않고 무작정 이런기능은 어때요 이런기능은 어때요 하면서 '합시다!'의 분위기로 휩쓸려서 시작을 했기 때문에 설계를 하지않고 무작정 했다. 그래서 구현되지 못한점이 많았다. 예를들어 찜기능은 거의 필수기능으로 넣으려고 했었는데 기능은 넣었지만 유저별로 그 기능을 각자 사용해야 되는데 기능이 사이트에 db로 되어있기 때문에 찜기능은 우리 사이트 공용 기능으로 되어버렸다. 이 부분을 수정하기에는 시간이 부족했고 이런 설계 하나하나가 부족하게 느껴졌고 그만큼 실력이 부족했다고 생각한다.

  • jinja템플릿
    jinja템플릿을 너무 늦게 썼었던 것이 시간부족에 한몫했었다고 생각한다. 처음부터 jinja에 대해서 공부하고 했었더라면 하루 이틀정도는 시간을 더 아꼈을 거같고 그시간동안 우리가 구현하지 못했던 기능들 (나는 좋아요, 찜기능의 개별화, 마이페이지에 자신이 찜한 카드만 보이기 같은 원래는 계획했지만 구현하지 못한 기능들을 구현하고 싶었고 이런 기능들 외에도 카드마다 기술스택을 넣고 카테고리화 시키고 싶었다.)을 구현할 수 있었을 것만 같았다.

  • 검색도 기술이다.
    검색도 기술이다라는 것을 이번에 뼈저리게 느꼈고, 그만큼 내 실력이 아직 한참 부족하다는 것을 느꼈다.
    검색기능에 시간을 너무 많이 쏟은 것 같았다. 검색기능을 구현하기 위해 처음에는 어떻게 구현해야 할 지 모르니까 당연히 서버에서 뭔가 검색을 하는거니까 서버에 대해서 찾아봐야겠다. 라고 생각해서 flask 검색기능에 대해서만 찾아봤다. 하지만 그건 너무 크나큰 오산이었다. DB는 단순히 저장만 하는 공간이 아니라 DB 나름의 기능이 있을텐데 그것을 관과하고 서버에서만 문제점을 찾고있었던 것이었다. 자신이 어떤 기능을 구현하고 싶고, 그 기술을 구현하기 위해 구글링하고 검색하는 것도 실력이고 기술이다라는 것을 이번 프로젝트를 통해 진심으로 뼈저리게 느꼈다.

  • 로컬에서만 생각한 서버.
    로컬과 리눅스를 사용한 퍼블릭 서버와는 기본 설정이 다른 것 같다. 그래서 그 차이에서 생기는 오류들이 있었고, 이때문에 원래 배포하려던 금요일에서 마지막날인 토요일로 배포가 하루 밀어지는 불상사가 발생했다. 다음부터는 배포를 조금 더 일찍해보고 배포한 서버에서 테스트를 걸친 후에 완벽하게 준비해야겠다고 생각이 들었다.

4. 회고

이번 부트캠프 사전스터디는 애초에 사전 강의 스터디로 모였었고 나는 그것으로 끝날 것이라고 생각했다. 그런데 다른 스터디원들도 정말 열정 넘치시고 잘하시는 분들을 운좋게 만나서 나도 한순간에 한단계, 두단계정도 레벨업 한 것 같아서 기분이 정말 좋은 스터디였다고 생각한다. 사실 스터디를 하는 도중에 약간 서로 열띤 토론을 해서 기분이 상할 수도 있겠다...라는 생각이 들긴 했지만 다들 열정이 많으셔서 열띤 토론이 이어졌었던 것 같고, 그로인해 처음에 생각했던 것들보다 조금 더 좋은 프로젝트 결과물이 만들어 졌던 것 같다. 다음부터는 뭔가 새로운 프로젝트를 할 때 아쉬웠던 점을 보안하고 하고싶은 것들을 모두 구현해내는 사람이 되고싶다.
그리고 이번 스터디를 통해서 좋은 사람들을 알게된 것 같아서 기분이 너무좋다.

좋은 웹페이지 즐겨찾기