요즘 바이브코딩에 대한 말이 많죠? 말만 하면 뭐든 만들어준다는 만들어준다는 바로 그거요.
저도 똑같이 관심이 많습니다. 얘가 정말 저만큼 일을 잘하면 저는 굶어야 하니까요.
그런데 여러 웹사이트, 그리고 유튜브 영상들을 보면서 의심이 하나 생깁니다. 아주 간단한 랜딩 페이지 이상 뭔가를 만들어내지 못하는 것 같은 거에요. 기껏해야 블로그, 테트리스, 타이머 같은 것만 모두들 만들어내고 있더군요.
한정된 시간에 소개를 해야 하는 튜토리얼이기 때문에 그런지, 아니면 비즈니스 로직이 들어가야 하는 걸 못만드는 건지 헷깔리기 시작했습니다.
그래서 저는 직접 검증해 보기로 했습니다. 모두에게 알려진 흔한 로직 말고 제가 생각한 로직을 하나씩 설명하면 바이브코딩 툴이 정말 쓸만한 결과를 낼 수 있을까?
Awesome Devblog(어썸 데브블로그)라는 github repo가 있습니다. 우준혁님께서 시작하신 프로젝트로 공식 설명에 따르면 국내 개발자 블로그 모음 입니다.
RSS도 등록할 수 있게 되어 있는지라, 여기서 아이디어를 얻어 수많은 형제자매 프로젝트들도 나왔어요. 주로 RSS 글을 읽어서 목록을 보여주는 거죠. 즉, RSS 리더기 같은 겁니다.
사실 RSS 리더기는 뭔가 복잡한 로직이 들어가거나 하는 건 아닙니다. 그저 데이터를 수집하고, 쌓아두고, 보여주기만 하면 됩니다. 그래도 바이브코딩 툴이 이정도를 만들 수 있다면, 대단한데.. 라고 인정해 줄 생각입니다.
가장 먼저 할 일은 어떤 바이브코딩 툴을 쓸 것인가였습니다. 커서나 윈드서프, 코파일럿 같은 제품은 애시당초 로컬에서 동작하기 때문에 고려 대상이 아니었습니다. 브라우저로 접속해서 대화형 인터페이스와 미리보기를 지원하는 플랫폼 중에 골라야 했죠.
후보군은 다음과 같았습니다.
이 외에도 여러 플랫폼들이 있겠지만, 대략 이정도면 충분할 거라고 생각했어요. 국내외 후기를 찾아본 결과 특별히 더 나은 기능을 제공하는 플랫폼은 없어보였거든요.
그래서 하나씩 시도해 보기로 합니다. 그리고 하나씩 소거해 나갑니다.
먼저 V0, bolt.new, replit은 보류입니다. 특별히 기능이 부족하다거나 뭔가 문제가 있는 것은 아니었습니다. 그냥 가입할 때 주는 무료 크레딧이 너무 빨리 떨어졌어요.;; 프롬프트를 3~4개 입력하고 나니까 결제하라고 나오더라고요.
테스트하겠다고 모든 플랫폼을 다 결제하기에는 너무 가난한 저여서, 일단 보류해 둡니다.
다음으로 탈락한 건 파이어베이스 스튜디오였습니다.
firebase studio는 돈 내라는 말은 안합니다만, 성능이 너무 엉망이어서 이건 아직 쓸 물건이 아니겠다 싶었습니다. gemini가 내장되어 있는데 구글 ai 스튜디오에서 나오는 결과만도 못한 응답, 이름은 파이어베이스 스튜디오인데 정작 파이어베이스 연동은 수동으로 해야 하는 번거로움 등이 겹쳐서 아직은 미비하다는 판단을 내립니다.
물론 구글답게 시작은 미비하였으나 나중에는 결국 모든 것을 이기리라는 확신은 있었습니다만, 그것이 지금은 아닌 것 같았습니다.
결국 남은 건 lovable 하나였습니다. lovable은 무료 요금제의 경우 일정량의 크레딧을 주는 것이 아니라 하루에 5건의 메시지, 한달 최대 30개의 메시지를 보낼 수 있게 되어 있습니다. 그래서 저는 lovable로 개발하기로 하고, 프로젝트를 시작합니다.
먼저 말씀드릴 것은, 저는 이런 웹 기반 바이브코딩 툴을 처음 써 본다는 겁니다. 따라서 바이브코딩에 최적화된 프롬프트 작성법이라거나, 효율적으로 바이브코딩을 잘 하는 법 같은 건 전혀 모른 상태에서 시작했습니다. 아마 저처럼 처음으로 바이브코딩에 입문하신 분들 대부분이 비슷하실 것이라 생각해요.
제가 여러가지 삽질을 하면서 느꼈던 점을 천천히 기술하는 형식으로 말씀드리니, 완벽한 가이드를 원하시는 분이시라면 죄송하지만 다른 아티클을 찾아주시면 감사하겠습니다.
다만 저는 개발을 꽤 오래 했습니다. 약 18년정도 되었네요. 그러니까 기술적인 베이스는 아주 조금은 가지고 있다는 것을 전제하시고 읽어주세요.
무턱대고 그냥 제가 필요한 기능을 말했습니다. LLM에다가 기획서를 정리해 줘 이런 과정도 없었어요.
이 질문은 github에 있는 rss 주소를 읽어서 저장하는 API 하나와 rss 주소당 글을 수집하는 API 하나를 만들고, 이를 통합해서 사이트를 하나 만들어달라는 요청입니다. 어디서 본 건 있어가지고 자세히 말하면 잘 만들어준다길래 열심히 적어봤어요.
지금 다시 읽어보니 일반적인 바이브코딩 튜토리얼하고 좀 다른 것 같기는 하네요. 일반적인 바이브코딩은 "ㅇㅇ 사이트 만들어줘." 처럼 UI를 명시하는 방식으로 시작하던데, 전 그렇지 않았었군요.
저는 개발자이기 때문에 머리속으로 한가지 기능을 만들어내기 위해 어떤 절차를 따라야 하는지 각 태스크를 분리하는 것이 익숙합니다. 그래서 이런 식으로 진행한 것 같습니다. 만약 이런 훈련이 되어있지 않은 분들이라면 챗GPT같은 LLM에 만들 기능을 나열하고 개별 태스크를 쪼개는 것도 방법이겠다 싶은 생각이 듭니다.
여하튼 저렇게 요청을 하고 나니, 러버블이 뭔가 답을 줬습니다. 영어로 써 있어서 무슨 뜻인지는 잘 모릅니다.
일단 뭐라고 하는지는 모르겠고, 수파베이스에 연결하라는 버튼이 보입니다.
전 이때까지 수파베이스가 뭔지도 몰랐습니다. 그래서 찾아봤죠. 클라우드 DBMS 비슷한 거더군요. postgresql 기반의 파이어베이스 같은 거였습니다. 자세히는 안 알아봤고, 그냥 데이터베이스가 러버블 내장이 아니라 수파베이스 기반으로 연동하는구나 정도만 이해했습니다.
어쨌든 데이터베이스는 필요하므로 시키는 대로 버튼을 눌렀습니다.
수파베이스 사이트가 새 탭에 뜨길래 회원가입하고, 로그인하고, 연동 인증을 했습니다. 그랬더니 러버블이 연동을 완료했다고 알려주더군요.
오. 훌륭해. 혼자 감탄하면서 수파베이스 메뉴를 뒤져봅니다. 테이블 에디터가 있습니다. 확인합니다. 텅 비어 있습니다. 훌륭하지 않아..라고 되뇌이며 러버블에게 물어봅니다.
여태까지 영어로 대답하다가 갑자기 한글로 대답합니다.
안만들었다고 하네요. 잘못 본게 아니었습니다. 뭔가 잔뜩 쿼리를 쓰더니 쿼리 실행을 승인해 달라고 합니다. 승인을 안 하면 진행할 수가 없으므로 승인합니다.
그랬더니 갑자기 코드를 구현하기 시작합니다. 처음 질문한 컨텍스트를 잊어버리지 않은 것 같습니다.
뭔가를 구현했다고 합니다. 어라? Supabase Edge Function을 만들었다고 하네요. 아무래도 러버블은 백엔드를 스스로의 서버에 구현하는 게 아니라 수파베이스에 의존하는 것 같습니다. 어차피 바이브코딩을 하는 입장에서는 어디에 구현되었는지는 그다지 중요하지 않다고 판단하고 그냥 진행합니다. 돌아가긴 너무 늦었어...
Supabase Edge Function이 뭔지는 몰랐지만, 그냥 AWS Lambda 같은 거겠거니 하고 넘어갑니다.
혼자 코드를 막 만들더니 혼자 버그를 만들었습니다. 다 구현했다고 하더니 거짓말이었나봅니다.
하지만 걱정 없습니다. 빌드가 실패하면 Fix It 버튼이 나오거든요. 누르면 알아서 버그를 수정하기 시작합니다. 코드를 만들고 버그도 만들고 디버깅도 하는 거 보니 어쩐지 동질감까지 느껴집니다. 여하튼 뭔가 막 생각을 하더니 여기가 버그가 있었다며 수정했다고 합니다.
다행스럽게도 러버블은 빌드 실패시 수정하는 것은 포인트를 차감하지 않습니다. 이것마저 포인트를 차감했다면 양심도 없는 플랫폼이라며 욕했을 꺼에요. 일부러 자기가 버그를 만들고 계속 fix it을 시켜서 포인트만 차감한다고 음모론을 펼쳤겠죠.
Code를 눌러보면 수정한 코드도 보여줍니다.
대충 읽어보니 ... 모르겠습니다. 전 타입스크립트는 할 줄 몰라요. 상관없습니다. 저는 이 실험에서 코드는 단 한 줄도 쓰지 않을꺼니까요.
심지어 러버블은 직접 코드를 수정할 수도 없습니다. github과 연동해서 가져오는 방법이 있기는 한데 귀찮아서 그렇게까지 하고 싶지도 않아요.
다 고쳤다더니 또 빌드가 오류가 납니다.
이정도면 인간이 뒤에서 키보드로 치고 있는 거 아니냐 싶은 합리적 의심이 듭니다. 우리가 생각하기에 AI 코딩은 막 뭔가 되게 빨리 잘 만들어줄 것 같지만 현실은 계속 빌드 실패입니다.
지금 할 수 있는 거라고는 Fix It 밖에 없기 때문에 Fix It 버튼을 누릅니다. 순식간에 샤샤샥 고쳐줄 것 같지만 실은 러버블이 생각하느라 꽤 오래 걸립니다. 한번 프롬프트를 입력하면 한 5분은 기다려야 하기 때문에 멍때리고 있기는 좀 그래서 다른거 하다가 확인하는 방식으로 진행했습니다.
한편 이런 생각도 들더군요. 빌드 오류가 여섯번만 나면 삼십분이 흘러가는데, 유튜브에 돌아다니는 "30분만에 앱 만들기!" 같은 걸 하는 분들은 모든 것을 통달하신 건가 아니면 인간이 만들어도 30분이면 되는 앱만 만드는 건가.. 같은 쓸데없는 생각이요.
이런 부질없는 생각을 하고 있던 찰나 러버블이 답을 해 줍니다.
그렇습니다. 또 빌드 오류입니다. 이쯤 되면 나를 화가나게 해서 더이상 이 서비스를 못 쓰게 하려는 속셈인가 싶습니다. 그렇지만 제 손은 묵묵히 fix it 버튼을 눌렀죠.
러버블은 참 일관성이 있습니다. 또 빌드 오류를 냈거든요. 이제 화도 안 납니다. 그저 fix it을 누를 뿐이에요.
fix it 만 다섯번쯤 하고 나니 지친 저는 밥을 먹고 오기로 합니다. 다녀왔더니 드디어!
또 오류를 냈습니다. 하지만 배가 불러서 기분이 좋아진 저는 넘어가 주기로 했죠. 또 fix it을 누릅니다.
마침내 빌드 오류가 나지 않습니다. 계속 버그를 만들어내는 나를 보는 기획자의 마음도 이랬을까.. 하는 아련한 생각을 해 봅니다.
드디어 빌드를 성공한 저는 수파베이스에 가서 API를 테스트 해 보기로 합니다. 참고로 supabase Edge function 테스트는 Edge functions => Functions => 해당 함수 선택 => 우측 상단 Test 버튼을 누르면 할 수 있습니다.
물론 무턱대고 오류가 나! 라고 하면 러버블이 대체 뭐가 오류가 난다는 건지 감을 못 잡을 것 같아서 curl 명령어를 첨부하기로 합니다. curl 명령어는 supabase 의 해당 함수 선택 후 details를 클릭하면 볼 수 있습니다.
Bearer 인증을 사용하는군요.
인증 키는 비밀이라서 지웠습니다. 실제로는 알 수 없는 글자가 써 있어요.
그랬더니 러버블이 뭔가를 멋지게 고쳐줬습니다. 그렇지만 다른 오류가 나기 시작했어요...
이 시점에서 저는 뭔가 잘못되었음을 깨닫습니다. 이건 러버블 문제가 아니라 내 문제일 수도 있다. 그래서 저는 원본 파일 주소를 확인합니다.
https://github.com/awesome-devblog/awesome-devblog/blob/main/db.yml 로 되어 있었습니다. 이건 github 페이지였던 겁니다.
우리에게 필요한 것은 raw yml 파일입니다. 즉 주소가 https://github.com/awesome-devblog/awesome-devblog/blob/main/db.yml 대신 https://raw.githubusercontent.com/awesome-devblog/awesome-devblog/refs/heads/main/db.yml 여야 했습니다.
(raw url은 github 페이지에서 Raw 버튼을 누르면 알 수 있습니다.)
그래서 러버블에게 대놓고 사과해 봤자 특별히 달라지는 부분이 있을 것 같지는 않아서 마음속으로 사죄를 하고 다시 요청을 합니다.
이번에는 API 테스트가 정상적으로 실행되었습니다. 데이터베이스 sources
테이블에도 데이터가 들어왔어요. 드디어 뭔가 하나 만들어졌구나..라는 기쁨이 화려하게 제 몸을 감쌉니다.
이제 피드를 수집할 차례입니다. 러버블에게 다시 요청을 드립니다
참고로 503은 서버가 작업을 처리할 수 없다는 뜻입니다. 더 쉽게 표현하자면 "서버에 버그 있음" 정도 되겠습니다.
또 뭔가 뚝딱 뚝딱 고쳐줬습니다. 그런데 다른 오류가 나요. 고쳤다고 했지 오류가 없다고는 안했다.
이 과정이 굉장히 지난해 보인다면 정상입니다. 개발자는 하루 종일 이러고 있습니다. AI가 등장하기 전에는 고쳐놓고 테스트하고 안돼면 스택 오버플로우를 뒤지고 다른 방법으로 또 고쳐놓고 테스트하고를 반복했죠. 제가 개발하고 있을 때는 당연한 거라고 생각하고 있었는데 막상 일을 시키는 입장이 되니까 엄청 열받네요.
메시지를 자세히 보시면 아시겠지만 저는 한글을 무척 이상하게 썼습니다.
오류라기보다는 rss feeds 가 오류가 있다고 하는데, 자세한 오류 원인을 살펴봐 줘
그렇지만 러버블은 잘 알아듣고 문제를 해결합니다. 대단한 AI 같으니라고.
Deno의 native fetch
가 Node.js 의 HTTP 메서드보다 낫기 때문에 그 방법으로 수정했다고 합니다. 테스트해 봤는데 supabase 의feed_item
테이블에 데이터가 잘 들어옵니다. 기능 하나 더 완성했군요.
만족한 저는 이제 시스템을 개선해 나가기로 합니다.
개발의 세계에 익숙하지 않은 분들은 잘 이해하기 어려울 수도 있는데, 시스템은 한 번 구축되었다고 끝이 아닙니다. 끊임없이 보이는, 혹은 보이지 않는 부분을 수정해나가면서 개선하죠. 이제 진짜 개발 시작입니다.
진짜 뼈때리는 조언을 듣고 싶으시다면 쑤난 님의 책 개발자의 IT 회사 취업 오해 풀기을 추천합니다. 얇은 책이지만 끊임없이 개선해야 하는 진짜 개발의 세계에 대해 이야기합니다.
RSS는 그 특성상 웹사이트 도메인이 사라지거나, 아니면 개발자가 블로그를 폐쇄하거나 하는 등의 이유로 RSS 주소가 없어지는 경우가 있습니다. 그렇지 않더라도 외부 접속을 차단하는 사이트들도 있고요. (RSS는 원래 외부에서 수집해가라고 제공하는 데이터이긴 하지만, 서버 관리자의 미숙 등으로 접속이 안 되는 경우가 의외로 많습니다.)
매일 RSS 를 수집해야 하는 RSS 수집기가 계속 없는 페이지를 방문하는 건 일종의 낭비죠. 그래서 저는 3번 오류가 난 RSS는 수집하지 않는 로직을 추가하기로 했습니다.
이전 작업에 어찌나 만족했는지 "좋아"라는 멘트까지 썼었네요.
뭔가를 바꿔줬습니다. 그런데 또 빌드 오류가 나요. 허허. 러버블에게 조련당하는 느낌입니다.
fix it을 눌러 고치라고 했더니, error_count
라는 컬럼이 없어서 오류가 나는 거라고 합니다. 그러더니 데이터베이스 컬럼을 추가하는 쿼리도 만들어 줬어요. 그리고 Apply 버튼을 누르라고 나옵니다. 눌렀습니다. 포인트가 차감되고 컬럼이 생성됩니다.
놀라운 건 데이터베이스 컬럼을 바꾸면 수파베이스에만 적용하는 게 아니라, 해당하는 타입스크립트 코드도 함께 수정한다는 겁니다.
이녀석, 내 생각보다 똑똑할지도? 라는 생각이 스칩니다.
가만히 엣지 펑션을 들여다 보던 저는 이상한 점을 발견합니다. 기존 코드는 다음과 같았습니다.
// Check for existing sources
const { data: existingSources, error: queryError } = await supabaseClient
.from('sources')
.select('id, updated_at')
.eq('rss', blog.rss)
.limit(1);
if (queryError) {
console.error(`Error checking source: ${blog.rss}`, queryError);
errorCount++;
continue;
}
타입스크립트에 익숙하지 않던 저는 이 코드를 얼핏 보고는 오해하고 맙니다. id
와 updated_at
컬럼을 기준으로 뭔가를 조회한다고 생가한 거에요.
그래서 다음과 같이 수정을 요청하죠.
저는 틀렸고 러버블이 기존에 작성한 코드는 맞았습니다. 하지만 언제나 충실한 AI는 제가 시키는 대로 고쳐주고 맙니다. 게다가 두번째 요청과 맞물려서 역대급 이상한 코드를 만들어냅니다.
요청 두 개를 동시에 한 이유는, 러버블이 "횟수"로 AI 활용을 카운팅하기 때문입니다.
다른 바이브 코딩 툴들은 보통 "토큰" 단위로 과금을 하죠.
"횟수" 기반 카운팅은 한번에 몇 개의 요청을 해도 한 번 횟수만 차감하기 때문에 이 때는 이게 현명한 방법이라 생각했습니다.
하지만 지금 와서 생각해 보니, AI에게 일을 시킬 때는 하나씩 시키는 게 훨씬 현명하다는 생각이 듭니다.
동시에 일을 여러 개 시키면 무언가 예상치 못한 잘못된 결과를 가져오는 경우가 많아요..
의심병이 도전 저는 러버블이 수정한 코드를 다시 한 번 확인하다가 "이건 아니지"라는 생각이 들고 맙니다. 그래서 로직 변경을 요청하게 됩니다.
그랬더니 러버블이 코드를 검토하고는 저에게 피드백을 줍니다.
변경사항을 적용할 수 없습니다. 왜냐하면 이전의 코드와 똑같거든요. 라는 메시지였죠. 흥 시크한 것 같으니라고
그제서야 저는 다시 한번 코드를 확인합니다. 그리고 러버블이 맞았고 제가 틀렸다는 것을 급 인정하게 됩니다. 이 날은 제가 수면량이 부족했나봅니다.
엣지펑션 로그를 보던 중 뭔지 모를 오류 로그를 발견합니다.
여하튼 뭔가 오류가 있다고 합니다. 그리고 수정해 줄 꺼냐고 제안하죠.
이 시점에서 저는 바이브코딩의 한가지 가능성을 발견합니다. 아무것도 모르는 사람이 질문을 하면서 코딩을 배울 수 있겠구나.
물론 국지적인 지식을 배운다고 해서 실력이 일취월장하는 건 아니지만, 그래도 모르는 것보다 낫잖아요.
그리고 오류가 있으면 그냥 오류 메시지를 복사한 다음 수정해 달라고 하면 수정해 주는구나.. 도 깨닿습니다.
그런데 프론트엔드 테스트를 하던 중 이상한 점을 발견합니다. 수파베이스에 있는 데이터와 프론트엔드에 나오는 데이터가 다른 거에요. 그래서 물어봅니다.
왜 데이터베이스를 다 만들어놓고 연동을 안 시켰는지는 잘 모르겠습니다. 아마 제가 직접 시키지 않아서인 것 같기는 한데, 알아서 다 해주는 건 절대 아니군요.
아무래도 바이브코딩은 아직은 하나씩 직접 사람이 챙겨야 하나 봅니다.
그럼에도 불구하고 고무적인 점은, 시키지도 않았는데 로딩 상태와 오류 처리도 추가했다는 점입니다. 꼭 필요한 건 안해주고 옵션 요소는 해주는 센스 이러면 미처 생각하지 못한 부분도 챙길 수 있어 좋지요.
그런데 디자인이 너무 개발자스럽습니다. 이것은 마치 CSS 프레임워크의 시조새 부트스트랩이 유행할 무렵 모든 사이트의 디자인이 부트스트랩스러웠던 것처럼, 테일윈드의 전형적인 사이트 디자인을 보는 것 같았죠.
미적 감각은 전혀 없지만 비슷한 걸 잘 골라내는 저로써는 이런 건 참을 수 없었습니다. 그래서 디자인 수정을 요청합니다.
디자인은 https://www.youware.com/ 에서 한 겁니다. 처음에 나왔던 프롬프트를 똑같이 입력해 놓고 디자인 해 달라고 했더니 이렇게 해 주었어요.
참고로 youware는 프론트엔드만 AI로 생성하고 공유하는 사이트입니다. 처음에는 매일 5개씩 무료 프롬프트를 주고 20달러를 결제하면 무제한으로 사용할 수 있더니, 지금은 무료일 경우 한 달에 5개, 유료여도 갯수 제한이 생겨서 매력이 많이 떨어진 상태입니다.
추가로 UI/UX 생성에 관심있으신 분들에게 팁. UI를 생성해 주는 사이트들은 의외로 꽤 있습니다. 구글이 갈릴레오 AI를 인수해서 만든 스티치 를 비롯해 피그마에서도 플러그인들이 있어요. uizard 나 uxpilot, visily.ai 등도 있습니다. 관심 있으신 분들은 찾아보셔도 좋아요.
여하튼, 원본 디자인보다 youware 디자인이 나아보여서 디자인을 바꿔달라고 했더니 시키는 대로 바꿔 줬습니다. 한결 낫네요.
프론트 디자인을 바꿨더니! 다시 데이터베이스 연동 코드가 사라졌습니다. 또 샘플 데이터만 프론트에 표시되는 거에요. 뭐지?
그래서 다시 데이터베이스 연동을 주문합니다.
아래에 api.ts
파일 리팩토링하기..라는 메뉴가 생겼습니다. 아마 러버블이 생각하기에 한 파일의 코드 량이 너무 길다고 생각한 것 같습니다.
쿨하게 무시합니다. 저는 아직 기능 구현도 안 끝났거든요.
물론 하나씩 코드를 정리해 나가는 것도 좋은 태도이지만, 매일 다섯 개의 수정밖에 할 수 없는데 리팩토링으로 쓰기에는 아까웠어요.
당연히 제가 코드를 직접 작성할 때는 조금씩 계속 리팩토링을 계속했었습니다. 안그러면 코드가 너무 길어져서 읽기 어려우니까요. 하지만 바이브코딩에서는 어차피 코드는 제가 안 읽으니까 무시하기로 합니다. 나중에 러버블이 코드를 제대로 못 읽는 순간이 오면 그 때 리팩토링하죠 뭐.
이제서야 기본 기능이 완성되었으므로 저는 본격적으로 기능을 붙이기 시작합니다.
우선 디자인 중 최신순, 조회순은 의미가 없으므로 삭제합니다. (1)
그리고 가장 많이 사용된 태그 목록을 뽑아내는 기능을 추가합니다. (2)
더보기 버튼 대신 SEO 에 더 최적화된 페이징 방식으로 변경합니다. (3)
그런데, (2)의 기능에서 문제가 발생합니다. 러버블이 어떤 컬럼을 기준으로 태그를 가져올 지 감을 못 잡은 것 같아요. 기존 코드를 살펴보니 sources
테이블의 tags
컬럼을 기준으로 가져오고 있었네요.
이런건 의미론적인 문제이므로 직접 해당 컬럼을 알려줍니다.
러버블이 고쳐 준 코드는 다음과 같습니다.
이정도는 타입스크립트를 모르는 제가 봐도 읽을 수 있는 아주 명확한 코드입니다. 물론 저는 바이브 코더답게 자세히 보지 않고 슬쩍 훑어만 봤습니다.
참고로 categories 컬럼은 이렇게 생겼습니다.
text[]
타입이에요. PostgreSQL은 다른 데이터베이스와 다르게 배열 타입의 컬럼을 지원하기 때문에 자식 테이블 없이도 태그를 관리할 수 있습니다.
지금와서야 말하지만, 이게 제가 이 프로젝트를 시작한 계기입니다. 원래 모태인 awesome-devblog의 형재자매 프로젝트 중에는 daily devblog 라는 서비스가 있습니다. 매일 아침 10시, 어제 발간된 개발자들의 글을 모아서 이메일로 보내주는 서비스죠.
너무나 잘 사용하고 잘 읽고 있는데, 한가지 단점이 있었어요. 바로 개발글이 아닌 엉뚱한 글이 너무 자주 올라온다는 거였죠. 간단한 신변잡기면 그나마 재미로라도 읽을텐데, 종교에 대한 글이거나, 뭘 판다거나, 심지어는 보험 광고까지 올라오는 걸 보면서 이건 서비스를 망치는 거다 싶었어요. 그래서 개발 글만 보이도록 하고 싶었습니다.
그래서 저는 러버블의 개발 지능을 테스트합니다.
문제만 던져주고 어떻게 풀어야 할 지 질문을 했는데, 의외로 자세히 답을 써 주었어요. 모처럼 공들여 읽은 후 저는 다음과 같은 알고리즘을 제안합니다.
간단하게 말하면 AI를 통해 개발 글인지 판단하자는 거였죠. 위 글은 그걸 구현하는 방법을 적어준 거고요.
러버블은 제 대화에 따라 컬럼을 생성하고 gemini 키를 입력하는 화면까지 만들어줍니다. 이건 정말 어썸했어요.
하지만 어썸한 것과는 별개로 러버블은 멋대로 이상한 구현을 합니다. 저는 그냥 AI를 통해 개발 글인지 판단하고 싶었는데, 러버블이 만든 함수는 AI 호출 비용을 줄이기 위해 키워드 기반 필터링을 거친 후 키워드 필터를 통과한 글들만 AI를 호출했어요.
이런 사실을 어떻게 알았냐면, 해당 기능을 테스트하던 중 분명히 제가 보기에는 개발 글인데 is_dev_post
컬럼이 False
로 표시되는 글들이 눈에 띄었거든요. 뭔가 이상하다 싶어 함수를 뒤져봤더니 이같은 만행이 드러난 거였죠.
분노한 저는 다시 요청을 합니다.
ChatGPT나 Claude 등 고급 모델이 있음에도 불구하고 Gemini 2.0 Flash-Lite API를 사용한 이유는 (제가 알기로) 가장 많은 무료 API를 호출할 수 있는 모델이었기 때문입니다.
RPM은 분당 요청수, TPM은 분당 토큰수, RPD는 하루에 호출할 수 있는 API 갯수입니다.
Gemini 비율 제한은 여기 에서 확인할 수 있습니다.
(4) 에서 엣지 펑션으로 만들어달라고 한 이유는 제가 매일 들어가서 업데이트 버튼을 누르고 싶지 않았기 때문입니다.
대신 cron을 이용하고 싶었어요. cron은 리눅스에 기본으로 내장된 스케쥴러입니다. 특정 시간이 되면 명령을 실행하죠.
하지만 저에게는 cron을 실행할 수 있는 서버가 없습니다. 그렇지만 언제나 대안은 있죠. 온라인에서 cron을 대신해주는 서비스 cron-job 이 있으니까요. 이 사이트는 주기적으로 특정 URL을 호출해주는 역할을 합니다. 우리의 엣지 펑션은 외부에 열려 있으므로 cron-job을 통해 엣지 펑션을 호출해서 자동으로 글을 업데이트하게 했습니다.
30분마다 한 번씩 업데이트하게 한 이유는 gemini의 API 제한 때문입니다. 너무 자주 업데이트할 경우 제한이 걸릴 것 같았어요. 실은 이것 저것 계산해서 최적의 값을 넣은 건데 막상 글을 쓰는 현 시점에는 왜 그랬는지 잊어버린 관계로 구체적인 숫자는 넣지 않습니다.
물론 이 상태 그대로 엣지 펑션이 실행되지는 않아요. 보안 인증이 걸려있거든요. 그래서 http 헤더에 인증키를 함께 담아서 호출해 봅니다.
잘 되네요.
안타깝게도 러버블의 무료 제한, 한 달 30개의 대화를 모두 채우고 말았습니다. 25$가 없는 저는 다음달에 해야지..라고 미뤄놓고 까맣게 잊어버리고 있다가 2025년 6월 1일 다시 대화를 재개합니다.
그런데 막상 대화를 재개하려고 보니 이런, 제가 뭘 만들고 있었는지 하나도 기억이 안납니다. 예전같았으면 코드를 하나씩 읽어보며 파악했겠지만 지금은 바이브 코딩의 시대 아니겠습니까? 그냥 AI에게 물어봅니다.
엣지 펑션의 역할을 러버블이 설명해 주었는데요.
가만히 생각해 보니 글을 분류하는 엣지 펑션과 외부에서 호출하는 엣지 펑션이 굳이 다를 이유가 없습니다. 그래서 엣지 펑션을 하나로 합칩니다.
원래 개발을 할 때는 인터페이스는 간단하게, 내부 로직은 분산되게 작성하는 것이 기본입니다. 인터페이스가 많으면 관리 포인트가 많아져서 유지보수가 많이 어렵거든요.
그런데 엣지 평선을 합쳤다고 나오는데 수파베이스에 보니 여전히 예전 엣지 펑션이 남아있네요. 저는 수파베이스 사용법을 잘 모르므로 러버블에게 또 물어봅니다.
이런 식으로 엣지 펑션을 삭제하는 방법까지 친절하게 알려줍니다. 따라했더니 정말 엣지 펑션이 사라졌어요. 참 놀랍죠?
오 이제 다 되었어..라고 생각하고 테스트하는데 여전히 문제가 남아있습니다.
여전히 개발 글임이 분명한데 is_dev_post
컬럼이 False
인 데이터들이 많이 보이는 거죠. 왜 그런지 코드를 확인해 봅니다.
각 피드의 컨텐츠를 기준으로 개발 글임을 판단했더니 그런 거였습니다.
RSS 규격을 아시는 분이라면 이해하실 수도 있는데, RSS는 전체공개와 부분 공개가 있고, 부분 공개일 경우 데이터가 일부만 외부로 공개됩니다. 또한 RSS 컨텐츠는 HTML을 포함할 수 있으므로 , Gemini 입장에서는 HTML 태그만 가득하고 정작 컨텐츠는 별로 없는 글인 경우 진짜 개발 글임에도 불구하고 개발 글이 아니라고 판단해 버린 겁니다. 범인은 이 안에 있다.
그래서 저는 1.) AI가 직접 블로그 포스팅을 읽고 => 2.) 블로그 포스팅을 요약한 후에 => 3.) 요약한 블로그 포스팅을 기반으로 개발 글임을 판단하게 알고리즘을 변경합니다.
개별 글에는 이미지가 있을 수도 있고, 없을 수도 있습니다. 그런데 기존 UI는 모두 이미지가 있다는 가정 하에 리스트를 렌더링하고 있었어요. 그래서 이미지 데이터도 수집하고, 이미지가 있다면 이미지를 보여주고, 이미지가 없다면 글만 보여줄 수 있게 UI를 변경해 달라고 요청합니다.
러버블에 첨부한 이미지는 다음과 같습니다.
눈치가 안 빠르셔도 눈치채실 겁니다. velog의 UI입니다. 예뻐서 이용해 보고 싶었어요.
그렇습니다. 제가 그냥 publish를 안하고 캐시에 남아있던 UI를 보고는 아직 반영이 안 되어 있다고 생각한 겁니다.
굳이 이런 창피한 이야기까지 하는 이유는, 오랫동안 개발을 업으로 해 온 사람이라고 하더라도 실수를 하는 경우가 있다는 걸 말씀드리고 싶었습니다. 제가 특별히 모자란 사람이라서 그런 건 절대 아니에요. 결코, 결단코 아닙니다. 아니라고요...........
이미지는 잘 가져옵니다만, 다시 문제가 있습니다. 티스토리 블로그 같은 경우에는 첫번째 이미지가 대부분 티스토리 로고입니다. 러버블이 구현한 피드 파서는 HTML의 body
태그를 읽어서 이미지 목록을 추출하는데, 보통 티스토리 서비스 로고가 가장 먼저 나오거든요. 그런데 우리의 글에 티스토리 로고만 들어가 있는 건 의미가 없잖아요? 그래서 이미지를 가져오는 알고리즘을 수정해달라고 요청합니다.
이번에는 특정한 알고리즘을 명시하지 않았고, 그냥 티스토리 로고 같은 걸 빼 달라고만 요청했습니다. 그랬더니 이렇게 바꿔줬어요.
일반적인 패턴의 본문 영역에서 이미지 태그들을 찾돼, 로고나 이미지가 작은 이미지들은 제거하는 로직입니다. 이정도면 러버블은 천잰가? 싶은 생각이 들 정도입니다.
이 프로젝트를 진행해나가는 동안에도 수파베이스에 데이터는 쌓이고 있었습니다. 그런데 기존 데이터들에는 이미지를 수집한 기록이 없죠. 이렇게 과거 데이터를 한번에 마이그레이션해야 하는 경우가 가끔 생기는데요. 일반적으로 개발을 할 때는 일회성 프로그램을 만들어서 기존 데이터를 마이그레이션합니다만, 바이브코딩으로는 어떻게 해야 할 지 몰랐어요.
모르면? 물어보면 됩니다.
이런 식으로 현재 코드, 기존 데이터를 채우는 방법까지 제시해 줍니다. 어메이징 그레이트하죠.
그런데 결국 이건 실행 안했습니다. 귀찮아서는 절대 아니고요. 엣지 펑션을 계속 호출하면 gemini 제한에 걸릴 걸 뻔히 알거든요.
물론 아주 중요한 데이터라면 이미지를 채우는 엣지 펑션과 ai를 호출하는 엣지 펑션을 분리해서 이미지를 채우는 엣지 펑션만 계속 호출하면 됩니다만, 이미지가 반드시 보여야 하는 것도 아닌데 굳이? 라는 생각이 들어서 그만두었습니다.
현업에서도 이런 경우는 자주 생깁니다. 즉 어디까지 데이터를 버릴 지 결정해야 하는 문제입니다. 그 때 그 때 사안에 맞춰 방향을 잡아야 하는데, 방향성을 설정하는 것은 AI가 못 해 주겠죠?
우리는 웹에서 러버블을 이용해 바이브코딩을 하고 있고, 배포 및 서버 관리도 러버블에서 해 주며, 데이터베이스도 클라우드 베이스의 서비스인 수파베이스를 사용하므로 인프라를 건들 일이 전혀 없다고 생각했는데, 역시 오산이었습니다.
수파베이스에 들어가 봤는데, 용량을 거의 다 썼다고 빨간색! 경고가 떴습니다. 급히 눌러보니 Database Size가 90%를 넘어 있었어요. 수파베이스는 무료 용량을 500MB를 제공해 주는데 데이터만 있는데 500MB가 거의 다 찼다고? 싶어 어떤 컬럼이 용량을 차지하는지 확인합니다. 그리고 해당 컬럼을 삭제해 달라고 요청하죠.
1, 2,3 이 그 내용입니다.
4는 feed_items.is_dev_post 컬럼의 default 값이 null
이므로 당연히 처음에는 null
이지만, 조금 더 명시적으로 수정해 달라는 요청사항입니다. 안바꿔도 상관없는 코드를 굳이 바꾸는 이유는 혹시나 만약에라도 코드를 들여다볼 일이 생기거나, 데이터베이스 구조가 생각이 안나더라도 데이터의 흐름을 코드 레벨에서 빠르게 파악하기 위함입니다.
특히 오히려 바이브 코딩을 할 때 이런 점이 중요하다는 생각이 드는데요. 바이브 코딩은 어차피 AI가 코드베이스를 읽어서 추론한 후 무언가 코드를 작성하는 작업입니다. 바꿔 말하면 외부 자원(데이터베이스, API등..)에 대한 스펙이 명시적으로 코드에 적혀있지 않다면 AI가 실수를 할 확률이 높다는 뜻이기도 합니다.
5는 그냥 쓰는 곳이 없으므로 삭제한다는 의미입니다.
6은 데이터 마이그레이션을 위한 코드입니다. summary
수집 알고리즘이 추가되기 전 데이터들 중 일부 (2025-06-01 이후의 데이터들)만 대상으로 마이그레이션을 하기 위해 해당 컬럼의 데이터 변경을 요청했습니다.
한동안 잊고 있었는데 또 빌드 오류가 났네요. 전 이게 러버블이 멍청해서 그런 줄 알았는데, 그런 게 아니었습니다. 그저 제가 한번에 너무 많은 요청을 했기 때문이었어요.
코딩이라는 건 한 단계씩 밟아가는 것이 가장 안전하고 오히려 빠릅니다. 저는 그저 질문 갯수가 아까워서 여러 개를 요청했기에 생기는 문제인 것 같습니다.
수파베이스에서 Egress가 100%를 넘었습니다. supabase Egress는 outbound가 너무 많거나, 혹은 데이터베이스 read를 할 때마다 생기는 제한인데요.
어떻게 해결해야 할 지 모르겠어서 또 러버블에게 던져버립니다.
대량의 데이터를 조회한다고?
저는 그런 코드 작성을 요청한 적이 없습니다. 의심스러웠죠. 그래서 코드를 보여달라고 요청합니다.
토큰이 가까워서 여러 질문을 몰아 하는 주제에 이런 걸로 질문 갯수를 낭비하다니..무엄하도다.
놀랍게도 러버블이 문제점까지 분석해서 알려줍니다. 인기 태그를 사이트에 접속할 때마다 계산해서 가져오고 있었네요.
일반적으로 이런 인기 태그 기능은 배치(스케쥴러)가 돌면서 주기적으로 데이터를 업데이트합니다. 그래야 데이터베이스에 부하를 덜 주거든요. 그래서 저도 그 방향으로 바꿔봅니다.
다음날 Egress를 확인해 봅니다. 확 줄었습니다. 다행이다 싶어 한 시름 놓습니다.
1은 하루에 한 번만 피드를 업데이트하는 걸로 실행 주기를 조정하는 겁니다. 블로그는 SNS와 다르게 하루에 한 개 이상의 글이 올라가는 경우는 거의 없습니다. 세개 이상은 스팸을 의심해야 합니다. 따라서 하루에 한 번만 수집하면 충분하다고 생각했습니다.
하루에 한 번이라고는 하지만, 한번에 모든 피드를 다 순환하면서 가져오는 것이 아니므로 업데이트 주기는 계속 달라질 것이라고 생각했습니다.
2는 러버블의 조언을 따른 겁니다. 러버블이 저에게 이렇게 말해줬어요.
3은 통계 쿼리의 아주 중요한 부분입니다. SQL을 다뤄 보신 분들이라면 아실 텐데, select
절에서 컬럼을 명시하는 것과 모든 열을 가져오는 것은 속도에서 많이 차이가 납니다. 특히 group by
를 이용한 통계 쿼리에서는요.
그 부분 코드를 보다가 굳이 모든 데이터를 가져와서 통계를 계산할 필요는 없겠다 싶어 개선을 요청한 것입니다.
아직도 티스토리 로고가 나오고 있었네요.
귀찮으므로 다시 러버블에게 전권을 위임합니다.
youware가 만들어 준 디자인 중 파란색 윗 부분이 마음에 안 들었어요. 그래서 네가 알아서 고쳐달라고 요청했죠.
뭔가 작업을 하더니 훨씬 나은 디자인이라며 이런 걸 가져왔습니다.
별 차이 없는 것 같은데... 라고 생각했지만 러버블의 정성을 봐서 넘어가기로 합니다. 어차피 제가 직접 디자인할 능력도 없는걸요.
사소한 기능을 계속 추가합니다.
저는 이 서비스에 RSS 기능을 넣고 싶었습니다. 어차피 내 서버 비용도 안 나가는데 사람들이 이 데이터를 가져 가서 더 쓸모 있는 서비스를 만들면 좋겠다 싶었어요. 그래서 RSS 기능을 추가해 달라고 요청했는데.. 절반의 성공이었습니다.
RSS기능 자체는 추가되었습니다만, 러버블이 클라이언트 사이드 렌더링 방식으로 동작하는지라.. 곧바로 XML이 보여지지 않더라고요.
이게 처음 시도한 프롬프트입니다.
RSS 기능을 엣지 펑션에 넣어버리는 바람에 수정을 요청했습니다.
피드 기능 오류나서 러버블에게 보고드리는 알려주는 스크린샷입니다.
아마 앞으로도 가끔 생각나면 해당 프로젝트를 업데이트할 것 같기는 하지만 우선은 여기까지만 하기로 했습니다. 지겨웠거든요.
이 프로젝트를 하면서 느낀 점은 다음과 같습니다.
저는 코드를 단 한 줄도 쓰지 않았습니다. 말만 했어요. 그랬더니 서비스가 완성되었습니다.
머리속에 코드를 그리고 작성하는 데 익숙한 저로써는 무척 즐거운 경험이었습니다.
간단한 랜딩 페이지나 회사 소개.. 이런 단순한 READ 위주 페이지 말고, 현재 프로젝트처럼 뒷단에서 이것 저것 해야 하는 프로젝트를 과연 비개발자가 쓸 수 있을까? 라는 의문에 대해서는 일단 "NO" 입니다.
물론 제가 개발자라서 너무 개발자 위주의 프롬프트 진행방향으로 러버블과의 이야기를 끌고 갔을 수도 있습니다만, 어떤 문제가 부딛혔을 때 유튜브에서 말하는대로 "오류 로그 붙여넣으면 만사 해결 :-)" 이라는 만병통치약 방식이 과연 통할까?라는 의문이 들었습니다.
저만 해도 이 프로젝트를 진행하기 위해 여러가지를 찾아보고 러버블에게 물어보고 구글이랑 스택오버플로우랑 다른 LLM이나 퍼플렉시티 등을 뒤적거리며 해결책을 찾았거든요.
제가 누누히 말씀드리듯이, 코드를 작성하는 건 사실 그다지 어려운 일이 아닙니다. 센스가 있는 사람은 한달이면 배울 수 있고, 평범한 사람도 일반적인 CRUD는 세달 내에 할 수 있습니다. 당연히 일년을 배워도 전혀 못하는 사람도 있습니다.
하지만 그 외에 "개발"이라는 큰 범위에서 알아야 할 소소한 개념들 HTML,CSS, JS, 프론트엔드와 백엔드, 스케쥴러, 인프라, 데이터베이스, 네트워크, API 연동 등을 배워가는 건 어렵죠.
그리고 이 모든 걸 하나로 긁어모아 시스템을 만드는 일은 열배쯤 더 어렵습니다. 기계적인 코딩 훈련이 아니라 사고 훈련이 되어 있어야 하는 영역이거든요.
이전 같았으면 비개발자 분들은 엄두도 내지 못할 일을 지금은 대화로 진행할 수 있습니다. 그 한계도 뚜렸하겠지만, 적어도 시작점 자체는 훨씬 좋아졌습니다.
저는 이것이 훌륭한 변화라고 생각합니다. 개발을 업으로 삼지 않더라도, 논리적인 사고를 배우는 건 삶에 큰 도움이 된다고 (개인적으로) 많이 느끼고 있습니다.
바이브 코딩을 통해 무언가 인생을 역전한다기보다는, 모르는 것을 알아가는 계기로 삼는다면 이 또한 훌륭하지 않을까 생각합니다.
프로젝트 결과물은 개발자들의 놀이터 에서 보실 수 있습니다.
이 프로젝트는 25$가 없는 관계로 자그마치 한달에 걸쳐 진행되었고, 이 글을 쓰는 데만 꼬박 삼일이 걸렸습니다. 물론 읽으시는데도 엄청난 시간이 걸리시리라 생각합니다.
벨로그에서 가장 긴 글에 도전합니다.
그럼에도 불구하고 여기까지 읽어주신 분들에게, 진심으로 감사드립니다.
고맙습니다!
10일 전부터 피드가 제대로 정상 수집되지 않고 있던 것 확인했습니다.
그래서 러버블에게 헬프를 요청했어요.
이녀석 천잰가?
이제 프롬프트 엔지니어링까지 합니다.
다시 나오게 되었습니다. 참 개발 쉽죠?
안녕하세요. 어썸데브블로그를 운영하고 있는 우준혁이라고 합니다.
글을 쭉 읽어보니, 정말 대단하십니다. 바이브 코딩으로 블로그 피드 큐레이션 사이트를 만든 경험이라니!
너무 좋은 사례로 보여서요, 혹시 이 글과 결과물을 소개 페이지(https://github.com/awesome-devblog/awesome-devblog)에 추가해도 될지 문의드립니다.
감사합니다.