[프로젝트] ARS 개인 프로젝트 소개 및 정리

애이용·2021년 8월 9일
19

project

목록 보기
2/2
post-thumbnail

개인 프로젝트를 거의 끝냈다.
1차 개발 후기를 이어 프로젝트 소개 및 후기를 쓰려고 한다.

✔️ ARS 프로젝트 소개

ARS는 Algorithm Review Service의 약자로
알고리즘 문제 복습을 편하게 할 수 있는 "나"를 위한 웹 서비스이다.

평소에 알고리즘 문제를 풀 때 깃허브에 코드를 작성하고, 다시 풀고 싶은 문제들을 여기 벨로그에 정리했다. 내 벨로그를 보면 복습하자 태그로 확인을 해서 추가 정리를 계속 해왔다. 하지만 블로그로 포스팅하는 것만으로는 글도 많아지고,, 충분히 복습을 할 수 없었다.
또 그때마다 마음에 드는 문제 이름을 골라서 풀기도 해서 막 복습하는 느낌이었다. 블로그 포스팅만으로는 내가 원하는 바를 충족하지 못했다.

그래서 개인 프로젝트로 알고리즘 복습을 계획적이고, 편리하게 할 수 있는 서비스를 만들어보았다!!

간단하게 기능을 설명하자면
리뷰하고 싶은 문제를 등록하여 복습 알림 날짜를 설정해서 계속해서 Review를 추가할 수 있도록 구현했다.

여기서 핵심은 Slack으로 Review 알림을 주는 기능을 추가했다! 알림까지 온다면 더욱 더 복습을 할 의무감이 생길 것이라고 생각한다.ㅎ

실제 알림 내용

나한테 중요한 것이 알고리즘 문제 풀이들을 기록하는 거여서 지금도 계속 해서 내가 만든 프로젝트에 작성하고 있다. (벨로그에 써놓은 것들도 다 옮기고 있다.)
넘 만족스럽게 잘 쓰고 있다.

1차 개발에서는 스프링부트 환경에서 백엔드 기능과 화면을 모두 구현했다.
하지만 개발을 하면서 이렇게 뷰에 전달하는 게 맞는 건지 헷갈렸다. 또 완전한 REST API 서버로 백엔드를 개발 하고 싶어서
이번에는 React로 프론트엔드 개발을 진행했다. 약 일주일 간 프론트엔드 개발을 진행했다.

✔️ 기능(페이지) 소개

1차와 비교해서 소개를 해보겠다..ㅎㅎ
내기준 1차보다 훨씬 UI가 좋아지고, 기능들도 많이 추가됐다!

📄 메인 페이지

  • 로그인 하지 않은 경우
  • 게스트로 로그인 한 경우
    서버에서 따로 처리하지 않고, 구글 로그인으로 이름 정보만 저장합니다.
  • "나"로 로그인 한 경우
    문제 등록 버튼과, 환영 문구가 나옵니다.

📄 페이징 처리

📄 태그 별 문제 리스트 조회

태그 별로 문제 리스트를 조회할 수 있습니다. (1차에 없던 기능)
ezgif com-gif-maker (9)

📄 문제 상세 조회

  • "나"로 로그인 한 경우

    오른쪽 리뷰 박스는 고정된 채 스크롤이 됩니다.
    또한 즉시 난이도 수정이 가능하고, 상세하게 알림 날짜를 수정할 수 있습니다.
    문제 링크를 클릭하면 새 창으로 문제 페이지가 나옵니다.
    태그를 클릭하면 해당 태그 별 문제 리스트를 조회할 수 있습니다.

  • 로그인하지 않은 경우 & 게스트로 로그인 한 경우

    Add Review 대신 리뷰 목록이라는 문구가 나옵니다.
    수정, 삭제 버튼은 나오지 않습니다. 또한 난이도, 알림 날짜를 수정할 수 없습니다.

  • 1차 UI
    1차에서는 로그인 하지 않은 상태에서도 Add Review로 고정되어 있고 수정, 삭제 버튼이 존재했지만,
    지금은 아예 보이지 않도록 변경.

📄 문제 등록


제목을 입력한 후, 엔터키를 누르면 태그 입력 칸으로 이동합니다.

제목 입력 후, 태그 입력하기


전에도 말했듯이.. 넘 맘에 드는 이벤트 처리

  • 1차 UI

📄 리뷰 등록


Add Review 버튼 클릭 시 나오는 페이지입니다.
등록하면 내용을 바로 볼 수 있도록 상세 페이지로 이동합니다.

