바이브 코딩 4시간 후 라이브러리를 배포했다

커다란 생산성에는 대가가 따른다

바이브 코딩이라는 말이 유행했다. 혹은 아직 한창 유행 중이라고 봐야할지도 모르겠다.

넘쳐나는 바이브 코딩 간증 글을 보면서 반신반의하며 보다가, 모처럼 구독하고 있는 커서의 자동 완성 기능만 간신히 쓰는 것 같아서 조금 더 제대로 활용을 하고 싶다는 생각도 들었다. 결론부터 말하면 아직도 의심이 다 가지는 않았다. 하지만 바이브 코딩을 조금 더 알아보고 싶었다.

시작하기 전

아이디어의 시작은 업무였다. 사이드 프로젝트와 회사 업무 두 군데에서 공통적으로 사용 중인 라이브러리 하나가 눈에 띄었다. 지금은 SheetJS로 이름이 바뀐 xlsx가 그것이다. SheetJS는 좋은 라이브러리지만, 웹 페이지에 있는 테이블의 데이터를 엑셀 스프레드 시트 형태로 내려주는 용도로만 사용하기에는 너무나 거대했다. 최소화 버전의 번들 크기도 500KB 이상이었고 전체 기능을 사용하려면 1MB가 목전이었다. 그런데 내가 관여한 두 프로젝트에서는 기껏해야 몇 백건짜리 데이터가 담긴 JSON을 전달해서 작은 파일을 생성하는 정도의 기능만 필요했다.

.xlsx 파일의 구조를 들여다보니 .zip 파일 안에 파일이 몇 개 들어있는 단순한 구조였다. 불필요한 기능을 다 빼고 내가 필요한 기능만 추가하면 작고 가벼운 라이브러리를 만들 수 있을 듯 했다. 나처럼 번들 용량에 민감할 개발자가 세상 어딘가에 있을 거라 생각하며, 나와 그들을 위해 일주일에 겨우 하루 밖에 없는 휴일을 투자해보기로 했다. 게다가 매주 토요일 리더로서 참여하고 있는 부트캠프의 이번 주 주제가 오픈소스 라이브러리 제작이었기에 더 의미가 있을 것 같았다.

그래서 만들기 시작했다. 이름은 excelite.

첫 인상은 훌륭했다

프로젝트 셋업은 아주 순조로웠다. "TypeScript로 작성하는 라이브러리 프로젝트를 셋업해줘"라는 간단한 말 한 마디에 샘플 소스 코드와 테스트까지 포함한 7개 파일이 뚝딱 만들어졌다. 슬쩍 봐도 문제가 통상적인 셋업이었기에 문제가 될만한 부분은 없었...다고 생각했는데 ESLintPrettier 설정이 포함되어 있는 걸 발견했다. devDependencies도 최소한으로 하는 걸 좋아해서 최근 Biome을 즐겨쓰고 있었기에 ESLint와 Prettier 대신 Biome을 사용해달라고 했다. 또한 테스트 수트는 Node에 내장된 것을 사용할 예정이라 Jest도 제거해달라고 했다.

설치 명령어도 알아서 제안해주고 중간중간 테스트도 하라고 알려줘서 거의 "해줘" 만으로 프로젝트 셋업이 끝났다. CI 설정과 이슈 템플릿도 이 과정에서 추가되었다.

코드 작성도 순조로웠어

.xlsx 파일은 몇 개의 XML 파일과 기타 부속 파일이 포함된 .zip 파일이다. 그래서 확장자만 .zip으로 바꾸면 압축 프로그램에서 읽을 수 있다. .zip 파일은 파일 자체의 구조는 단순한 편인데 압축 알고리듬이 필요해서 순수 JS로 구현하기에 조금 복잡한 면이 있다. 하지만 .tar처럼 .zip 파일을 아예 압축하지 않는 방법도 있지 않을까 해서 리서치를 해보았다. 그래서 이번에 알게 된건데 .zip은 여러 압축 알고리듬을 지원하는 컨테이너였고, 알고리듬 중에는 아예 압축을 하지 않는 store 라는 것도 존재했다. 작성할 라이브러리는 번들 사이즈가 생성할 .xlsx 파일의 크기보다 중요했으므로 이 방식을 사용하기로 했다.

압축을 하지 않을 것이기 때문에 널리 알려진 jszip 패키지를 사용하는 것은 과했고, 그래서 압축을 전혀 하지 않는 간단한 ZipWriter 클래스를 작성하기로 했다. 사실 내가 작성한 코드는 별로 없었다. 퍼블릭 메서드가 두 개 있고, 압축을 하지 않는 클래스를 작성할 것이라고 최대한 자세하게 설명을 했더니 원하는 형태에 굉장히 가깝게 만들어주었기 때문이다. 클래스를 생성하고 사용 예시까지 알려주는 걸 보니 즐겁기도 했고, 무서울 정도였다. 명세만 잘 작성하면 몇 초만에 이런 기능을 만들어낸다.

생성된 파일을 참조해서 테스트 파일도 만들어달라고 했더니 곧잘 만들어냈다. 물론 구현이나 테스트가 완벽하지는 않았다. 웹 브라우저에서도 사용할 수 있도록 Buffer 대신 Uint8Array로 바꿔달라고 하고, 메서드의 인수도 변경해달라고 했다. 몇 번의 대화가 오간 후 내가 원하는 형태의 ZipWriter 클래스가 만들어졌다.

