공지사항 알려주는 고양이, 웹캣😺 개발기

Siwon Yoo·2022년 11월 11일
7

웹캣😺

목록 보기
3/3
post-thumbnail

🐈 서론

써야지 써야지 하던 포스트를 드디어 쓴다.
요즈음 정말정말 바쁜 하루를 보내고 있다. 정말 오랜만의 대면 학기 수업에도, 하고 싶은 것들에도 같이 집중하려니 시간이 많이 부족하지만 최선을 다하고 있다😁

웹캣은 바로 밑 스크린샷처럼 서강대학교 웹페이지의 공지사항 변화를 포착해 슬랙 채널로 메시지를 보내주는 고양이다.

새로운 공지사항이 올라오면 1분 안에 알려주고, 무료이다 😀

현재는 지인 대상으로만 일반공지 / 학사공지 / 장학공지 / 컴퓨터공학과 주요공지 / 컴퓨터공학과 취업-인턴십공지 다섯 개의 채널만 운영하고 있지만,

타 과 공지 게시판, 취업 관련 플랫폼, 공모전 관련 플랫폼 등의 공지도 긁어 동문 학우들을 대상으로 서비스할 예정이다.
가까운 미래에 채널이 20개 이상으로 늘어날 것 같다.
500명은 쓰지 않을까?

이미 기능 구현 및 테스트가 상당 부분 완료되어 소요가 크지 않을 것으로 생각된다.😉

🐾 왜 만들었어?

필요해서 만들었다!
내가 쓰려고, 또 주변 사람들도 쓰게 해주려고!

우리 학교 공지사항은 일반공지/학사공지/장학공지/각 학과별 공지(주요공지, 취업/인턴십공지)/교환학생 관련 공지 등 필요로 하는 공지들이 모두 다른 페이지에 분산되어 있었고, 수시로 들어가서 확인해야 하는 구조로 이루어져 있다.

거기다 필요에 따라 회사별 인턴 채용 공고나, 프로그래머스 챌린지 등 정말 다양한 사이트들을 돌아다니면서 공지를 확인할 일이 많았다.

페이지들을 하나씩 들어가서 들여다 보는 일은, 특히 매일 하는 것은 생각보다 많은 노력과 의지가 필요한 일이다. 또 선착순 마감되는 류의 공지는 빠르게 확인해야 하는데, 하루에 저 페이지들을 수십 번씩 들어가 볼 수도 없는 노릇이었다.

Visualping같은 웹 모니터링 서비스도 많았지만, 실시간 모니터링을 위해서는 유료 결제가 필요했고, 무엇보다 하루에도 십수 개의 공지사항이 올라오는데 이메일로 모두 받아보고 싶지 않았다.

주변에 나와 같은 니즈를 갖고 있는 사람들이 많이 있어, 개발을 결심하게 되었다.
그리고 중간고사 시험 종료까지 두 과목을 남기고 공부가 너무 하기 싫어 개발에 착수했다ㅋㅋㅋ

🐾왜 슬랙인데?

처음에는 누구나 쓰는 카카오톡으로 메시지를 발송해 주는 서비스를 구상했으나,

  1. 카카오 알림톡은 사업자등록이 필수였고,
  2. 각 공지 채널별 관리도 용이하지 않았고,
  3. 무엇보다 유료였다. (알림톡 건당 8원 정도)

슬랙을 사용하면

  1. 무료이고,
  2. 채널별 관리가 용이하고 (필요 없는 채널은 알림 끄거나 나가기 가능)
  3. 워크스페이스에 앱 추가나 API 관리도 잘 되고 있어서,
  4. 또 요새 사람들이 많이들 슬랙을 이용해본 경험이 있어 진입장벽이 낮을 것 같아서

슬랙으로 고르게 되었다.ㅎㅎ

🐈 어떻게 만들었어?

🐾 웹캣의 아키텍처

아주 단순하게 돌아가는 웹캣의 동작 환경을 소개한다.

AWS EC2 인스턴스를 하나 띄웠고, Linux 기본 스케쥴러인 Cron 데몬이 서버에서 Selenium with Python을 동작시킨다. 셀레니움이 headless 크롬 웹드라이버를 띄워 페이지를 스크래핑해 오면, beautifulsoup로 파싱한다. 데이터베이스서버에 저장된 텍스트 파일을 활용한다.