📄 리뷰 수정

📄 검색

키워드를 검색하면 (엔터키, 등록 버튼 클릭)
문제 이름이나 내용에 포함된 리뷰 리스트들이 조회됩니다.
ezgif com-gif-maker (7)
존재하지 않는 경우 다음과 같은 페이지가 나옵니다.

📄 방명록

ezgif com-gif-maker (8)
로그인 하지 않은 경우 방명록을 등록하면 닉네임이 "익명"으로 등록됩니다.
구글 로그인을 한 경우에는 해당 이름으로 등록됩니다.

"나"로 로그인하지 않은 경우, delete 버튼이 보이지 않습니다.

ezgif com-gif-maker (10)

📄 슬랙 알림

문제 이름을 클릭하면 해당 문제 링크로 이동합니다.
"여기"를 클릭하면 ars 메인 페이지로 이동합니다.

인증 ㅎㅎ

📄 404 페이지

존재하지 않는 url로 접속하였을 때 나타나는 페이지입니다.

✔️ 서버 아키텍처

백엔드 개발자가 되고 싶은 나는 아키텍처를 좀 더 열심히 설계하고자 했다.

  • 최종 서버 아키텍처

1차에선 도커를 적용하지 안했는데, 요번에는 도커로 nginx, 스프링부트 컨테이너를 띄우도록 인프라를 설계했다.
또한 redis cache를 적용하고 싶어서 docker로 redis 컨테이너를 띄워 컨테이너끼리 연결하였다.

도커를 도입해보고 싶기도 했고 또 이유가 있다.
도커를 사용하지 않고 엔진엑스를 사용했을 때, 프리티어인 내 ec2 서버가 먹통돼서 재부팅을 하는 순간 엔진엑스로 돌고 있던 애플리케이션들이 다 멈춰버렸다.

도커로 젠킨스만 띄우고 있었는데, sudo service docker start 요렇게만 명령하니 바로 젠킨스도 작동하였다. (restart 설정 해놨음)
그래서 nginx와 springboot 모두 컨테이너로 실행해 독립적인 환경을 만들어주도록 하고자 했다.
(이때 정말 삽질을 많이 했지만.. 성공했으니 됐다.)

  • 1차 서버 아키텍처

    도커라이징하기 전, 1차 서버 아키텍처이다.

✍️ 프론트엔드 정리

여기에 하루 하루 구현한 것들을 작성해놨다.

거의 백엔드 개발을 해와서, 리액트를 접해보는 경험이 별로 없었다. 그래도 배워보고 싶어서 강의 들으면서 따라해보고 프로젝트에서 짧게짧게 적용해본 정도였다.
계속해서 리액트를 공부해보고 싶었는데, 이번 기회에 리액트를 더 알게돼서 너무 도움이 됐다.

일단 너무 신기했다...
페이지가 아니라 컴포넌트 별로 상태가 바뀌다니.. 신세계였다.
처음에는 페이지를 계속 해서 이동하는 식으로 했는데, 나중에 컴포넌트 별로 상태 관리를 하도록 변경했다.
또한 나는 데이터를 응답할 때 뷰 단위로 해야하나? 어떻게 해야 깔끔한 응답을 할까 고민했는데, 이렇게 비동기식으로 프론트엔드 개발을 해서 따로 요청을 하면 된다는 것을.. 이제야 알았다. 정말 리액트로 개발해보길 잘한 것 같다.

또 엔터키 이벤트 처리도 다 코드로 구현해야하는 걸 이번에 알았다...
이벤트 핸들러 성공할 때마다 기록하고 싶을 정도로 꽤 있었다. ㅋㅋ

깃헙 코드를 보면 아직 많이 부족하겠지만 하나의 프로젝트를 완성한 것만으로도 너무 좋은 경험이었고
프론트엔드 개발도 이렇게 재밌다는 걸 알게 되어서 뿌듯. ㅎㅎ
Antd
Ant 디자인 너무 좋았다. 날짜 상세 설정한다던지, 뷰를 좀 더 이쁘게 하고 싶다던지 ant 를 통해서 모두 적용할 수 있었다. (부트스트랩도 썼다)

난이도 디자인

아 그리고 난이도 보여줄 때 1차에서는 빈 별, 채워진 별 따로 다운 받아서 진짜 보이는 것만 제대로 보여주자 라고 개발했는데 antd 덕분에 코드도 깔끔해지고 딱 내가 원하는 UI가 나올 수 있었다.

  • 1차
  • 완료

