12 min read

[뉴스레터 요약 버전] AI 시대의 협업 전략: 3자간 협업을 통한 대용량 JS 파일 리팩토링 경험

작년 초에 유명한 트윗이 떠돌았습니다. "AI will not replace you. A person using AI will." 이제는 여기에 동의하지 않지만, AI와 제대로 협업할 줄 아는 사람들은... 정말로 많은 인간 노동력을 대체할지도 모릅니다.

ChatGPT 초심자들의 흔한 실수

OpenAI가 ChatGPT의 GPT-4 모델을 공개한지 약 1년이 지났습니다. 그동안 주변에서 ChatGPT를 처음 써보는 사람들을 관찰해보니, 처음에는 개떡같이 물어봐도 똑똑한 인간처럼 찰떡같이 대답하는 ChatGPT의 능력에 무척 놀라워합니다. 그리고는 그들의 복잡한 실제 문제를 가져와서 ChatGPT에게 답을 얻어보려 하는데, 이 때 보통 3가지 실수를 범하더군요.

  1. ChatGPT가 정답을 단번에 줄 거라고 기대한다.
  2. ChatGPT가 정답을 단번에 줄 거라고 기대한다.
  3. 1과 2의 기대가 쉽사리 충족되지 않아 실망한다. 그래서 ChatGPT를 비교적 단순한 문제(e.g., 버튼 레이블 제안)에만 사용하거나, 수동적(e.g., VSCode Copilot)으로만 사용하거나, 아예 사용을 중단한다.

결과적으로, AI를 이용해 일상에서의 생산성을 끌어올릴 기회를 다수 놓치게 됩니다.

사실 이건 불과 몇 달 전까지의 제 모습이기도 합니다. 김창준님의 인지적 프롬프팅 교육을 들으면서 이전보다 훨씬 프롬프팅을 잘 하게 됐음에도 불구하고, 실제로 회사에서 접한 개발 문제에 ChatGPT를 이용하려다 보니 제가 1번과 2번 실수를 그대로 범하고 있었다는 걸 깨달았습니다.

하지만 이 실수를 깨닫고 전략을 바꿔나가다 보니, ChatGPT가 정답을 단번에 주지는 못하더라도 놀라운 도움을 줄 수 있다는 걸 실감하게 됐습니다. 그 전략이 바로 제목에서 언급한 AI + 코드 + 인간 3자간의 협업입니다.

이 3자간 협업 전략은 인지적 프롬프팅 교육에서 김창준님이 계속 강조했던 멘탈 모델입니다. 머리로만 알고 있었던 이 멘탈 모델을 어떻게 제가 직면한 문제에 적용하며 체화해나갔는지, 이것이 ‘ChatGPT에게 정답을 단번에 얻는’ 것과 어떻게 다른지 공유해보겠습니다.

💡
글이 너무 길고 코드 스니펫과 ChatGPT 프롬프트도 섞여 있어서 자세한 이야기는 뉴스레터에 담지 않았습니다. 전체 내용은 이 링크에서 보실 수 있습니다.

직면했던 문제

제가 XL8에서 담당하고 있는 제품 MediaCAT에는 자막 에디터가 내장되어 있습니다. 사실 ‘내장’이라는 건 유저 입장이고 실제로는 자막 에디터가 별도의 저장소로 분리되어 있죠. 올해 초부터 이 자막 에디터에 대한 고객 요구사항이 많아지면서 저의 주 역할을 에디터 쪽으로 옮겼고, 에디터 코드를 이리저리 살피게 되었습니다.

에디터 사용자들의 주된 피드백 중 하나는 에디터의 초기 로딩 속도가 무척 느리다는 것이었습니다. 그래서 본격적인 성능 개선 작업을 시작하기 전에 우선 낮은 곳에 매달린 과일이 없나 훑어봤습니다. 그 첫 단추는 번들 크기 측정이었고요.

측정해보니, 우리 자막 에디터의 메인 청크 크기가 무척 컸습니다. 그런데 node_modules는 그렇다 치고, 우리 앱 내에서도 단일 파일로 엄청나게 큰 용량을 가진 파일이 2개나 있었어요. 그 파일들을 살펴보니 현재 비즈니스 로직에서 필요한 부분이 극히 일부에 불과하더군요. 그래서 18,500줄짜리 파일의 리팩토링 노가다를 시작했죠.