웹 페이지별 공지사항만 저장하면 되어서, 따로 DBMS를 사용하지 않고 아래와 같이 파일 하나 당 웹페이지 하나에 대한 공지들을 저장했다. (35개 공지, URI를 포함해 70줄 정도 된다)

구현한 알고리즘이 동작하며 셀레니움이 긁어 온 공지와 저장된 공지를 비교하며 변화를 감지하고, 변화 감지 시 Slack API로 각 채널에 메시지를 전송한다.

Selenium을 사용한 이유는 곧 채용 플랫폼 / 공모전 플랫폼 / 각 회사별 채용 페이지 등도 서비스할 생각이기 때문이다.
학교 페이지들은 모두 SSR형식으로 되어 있어 셀레니움까지 활용할 필요는 없었지만, 다양한 플랫폼들은 SPA 형식인 경우가 많아 동적 크롤링이 필요했다.

크롬 웹드라이버를 사용한 이유는 학교 페이지를 포함한 많은 서비스들이 크롬 기반으로 관리되고 있었기 때문이다.

EC2 인스턴스의 운영체제는.. 별 생각 없이 기본값으로 띄우다가 Amazon Linux가 되었다. 관련해서 할 말이 정말 많은데, 마주친 이슈들에 대해 다룰 다음 포스트에서 이야기하겠다. 우분투 최고

🐾 웹캣의 알고리즘

스케줄러에 의해 매 분마다 수행되는, 웹캣이 공지를 읽어온 후 저장 중인 기존 공지와 비교해 변화를 감지하는 알고리즘을 소개한다.

v01부터 v03까지 가장 처음 형태에서 두 번 알고리즘을 수정했고, 현재는 v03이 적용되어 있다.

v01


처음에는 아주 단순한 형태로, 공지 게시판의 가장 위 공지만 읽어 왔고, 저장해 두었고, 비교했다.

서강대 컴퓨터공학과 홈페이지 기준 매번 최신 공지는 게시판의 가장 위에 추가되고, 우리 과 홈페이지 기준으로 동작에 아무 이상이 없었다.

서강대 컴퓨터공학과 주요공지

일반공지/학사공지/장학공지도 모두 같은 형식으로 구성되어 있었는데, 새 주요공지가 추가되면 가장 위에 추가되었다. 그런 줄 알았다.

서강대 일반공지

그런데 알고 보니, TOP 공지가 아닌 공지(나한테는 안중요한 공지)가 추가될 때는 같은 게시판의 중간에 추가되었고..

안중요한 공지인 줄 알아서 별로 관심이 없었는데, 실제로 이 공지도 놓치지 않고 싶어하는 사람들이 꽤 있는 것을 현실에서 확인하게 된다.

v02


그렇게 v01에서의 문제점을 개선하고자 고안한 알고리즘이다.

쉽게 가는 방법으로는 새로 읽어온 모든 공지들을 하나하나 기존 공지들과 비교하는 방법이 있었으나, 현재 알고리즘 설계와 분석 과목을 듣고 있는 나는 O(n^2) 알고리즘을 참을 수 없었다.

위 그림처럼 새로 읽어온 공지기존 저장된 공지를 순서대로 내려가면서 비교한다. 마치 Merge Sort에서 2개의 정렬된 배열에서 원소들을 순서대로 진행하며 비교해 하나의 정렬된 배열으로 합치는 것처럼 말이다.

왼쪽 공지(새로 읽어온 공지)와 오른쪽 공지(기존 저장하고 있던 공지)를 순서대로 동시에 읽어 내려가다가, 다른 항목이 발견되면, 오른쪽 리스트에서는 그대로 두고 왼쪽 리스트의 포인터(비교점, 커서..whatever)만 한 칸 내린다. 같으면 양쪽 포인터를 같이 한 칸씩 내린다.
새 공지는 기존 공지 위에 추가되기 때문에, 기존에 있던 공지는 왼쪽 리스트에서는 한 칸 다음 순서에 존재하고, 오른쪽 리스트에서는 기존 순서에 존재하기 때문이다.