ㅎㅎ 더 이뻐졌당.
문제 링크도 위치를 바꿔서 더 깔꼼하게 페이지를 구성했다.

✍️ 백엔드 정리

혼자 프로젝트 하니까 하고 싶었던 기술을 적용해볼 수 있어서 좋았다.
인프라 구축까지 혼자서 해 본 경험은 처음이었다. 특히 도커라이징까지..굳!
서버 한 대로 구축하긴 했지만 그래도 서버는 2대가 있는 게 좋은 것 같다... CI 서버는 따로 두는 게.. 아무리 무중단 배포로 구축한다 했지만 빌드 중에는 서버에 접근을 할 수 없다는.. ^^

도커

도커를 적용할 때 계속 서버가 먹통돼서 껐다 켰다를 반복했다..
2-3일 동안 헤맨 듯하다.
그리고 스크립트 오타까지.. 헤매기 완벽한 조건 ㅎㅎ
예를 들어 $IDLE_PORT$IDEL_PORT라고 작성했다던지.. ㅎㅎ

그래도 스크립트 배포할 때 과정을 다 이해하면서 적용하니까 어디서 막힌 건지 바로 알 수 있었다.

도커를 적용하면서 바뀐 스크립트 내용을 써보겠다.

  • 현재 활성화된 profile 찾기
  • 호스트상에서 스프링부트를 실행하는 경우
    다음은 무중단 배포로 활성화된 profile(dev1, dev2 중 하나)를 찾는 명령문이다.
curl -s http://127.0.0.1/api/profile

이렇게 로컬 호스트로 확인 가능하다.

  • docker 적용 후
    독립된 환경이 된 컨테이너에서 로컬 호스트로 확인할 수 없다.
    그래서 나는 사설 IP 주소로 수정했다. (공인 IP 주소도 되지만, 깃헙상에서 내 IP 주소를 쓰고 싶진 않았다)
curl -s http://172.31.33.165/api/profile

Redis 컨테이너와 연결하기

처음엔 다음과 같이 도커 컴포즈로 컨테이너들을 실행시켰다.

  • docker-compose.yml
version: "3"
services:

  ...    
      
  redis:
    image: redis
    command: redis-server --bind redis --port 6379
    container_name: redis
    hostname: redis
    ports:
      - 6379:6379

  ars1:
    build: .
    ...
    depends_on:
      - redis

  ars2:
    build: .
    ...
    depends_on:
      - redis
      

여기서 docker-compose up을 실행하면
host를 redis로 하여

  redis:
    host: redis
    port: 6379

연결이 된다.
하지만 나는 무중단 배포를 위해 스크립트로 스프링부트 컨테이너를 멈추고 지웠다가 다시 실행해야 한다.
그렇다면 docker-compose up에서 실행됐던 컨테이너와 완전히 따로 놀게 되어 redis 컨테이너와 연결이 끊어진다.

그래서 나는 docker-compose.yml과 스크립트를 모두 변경했다.

  • docker-compose.yml
version: "3"
services:

  ...  
  
  redis:
    image: redis
    command: redis-server --bind redis --port 6379
    container_name: redis
    hostname: redis
    ports:
      - 6379:6379
    networks:
      - backend

networks:
  backend:
    driver: bridge

이렇게 스프링부트 컨테이너들을 여기서 실행시키지 않고, redis 컨테이너와 연결할 수 있는 네트워크를 추가하였다.

그 후 스프링부트 컨테이너 실행하는 명령을 이렇게 하면 된다.

docker run -it --name $IDLE_PROFILE --network=deploy_backend -d -e active=$IDLE_PROFILE -p $IDLE_PORT:$IDLE_PORT ars

network=deploy_backend 설정을 추가하면 된다.

전체 스크립트 내용은 생략하겠다. 따로 포스팅을 한다면 링크 걸어두겠다.

Redis Cache

내 페이지들을 보면 cache를 적용할 곳이 많다. 특히 메인 페이지는 캐시를 이용하면 더 빠르게 데이터를 얻을 수 있다고 생각해서 캐시를 적용했다.

전체 태그 리스트는 캐시를 적용했는데, 아직 문제 리스트는 캐시를 적용하지 않았다.
(추가할 예정)

Paging

페이징 처리는 꼭 해보고 싶었다. 프론트엔드에서도, 백엔드에서도 어떻게 구현하는지 알고자 했다.
PageRequest를 이용하니까 적용하기는 꽤 쉬웠다.
처음에 검색 결과도 페이징 처리로 했는데, 이건 페이징 처리로 하기에는 UI가 이쁘지 않았다. 그래서 일단 페이징 처리를 빼놨다.
벨로그처럼 스크롤을 하면 추가적으로 데이터를 얻게끔 구현하고 싶은데, 이건 프론트엔드에서 먼저 적용해보고 백엔드를 구현하려고 한다.

  • https 주의 요함