그런데 말이 18,500줄이지, 비교하면서 지우는 게 결코 쉽지가 않았어요. 너무너무 지루했고, 자꾸 졸음이 쏟아지고, 실수도 자꾸 나왔습니다. 파일이 너무 기니까 내가 어디까지 제대로 했는지 확인하기도 어려웠고요. 문득 이런 귀찮고 반복적인 일을 ChatGPT가 잘 하지 않을까? 라는 생각이 들었습니다.

1차 시도: 나 대신 리팩토링좀 해줘

인지적 프롬프팅 기법을 이용해 함수 하나에 대한 리팩토링을 부탁해봤지만 실패였습니다. 지웠어야 하는 부분이 그대로 남아있었을뿐 아니라 애초에 컴파일도 안 되는 코드를 줬어요.

전반적으로, 코드 구조를 이해해서 변경하는 게 아니라 한 줄씩 내려가면서 지우는 방식이더군요. 몇 번 오류를 지적해서 다시 해달라고 했지만 모두 실패였습니다. 이대로는 안될 것 같다는 느낌이 강하게 들었죠.

2차 시도: 리팩토링하는 코드를 짜줘

이번에는 내 의도를 실현하기 위한 자바스크립트 코드를 짜달라고 해봤습니다.

You still fail to remove all the unneeded codes. Instead, can you provide a javascript code to refactor this function as my intention?

하지만 ChatGPT가 만들어준 코드가 생각보다 너무 좋지 않았어요. 1차 시도에서 실패했던, 자기가 내부적으로 쓰던 파이썬 코드를 그대로 자바스크립트로 변환한 걸로 보였습니다.

만들어진 코드를 보니, ChatGPT에게 이런 리팩토링을 그냥 시켰을 때 결과가 안 좋은 게 당연하다는 걸 이해하게 됐습니다. 어찌보면 그 이유도 자명합니다. ChatGPT는 인간이 웹상에 올려둔 문서들을 학습해서 만들어진 LLM입니다. 그런데 제가 원하는 수준의 리팩토링을 한 코드의 Before & After 스냅샷 같은 게 웹상에 과연 충분히 많았을까요? 아마 아니었겠죠.

3차 시도: AST로 리팩토링하는 코드를 짜줘

저는 파일 내용을 단순히 라인 바이 라인으로 지우는 걸 원하는 게 아니라 조건에 따라 if 문 같은 ‘블록’을 지우길 원했습니다. 그러면 이 함수를 문법적으로 이해해야 했고, 그렇다면 AST(Abstract Syntax Tree)라는 키워드를 이용하면 좋겠다는 생각을 했어요.

그래서 ESLint 같은 정적 분석 도구의 개발 경험이 있는 엔지니어의 역할을 부여하고, AST에 기반해 리팩토링하는 코드를 짜달라고 했더니 제법 훌륭한 babel 기반 코드가 나왔습니다. 아, 이렇게 traverse해가면서 어떤 구문일 때 어떤 조건에서 어떤 걸 지우면 되겠구나 하는 감이 대강 왔죠. 큰 진전이 온 순간이었습니다.

하지만 문제는 제가 babel을 AST로서 다뤄본 경험이 없다는 것이었어요. ‘어떤 구문일 때 어떤 조건에서 어떤 걸 지운다’ 라는 로직을 babel로 정확하게 짤 자신이 없었습니다. 그렇다고 babel을 하나하나 공부하고 싶지는 않았기에, ChatGPT에게 너라면 babel 어떻게 짤래? 를 물어보고, 설명도 해달라고 했어요. 그 코드와 설명, 그리고 공식문서도 조금씩 찾아보면서 babel에 대한 이해를 빠르게 높였습니다.

그러나 높아진 이해를 바탕으로 삭제할 코드와 남길 코드를 구분하는 로직을 아무리 잘 짜려고 해봐도 쉽지 않았습니다. 특히 두 가지가 어려웠어요.

  • 중첩된 if 문을 한번에 처리하려니 코드가 너무 복잡해진다.
  • 하나의 validator 함수가 다른 validator를 호출하고, 그게 또다른 함수를 호출하는데, 나는 결과적으로 아무런 부수효과가 없는 함수만 지우고 싶었다.