여기까지 작업하는 데 내가 작성한 코드는 하나도 없고 나는 오로지 리뷰만 했다. 방향을 명확하게 정해주면 빠르고 그럴듯한 형태로 결과를 냈었다. 가끔 바이브 코딩을 노코드와 오해하거나 혹은 호도하는 글을 보게 되는데, 바이브 코딩이라 해도 리뷰할 정도의 기술 역량은 여전히 필요했다. 그렇지 않았다면 명세를 작성하는 것부터 어려웠으리라. 마찬가지로 압축 파일 검증을 위한 crc32도 구현해달라고 했다. 대단한 성능이 필요하지 않았으므로 처음 모듈을 로드할 때 테이블을 만들기로 하고, crc32 체크섬을 ZipWriter 클래스에 반영했다. 이제 기반도 만들어졌고 계속해서 파일을 작성하고 테스트 환경까지 구성했다.

기본적인 테스트까지 다 포함되었는데, 처음 저장소를 만들던 시점부터 1시간 30분이 걸렸다. 이렇게나 생산적일 수 있다니!

괴로운 20% - 꼬이기 시작했다

이 정도면 100%는 아니어도 80%는 완료되었다 생각했다. 내가 작성한 코드는 거의 없다시피 했으므로 앞으로의 작업도 순탄하게 흘러갈 것이라 보았다. 언제나 그렇듯 예상은 빗나가기 마련이다.

시작은 테스트가 실패할 때였다. 타입스크립트를 사용했기 때문에 테스트를 실행하려면 별도의 설정이나 도구가 필요했다. Cursor는 언제나 대중적인 픽을 해주는데 이번에도 역시 ts-node를 추천해줬다. 그러나, 개인적으로 ts-node에는 안 좋은 기억이 있기에 tsx로 바꿔달라고 했다. 잘 되는 것 같았는데 다시 살펴보니 내가 요청한 대로 Node 빌트인 테스트 수트를 사용한 것이 아니라 자체적으로 실행 코드를 작성하고 결과를 확인하고 있었다.

테스트 수트를 그대로 실행하려고 보니 오류가 난다며 다시 tsx를 사용해서 파일을 실행하려고 시도하길래 tsx를 로더로 사용하라고 알려줬다. 하지만 잘못된 플래그를 사용했고, 그래서 검색 후 제대로 된 플래그 이름을 알려주었어야 했다. tsx 보다 최근 눈여겨보던 ts-blank-space를 사용해보고 싶어서 로더를 바꿔달라고 요청했더니 설정에 문제가 있었는지 오류가 났고, 자체적으로 수정을 시도하던 Cursor가 또 ts-node 패키지를 추천하길래 '아까 지웠잖아!' 싶어 결국 금지 명령을 내렸다.

그 후로도 몇 차례 수정 후에 결국 테스트를 통과시키게 됐다.

문제는 테스트나 환경 설정에만 있는 게 아니었다. 후반부로 갈수록 미세 조정을 위해 요청을 하면 엉뚱한 방향으로 튀는 일이 많아졌다. 특히 ts-node는 몇 번이나 살아서 돌아오는 좀비같았고, 뻔히 내부에 작성된 모듈이 있는데도, 다른 모듈에서 .xlsx 파일을 작성하려고 하니 외부 xlsx 패키지를 호출했다. ESLint도 두어번쯤 출몰했다.

그래서 작업을 하면서 규칙을 하나씩 .cursorrules 파일에 추가해달라는 요청을 하기 시작했다. Node 빌트인 패키지를 사용할 때는 반드시 node: 프리픽스를 추가해달라, ts-node, eslint, tsx는 사용하지 마라, 테스트는 영어로 작성해라, 테스트 실행할 때는 ts-blank-space/loader를 로더로 사용해라 등 속터질 때마다 하나하나 설정을 추가해갔다. 키보드를 누르는 손가락에 점점 더 힘이 들어가기 시작한 건 착각이었을까.

이 시점에서는 이미 더이상 바이브 코딩으로 부르기 어려웠던 것 같다. 명령으로만 해결하기에는 너무 답답하고 엉뚱한 행동을 반복해서 내가 하나씩 수정하는 게 속이 편했다. 초반 80%는 AI 덕분에 빠르게 작성할 수 있었다면, 나머지 20%에서는 오히려 AI와 투닥거리느라 많은 시간을 보냈다(물론, 사과는 빨랐다). 후반 20% 작업에 걸린 시간이 초반 80%보다 두 배쯤 더 걸린 것 같다.

결론: 바이브 코딩, 다시 할까?

라이브러리는 무사히 배포했다. 마지막은 좀 괴로웠지만, 그만큼 얻은 것도 많았다.

AI가 잘하려면 결국 내가 잘해야 한다는 걸 다시금 느꼈다. 명세를 명확히 쓰고, 원하는 걸 정확히 설명할 수 있는 능력. 이게 없으면 빠르게 결과를 내는 강점이 그대로 빠르게 말아먹는 단점이 되더라. 정신을 잠깐 놓으면 순식간에 테스트 파일을 다 갈아엎으려 들기도 했다.

100%를 기대하면 실망할 수도 있다. 특히 마이너한 선택이나, 비주류 도구를 선호한다면 신경써야 할 부분이 많아지고 어려움을 겪게 될 것 같다. 하지만 빠르게 80%를 완성하는 능력도 충분히 대단하고 가치있다고 생각한다. 내가 더 익숙해지고 나면 80% 이상을 얻을지도 모르겠다.

바이브 코딩? 이 정도면 일단… 또 할 것 같긴 하다.

댓글을 남겨주세요

This site uses Akismet to reduce spam. Learn how your comment data is processed.