ec2 웹서버에 접속하든, vercel에 접속하든 계속해서 위의 사진의 결과가 나왔다. 원래 개인 서버에는 이런 건가..? 했는데 아니었다.

ACM의 설정으로 들어가서 인증서를 편집해야 한다.
기존에는 도메인 이름을 *.example.com 이런 식으로 설정하여 인증서를 생성했는데, example.com로 설정해서 인증서로 새로 만들어서 설정하니 해결되었다.

자세한 설명

와일드카드 이름()을 사용하는 경우 와일드카드는 하나의 하위 도메인 수준에만 일치합니다. 예를 들어, .example.com은 login.example.com 및 test.example.com을 보호할 수 있지만, 와일드카드는 test.login.example.com 또는 example.com을 보호할 수 없습니다. example.com 및 www.example.com으로 웹 사이트에 액세스할 수 있는 경우 인증서에 여러 도메인 이름을 포함하여 웹 사이트의 가능한 다른 도메인 및 하위 도메인 이름을 포함할 수 있습니다.

그럼 해결!

  • 슬랙 알림
    슬랙 API를 호출하여 기능을 구현했다.
    알림 내용에 링크를 어떻게 삽입하는지 엄청난 구글링을 하다가 공식 문서에서 발견했던 기억이 난다. 항상 공식 문서를 먼저 찾아보는 걸 습관으로 들여야지.
    링크 삽입 관련한 공식 문서

며칠 전에도 오전 9시에 딱! 슬랙 알림와서 복습을 했다. ㅎㅎ
ARS 짱~

Querydsl

  • 태그

    이렇게 태그이름(글개수) 리스트를 조회해야 하는데, 어떻게 가져와야할지 많은 고민을 했다가 Querydsl을 적용했는데 너무 간단하게 가져올 수 있어서 놀랐다.
.groupBy(problemTag.tag)
.select(problemTag.tag.tagName, problemTag.tag.count())

이런 식으로 조회하면 된다.

  • 검색
.where(review.content.containsIgnoreCase(keyword).or(review.problem.title.containsIgnoreCase(keyword)))
.orderBy(review.problem.createdDate.desc())

객체지향 쿼리라는 것을 아니까 신세계였다..
Querydsl 더 깊이 공부해봐야겠다!

테스트 코드

아직 주석처리한 테스트 코드는 남아있지만, 1차에서 몇 개 실패한 테스트 코드를 많이 수정해서 테스트를 통과시켰다.
이번 개발을 하면서 테스트 코드의 중요성을 더욱 더 깨닫게 되었던,,
미리 테스트 코드를 작성했다면 고쳐야할 부분이 제대로 고쳐졌는지 바로 확인도 가능하고, 맞게 코드가 작성된건지 내 코드를 신뢰할 수 있는 것 같다.

테스트 코드는 연습하면서 계속 추가하려고 한다.
또 테스트 코드 작성해서 spring rest docs로 api 문서화를 해보는 건 추가적으로 해볼까 생각 중이다. redis cache 적용도 할 수 있는 건 추가로 해보고?

✍️ 전체 후기

내가 원하는 의도대로 모두 구현되어서 뿌듯하다. 적용해보고 싶은 기술들을 다 적용할 수 있어서 좋았다.

다만 다른 사람들까지 작성하는 서비스였다면,, 누군가는 쓰시지 않을까?!? 하는 생각ㅎ 나한텐 너무 만족스러운 서비스라..ㅎㅎ
사실 그런 식으로 개발을 구현할 수 있긴 하다. 하지만.. 또 이 프로젝트에 너무 많은 힘을 쓸까봐 여기서 마치려구 한다.

쨋든! 많은 기술을 공부할 수 있어서 좋았고, 나는 계속해서 이 서비스를 이용할 것 같다. 하다가 불편하면 refresh token 적용해야겠다!

많이들 놀러와서 방명록 작성해주면..// 감사하겠습니당

깃허브 링크도 적어놔야겠다 ㅎㅎ~

🔗 링크

profile
로그를 남기자 〰️

2개의 댓글

comment-user-thumbnail
2021년 8월 29일

와 너무 좋은데요? 다른 사람들도 같이 쓸수있으면 커뮤니티로 발전되면 엄청 유용할것같아요

1개의 답글