왼쪽 리스트에서의 공지가 오른쪽 리스트에서의 공지와 다르면 새 공지가 추가된 것이므로, 메시지를 전송한다.

O(n)의 linear 시간복잡도를 갖는 완벽하고 아름다운 알고리즘이다..
라고 생각했다.
수업 중 테스트용 채널에서 갑자기 30개가량의 알림이 동시에 울려 깜짝 놀라기 전까지만 그렇게 생각했다.

애플워치가 손목에서 한참 울었다.
나도 울었다.

왜인고 하니..
v02 알고리즘은, 새 공지가 추가되는 경우에 한해서는 완벽하게 잘 동작한다. 하지만 공지사항은, 때로는 수정되거나, 때로는 삭제되기도 하며, 순서가 바뀔 수도 있다. 위에서의 TOP 공지와 TOP이 아닌 공지 스크린샷이 있었는데, TOP 뱃지가 달려 있다가 떼어지면 공지사항이 같은 페이지에서 아래쪽으로 이동하기도 했다.

공지사항 제목이 수정되거나 (가령 마감 표시 등이 붙어서), 공지 순서가 바뀌거나, 공지가 삭제되면 v02 알고리즘에서는

기존 저장된 공지사항 리스트를 읽어 내려가다가 변화가 발생한 공지 순서에 있던 공지(수정이건 삭제건 이동이건)를 새로운 공지로 인식했고,
아까 그림에서 왼쪽 리스트의 포인터만 한 칸 내렸기 때문에(새 공지로 인식해서)
공지 순서를 하나 삐끗한 상태로 비교하게 되어
기존 공지들도 다 새로운 공지로 인식했다. 😥


내 완벽했던 계획에 차질이..

v03

그렇게 개선한 현재의 알고리즘은, 아래와 같다.
공지들이 자유롭게 수정, 삭제, 이동되는 경우에서는 모든 공지들을 하나하나 비교하지 않고는 결국 완벽하게 변화를 감지할 수 없다.

결국 모두 비교하는 알고리즘을 적용했는데, 공지가 매 순간 변경되지 않는 특성을 고려해, 공지에 변경이 있는 경우에만 모든 공지를 상호 비교하도록 했다.

하나의 공지사항만 수정된 경우에도, 공지의 순서가 이동한 경우에도 정확하게 변경된 공지만 확인할 수 있다.

매 분 같은 작업을 수행하는데, 99% 이상의 경우에는 공지사항에 변화가 없기 때문에 average case에서 여전히 O(n)의 시간복잡도를 갖는다.😊

🐈 간단한 후기

처음 생각할 땐 정말 쉽게 뚝딱 만들 수 있을 줄 알았는데, 역시나 이번에도 처음 생각과는 달랐다.

정말 많은 이슈들을 만났고
(주로 인프라 리눅스에서 도는 셀레니움 관련 이슈들이고, 다음 포스트에서 소개 예정이다),
어떻게 알고리즘을 구성할지도 고민을 많이 하게 되더라😁

이왕 만드는 거 단 하나의 공지도 놓치지 않고, 공지 제목이 수정되는 사소한 경우도 감지하면서 빠르게 감지하고, CPU 리소스도 효율적으로 쓰면서 사용자 경험도 깔끔하게 만들고 싶었다.

완성도를 높이고 싶은 욕심이 점점 생겨 예정보다 오래 걸렸지만, 과정 속에서 느끼고 배우는 것도 정말 많았다.

개발자라서 행복하다😎
얼른 많은 학우들이 기뻐하면서 썼으면 좋겠다!

profile
세상은 넓고 배울 건 언제나 많다😃

5개의 댓글

comment-user-thumbnail
2023년 1월 2일

헉 아이디어가 너무 좋네요!! 저희 학교도 이런 게 있었으면 좋겠습ㄴㅣ다 XD 글 잘 보고 가요~!!

1개의 답글
comment-user-thumbnail
2023년 4월 13일

웹켓 아버님...다음에 만나면 고양이 간식비 대신 아버님 식사비 내드릴게요..!

1개의 답글