그런데…. 여기서 다시 한 번 깨달았습니다. 내가 또 ‘정답을 단번에’ 얻으려고 하는구나. 생각을 바꿔먹어야 했어요.

4차 시도: AST로 이렇게 리팩토링해봤어. 이 부분이 잘 안 되는데 너라면 이 다음에 어떻게 해볼래?

여기서부터는 일사천리였습니다. 비교적 단순한 로직으로 traverse를 한 번 돌리고, 결과물을 살펴보고, 전체가 아닌 ‘미진한 부분’ 만 ChatGPT에게 들고 가서 처리하는 방법을 물어보고(e.g., 이건 보존하고 저건 삭제하고 싶은데 어떻게 짜면 되겠냐), traverse를 개선해서 다시 돌려보는 걸 반복했습니다. 제 babel 코드가 급격하게 좋아졌죠.

그러고도 미진한 부분이 있었지만, 'traverse를 여러 번 한다'는 아이디어를 이용해 빠르게 코드 양이 줄어들었습니다. 그래서 마지막에는 코드를 눈으로 확인하며 손으로 마무리했어요. 어차피 남은 코드가 별로 많지 않았으니까요.

결과

ChatGPT와 협업하여 진행한 긴 리팩토링을 끝내고 나서 무척 뿌듯했습니다. 구체적으로는 이런 결과물들을 얻었어요.

제품 입장

  • 18,500줄 짜리 코드가 1,335줄이 되고, 메인 청크 번들 크기는 약 7.8% 감소
  • 초기 로딩에 필요한 JS 파일 크기가 줄어들고, 로직도 줄어들면서 초기 로딩 속도가 소폭 향상됨

내 입장

  • 길고 복잡한 레거시 코드를 AST로 리팩토링해본 경험과 자신감을 얻음
  • 대부분의 복잡한 문제를 AI + 코드 + 인간 이라는 3자간 협업을 통해 효과적으로 해결할 수 있겠다는 자신감을 얻음

이 마지막 항목이, 바로 이 글을 쓰게 된 계기입니다.

맺으며

글을 쓰면서 작년 1월에 본 이 트윗이 생각났습니다.

작년과 달리, 이제는 이 말에 동의하지 않습니다. 사람들이 단순하게 AI를 ‘이용’만 한다면 그 변화가 아주 크지는 않을 거라고 생각하기 때문입니다. 하지만 AI와 제대로 협업할 줄 아는 사람들은… 많은 인간 노동력을 대체할지도 모르겠습니다. 제가 말하는 '제대로 된 협업'은 결국 이런 겁니다.

  1. AI가 잘 하는 일, 코드가 잘 하는 일, 인간이 잘 하는 일이 무엇인지 이해한다.
  2. 내가 풀려는 문제를 분석해서 AI/코드/인간이 잘 하는 영역을 구분한다.
  3. AI가 첫 코드를 잘 만들 수 있게 도와주고, 그 코드를 작게 실행해보면서 AI와 함께 개선하고, 중간중간 + 마지막에 인간이 하기 더 쉬운 건 내가 직접 한다.

저는 이걸 몸으로 깨달으면서 AI를 대하는 시각에 거대한 변혁이 일어났습니다. 이후에 ChatGPT를 훨씬 더 유용하게 써먹게 됐고요. 좋은 AI 기반 제품은 모두 명시적이든 암묵적이든 이 형태를 가지고 있을 거라고 생각합니다. MediaCAT이 추구하는 바 또한 이와 유사해요.

  • AI: 한 언어의 자막을 다른 언어의 자막으로 기계번역
  • 코드: AI가 이해하고 작업하기 쉽게 프리프로세싱, 인간이 이해하고 작업하기 쉽게 포스트프로세싱
  • 인간: 기계번역된 결과를 최종 검토하고 수정, 이 과정도 AI와 협업하여 더 쉽게 함

기존에 ChatGPT에게 ‘단번에 정답을’ 얻으려다가 실망하셨던 분들은 이 3자간 협업 모델을 한번 시험해보세요. 생산성에 놀라운 변화를 느끼실 거라고 확신합니다.