2024. 9. 30. 03:28ㆍBackend
서론
글또 4년 차면 글을 쓰는 것뿐만 아니라 좋은 글을 찾아 읽는 것도 즐기게 된다. 여러 회사의 테크 블로그를 자주 챙겨 읽는데 매번 업데이트가 되는지, 안되는지 알 수 없으니 직접 페이지를 방문하는 수밖에 없었다. 카카오페이 같은 경우는 감사하게도 새로운 글이 올라올 때마다 링크드인에 노티를 주지만 그렇다고 모든 회사를 팔로우 할 순 없는 노릇이었다.
해결해야 할 문제가 얼마나 고통스러운지, 이걸 해결하면 얼마나 많은 사람들이 편안해지는 지에 따라 문제의 중요성을 파악하곤 하는데, 냉정하게 말해서 직접 블로그를 방문하여 새로운 글을 확인하는 게 그리 고통스러운 일은 아니다. 단지 조금 귀찮았을 뿐.. 그래서 나도 아주 약간의 노력만 들여 이 문제를 조금 편하게 만들어보자는 마음에 🔗 테크 블로그 모아보기 서비스를 개발하게 됐다.
백엔드
서버는 Go 와 Gin 프레임워크로 개발했다. Go를 이용한 웹 스크래퍼 만드는 강의를 잠깐 들었는데, 강의에선 구직 시장 페이지를 대상으로 한 웹 스크래핑을 보여줬다. 내가 아는 스크래핑은 파이썬 selenium을 사용하는 게 전부였는데, Go와 Goquery를 이용한 스크래핑은 파이썬 대비 비교도 안될 만큼 놀라운 성능을 보여줬다. 이 점이 Go로 웹 스크래퍼를 만들어봐야겠다는 첫 동기부여가 됐다. (파이썬 비하 의도는 전혀 없다.. 아이 러브 파이썬!)
실제로 스크래핑할 블로그가 늘어나면서 동기식, 순차적으로 블로그를 차례로 스크래핑하는 API는 시간이 상당히 오래 걸렸다. 하나의 블로그를 스크래핑할 때도 페이지의 수만큼 호출해야 하는 API 가 늘어나기 때문에 이를 동기식으로 호출하는 건 개선이 필요하다고 생각했다. 무엇보다 내가 사용하는 언어가 무엇인가, 무려 Golang 아니겠는가. 빠르다고 소문난 Goroutine의 성능을 실제로 경험해 볼 수 있는 기회라 생각했고, 동기식으로 호출하던 모든 API를 고루틴에 태워버려 비약적인 속도 개선을 이룰 수 있었다. 이에 대한 내용은 별도 블로그에 첨부한다.
스크래핑 코드를 짜는게 살짝 귀찮긴 했다. 수집할 블로그가 늘어나면서 스크래퍼 패키지를 회사마다 만들 수 밖에 없었는데, 오히려 medium 처럼 공통된 플랫폼을 사용하는 회사의 블로그는 공통된 html 구조를 가지고 있어 수월하게 스크래핑 할 수 있었다. (샤라웃 투 당근, 무신사, 29cm 레쓰고)
현재는 12개 정도의 회사를 스크래핑하기에, 12개의 패키지를 만들었다. 회사마다 html 구조가 다르니 어쩔 수 없다고 생각하는데 이를 기술적으로 풀 수 있는 방법은 없을지 더 고민해봐야겠다. 만약 스크래핑할 회사가 50개 정도로 늘어나면..? 50개의 서로 다른 패키지를 관리하는게 더 힘들 것 같다... RSS 라는 것을 사용하면 HTML 구조에 상관없이 업데이트가 가능하다고 하는데, RSS 를 적용할 수 있을지 좀 더 조사가 필요할 것 같다.
DB 선정
우선 여러 테크 블로그의 HTML 형식에 맞는 스크래퍼를 만들고, 스크래핑한 결과를 구조체에 담는다 (구조체는 Java 의 DTO, DAO 정도로 생각할 수 있다.) 구조체를 배열에 담고 이를 DB에 저장하는 아주 단순한 흐름이다. DB를 선정하는 과정에서 고려한 점은 스키마의 유연성인데, 아무래도 각 회사마다 보여줄 수 있는 데이터가 다르다고 생각하여 RDB 보단 Nosql 쪽으로 방향이 기울었다. 무엇보다 점진적으로 검색 기능도 추가하고 싶었는데, mysql의 전문검색 보단 mongoDB의 text 검색이나 elasticSearch 같은 검색 엔진이 적합할 것이라 생각해서 우선 mongoDB 를 선택했다. 그리하여 현재는 블로그 제목 필드에만 인덱싱을 걸어 빠른 속도로 검색이 가능하게 했다. 다음 단계에서는 블로그 전문을 인덱싱하여 검색할 수 있도록 만들 예정인데, 저장하는 블로그의 수가 점차 늘어나다 보니 mongoDB의 검색 성능으로는 한계가 있을 거란 우려가 생겨 elasticSearch 도입도 고려 중이다.
프론트엔드
Typescript + React + Next.js로 앞단을 구축하고 Claude의 도움을 받아 UI를 어떻게든 그렸다.
프론트엔드 개발은 첫 직장에서 리액트를 사용해본게 전부였고, 그 사이엔 프론트엔드 개발의 트렌드는 CRA에서 Next.js로 많이 넘어왔다고 느꼈다. 강의를 통해 Next.js를 찍먹할 수 있었는데 서버 사이드 렌더링 방식이 초기 로딩 속도를 개선하면서 사용성이 나아진걸 체감할 수 있었고, SEO 측면이나 API 호출 성능 개선면에서도 만족스러웠기 때문에 이번 프로젝트에서도 Next.js 를 사용하기로 했다. vercel을 이용해서 serverless 배포를 무료로 할 수 있다는 점도 선택한 이유 중 하나였다. 초기 버전의 UI는 그저 블로그를 리스팅 하는데 그쳤는데, 검색 기능도 추가되면 좋겠다는 생각에 search input 컴포넌트를 추가했다. 당연히 서버도 mongoDB 에서 Title을 쿼리 할 수 있도록 개선했다.
디자인
처음 설계한 디자인은 너무 구렸다. (구려서 스크린샷도 안찍은듯 ㅇㅅㅇ) 이건 나도 안 쓸 것 같단 생각에 다른 기술 블로그를 레퍼런스 삼아 많이 찾아다녔다. 그중 오늘의 집 테크 블로그의 톤 앤 매너가 마음에 들었고 이를 기반으로 UI를 재편했다. 이 역시 Claude의 도움을 받았는데 오늘의집 기술 블로그 화면을 스크린샷 떠서 Claude 에 붙여넣고 이를 기반으로 HTML 과 CSS 를 next.js 에서 활용할 수 있는 형태로 만들어달라 했다. 그 이후 부턴 복붙과 짜집기의 연속이었고 나름 만족할 만한 깔끔한 UI 를 얻을 수 있었다. 사실 진짜 디자이너 분들의 시선에선 🐸다는 말이 나올 수 있겠지만,,, 그렇지만 난 귀여운 백엔드 개발자인걸?! 디자인은 딱 Claude 수준의 결과물만 차용하는데 만족했다.
배포
앞에서도 말했지만 처음엔 혼자 사용할 용도로 만들었기에 배포는 생각도 하지 않았다.
그래서 처음 형태는 local에서 모든 서버가(mongo 든, golang 이든) 통신하는 형태였다. 하지만 배포하기로 마음먹은 순간부터 드는 생각은 비용이었다. 어림잡아도 최소 1대의 서버는 돌려야 했다. 프론트엔드야 vercel로 무료 배포 할 수 있단 점이 다행이었지만, 백엔드는? ec2 내부에 docker-compose로 go 서버와 mongo 서버를 모두 돌리면, 당연히 위험하겠지만 비용은 아낄 수 있지 않을까. 내키진 않았지만 비용을 아끼려면 그 방법이 적합하다고 생각한 찰나에 작년 GopherCon에서 수빈님이 aws lambda로 go 애플리케이션을 배포한 내용이 불현듯 떠올랐다. 기본적으로 Lambda는 호출한 횟수만큼 과금되기 때문에 ec2처럼 띄워놓기만 해서 돈만 먹는 하마가 아니었다. 사이드 프로젝트 특성상 호출 횟수가 그리 크지 않을 것이라 예상했기 때문에 go 서버는 aws lambda로 배포하기로 결정했다. 그렇다면 mongoDB 는 어떡할 것인가? 이 역시 은혜로운 Atlas 사에서 프리티어로 제공하는 mongo cluster를 활용하기로 했다. 결국 총 3개의 서버를 모두 서버리스한 형태로 배포할 수 있게 됐다. 많은 사람들이 내 서비스를 사용해서 lambda 호출 횟수를 터뜨려주길 바라는 마음과 (거의) 공짜로 배포할 수 있어서 다행이라는 양립적인 마음이 동시에 들었다.
피드백
감사하게도 많은 분들이 피드백을 주셨다.
사실 RSS는 이번 피드백을 통해 처음 알게 됐다. 현재 개발 방식은 모든 HTML의 구조를 파악하여 파싱하는 방식인데 RSS가 가능한 블로그는 별도로 처리하도로 개선해봐야겠다.
실제로 프론트 쪽 부분은 지훈이가 PR을 남겨줘서 UX 측면에서 훨씬 개선됐다. 이 자리를 빌려 고마움을 표한다🫶🏻
마무리와 앞으로는
이 프로젝트로 수익화는 전혀 생각없고 (애초에 다른 회사 블로그 긁어모아놨으면서 돈 벌겠다는 건 좀..) 그저 사람들이 꾸준히 찾는 서비스가 되도록 계속 개선하고 싶다.
그리고 이미 유사한 서비스가 존재한다. 이미 잘 만들어진 서비스가 있지만, 그래도 내가 직접 만들어보는건 다르니까 개발하기로 했다. 확실히 직접 개발하면서 겪은 다양한 에러와 트러블 슈팅을 거치면서 역시 해보길 잘했다고 생각했다. 배포없이 나만 사용하는 서비스로 남겨두려했지만 지금 생각해보면 배포하길 백번 잘한 것 같다. 500 뜰까봐 조마조마하면서 모니터링도 하게 되고, 어떻게 개선할지, 어떤 기능을 추가할지 지속적으로 고민하게 된다. 고민이 깊어지면서 어떻게 문제를 해결할지 생각하는 자세도 깊어지는 걸 어렴풋이 느꼈다.
아직은 너무 초기 단계의 서비스라 감상적인 회고를 남기기엔 이른 것 같다. 블로그 본문 검색 기능이 꽤 도전적일 것 같은데, 그것부터 해결하고 감상에 빠지기로 하자.