← 블로그

AI 시대의 마이그레이션, 2.5주의 기록 (2) — AI에게 맡겨봤더니

2026-05-21

AI마이그레이션NB2BClaude개발

진짜 흥미로운 이야기

지난 글에서 마이그라는 일 자체에 대해 배운 5가지를 정리했습니다. 옮기기는 옮기기일 뿐 / 공존 기간 경계 / 청소는 별도 sprint / 외부 룰은 강도 조절 / 비슷한 시스템은 묶음 머지 — 이런 원칙들이었지요. 다만 그게 다가 아니었습니다. 이번 2.5주의 마이그가 다른 마이그와 결정적으로 달랐던 점이 있었거든요. AI 에이전트(Claude Code)를 옆에 두고 했다는 점.

이전 디자인 회고에서 *“Claude는 훌륭한 도구이지만, 알아서 다 해주지는 않는다”*고 정리했었습니다. 이번 코드 마이그에서는 그 명제가 더 분명한 모양으로 드러났습니다. 코드를 옮겨 달라고만 하면 알아서 옮겨줄 줄 알았던 비개발자 출신이 그제서야 알게 된 것들이 있습니다.

이 글은 AI에게 마이그를 맡길 때 반드시 알아두면 좋은 4가지를 정리한 기록입니다. AI 에이전트로 마이그를 진행하시는 분께 가장 도움이 될 부분이라고 생각합니다.


교훈 1 — AI에게 코드를 옮기게 시키면 옛 코드를 읽지 않고 추론합니다

이번 마이그에서 가장 충격적이었던 발견입니다. AI 활용 마이그를 한다면 이 한 가지가 가장 중요합니다. 상황은 이렇습니다. 마이그 작업의 90%는 옛 코드를 새 모듈로 옮기는 단순 작업입니다. AI 에이전트에게 *“이 함수를 새 파일로 옮겨 줘”*라고 시키면 잘 해줄 것 같죠. 해주기는 합니다. 그런데 정확히 해주지는 않습니다.

문제는, AI가 원본 코드를 정확히 읽지 않는다는 점이었습니다. 대신 유사한 패턴을 기억에서 떠올려 추론해서 새 코드를 만듭니다. 변수 이름을 추론합니다. 데이터 형식(배열인지 객체인지)을 추론합니다. 함수가 받는 인자의 개수와 순서를 추론합니다. 시간대 처리 방식까지 추론합니다. 결과: 그럴듯하지만 미묘하게 다른 코드가 만들어집니다. 빌드는 통과합니다. 화면도 떠 있는 것처럼 보입니다. 그런데 데이터가 이상한 곳에서 어긋납니다.

저희가 겪은 사례 몇 가지:

  • 함수가 받는 인자가 3개였는데, AI가 2개로 추론. 라이브에서 표시되는 값들이 어긋남.
  • 데이터가 배열 형식이었는데, AI가 객체 형식으로 추론. 표시 영역이 통째 빈칸.
  • 시간을 한국 시간대로 처리해야 했는데, AI가 기본 UTC로 처리. 하루씩 어긋남.

각각 발견까지 며칠씩 걸렸습니다. 자동 검증은 모두 통과한 상태로요.

해결책 한 줄: 마이그 작업 전, AI에게 옛 코드의 본문 + 그 함수를 호출하는 모든 곳의 데이터 형식 정의를 전부 읽으라고 명시 의무화합니다. “추론 금지, 추측 금지. 옛 코드를 직접 읽고 그 결과만 옮겨라.” 이 규칙을 적용하기 에는 18개 PR 중 추정 사고 5건 발생. 적용 에는 같은 18개 PR 중 추정 사고 0건. 측정 가능한 효과였습니다.

배운 것: AI는 생성에는 강하지만 문맥 정확도에는 약합니다. 마이그 같은 정확한 옮기기 작업에서는 AI가 왜 그렇게 옮겼는지를 추적할 수 있어야 합니다. *“유사 패턴으로 추론했다”*는 답이 나오면 그 결과를 신뢰하지 마세요. 옛 코드를 직접 읽고 그 결과만 옮기게 강제하세요. 이 교훈은 AI 없이 사람이 직접 마이그하는 경우에도 일부 적용됩니다. 기억으로 옮기는 것과 원본을 직접 보고 옮기는 것의 정확도 차이는, 사람도 큽니다.


교훈 2 — 빌드 통과는 코드 정합성만 검증합니다. 기능 동작은 따로 확인하세요

마이그하다 보면 점점 자동 검증을 신뢰하게 됩니다. “테스트 247개 통과, 타입체크 0 에러, 빌드 6.24초” 라는 출력을 보면 작동한다고 믿게 되죠. 작동 안 했습니다. 저희 경우, 한 번은 다음 같은 한 줄이 새 코드에 추가됐습니다:

const PROMPT = `... 별도 `extras.academy` 키로 분리.`;

비개발자 입장에서는 그냥 평범한 한 줄로 보이지만, 컴퓨터 입장에서는 작은 문법 오류가 들어 있습니다 — 따옴표 처리 실수 한 글자. 컴퓨터는 *“여기서 무엇을 해야 할지 모르겠다”*며 그 파일 전체를 처리하지 못하고 멈춰버립니다. 결과: 라이브에서 앱이 통째로 안 뜹니다. 그런데 자동 검증은 모두 통과한 상태였습니다. 이유는 각 검증 도구가 검사하는 영역이 한정적이기 때문입니다:

  • 단위 테스트는 새 React 모듈만 검사 — 옛 코드 파일은 대상 외
  • 타입체크는 새 코드의 형식 정의만
  • 린터는 새 코드의 스타일만
  • 빌드는 옛 코드 파일을 그대로 복사만 (검증 X)

즉, 옛 코드 파일에 어떤 문법 오류가 추가돼도 4개의 자동 검증은 모르고 통과시킵니다. 해결: 옛 코드 파일에도 문법 검사를 별도로 거는 5번째 검증축을 추가했습니다. 그리고 항상 마지막에 실제 환경에서 한 번 화면을 띄워 보는 수동 확인을 의무화했습니다.

배운 것: 자동 검증 도구들이 무엇을 검증하지 않는지를 명확히 파악하세요. *“X가 통과했다 = Y도 안전하다”*라는 추론이 항상 맞지는 않습니다. 도구의 강점과 사각지대를 둘 다 알아야 합니다. 그리고 항상 마지막엔 사람이 한 번 클릭해 봅니다. 빌드 통과 ≠ 기능 동작. 이 차이가 AI 시대에는 더 위험합니다. AI가 모든 자동 검증을 통과시키는 코드를 만들어내기는 점점 잘하지만, 그게 실제로 잘 도는 코드인지는 다른 문제이기 때문입니다.


교훈 3 — 룰은 강제로 채워야 하는 박스가 없으면 안 지켜집니다

마이그 동안 저희는 약 15개의 룰을 신설했습니다 — “데이터 키 인벤토리 작성”, “데이터 형식 검증”, “테스트 mock 정합 확인” 같은 것들. 문제는, 룰을 신설해도 다음 sprint에 적용 안 됐다는 것입니다. 매번 같은 종류의 결함이 반복됐죠.

이유는 단순합니다. 룰이 문서로만 존재하면 사람이 읽지 않습니다. 읽었다 해도 지키지 않습니다. 기억이 안 납니다. 바쁘면 건너뜁니다. 해결: 룰을 PR 설명란의 체크리스트로 강제. 머지 전에 각 체크박스를 손으로 직접 채우지 않으면 머지 안 됨.

## 데이터 키 인벤토리
- [ ] 옛 코드의 데이터 키 전수 검색 결과 첨부
- [ ] 새 코드가 동일 키로 접근 (라인 단위 확인, 이름 변경 0건)
- [ ] 실 데이터로 화면 렌더링하는 테스트 1건 이상 추가

박스가 비어 있으면 머지 보류. 이렇게 강제로 의식하게 하는 장치가 생기자 룰 위반 사고가 크게 감소했습니다. 핵심은 룰 자체보다 룰을 지키게 하는 메커니즘입니다. 사람의 기억과 의지에 의존하지 마세요. PR 템플릿, 머지 자동화, CI 게이트 — 어떤 방식이든 사람이 명시적으로 채워야 통과하는 강제 장치를 만드세요.

배운 것: *“룰을 신설한다”*는 행위 자체로는 아무것도 바뀌지 않습니다. 룰이 지켜지는 환경을 만들어야 비로소 효과가 나타납니다. 룰 위반이 반복되면 룰을 더 추가하지 말고 지키게 하는 장치를 점검하세요. 이 점은 AI 시대에 더 critical합니다. AI에게 *“이 룰을 지켜라”*라고 prompt에 넣어도 프롬프트가 길어질수록 잘 지키지 않거든요. 결국 사람이 직접 박스를 채우는 forcing function이 가장 안전한 안전망이라는 걸 이번에 배웠습니다.


교훈 4 — AI에게 글(프롬프트)을 옮기게 시키면 슬쩍 줄여 씁니다

마지막 교훈입니다. 교훈 1과 비슷한 본성의 결함이지만 다른 영역에서 발생합니다. 상황은 이랬습니다. 옛 코드에 길고 정교한 AI 프롬프트(LLM에게 보내는 지시문)가 들어 있었습니다. 80줄짜리 한국어 가이드. 몇 달에 걸쳐 시행착오로 다듬은 결과물. 이걸 새 모듈로 그대로 옮겨야 했습니다.

AI에게 시켰습니다: “이 프롬프트를 새 파일로 옮겨라.” 결과: 80줄이 65줄로 줄어 있었습니다. AI가 *“중복되는 표현”*을 정리했습니다. 그럴듯한 문장으로 줄였습니다. 자기 추론으로 멋있는 한국어를 만들었죠.

문제 1: AI 프롬프트는 문장 하나의 미묘한 표현이 출력 품질에 영향을 줍니다. AI가 *“정리”*한 부분이 저희가 몇 달 동안 다듬은 핵심일 수 있습니다. 문제 2: 줄어든 게 명백하지 않으면 발견조차 못 합니다. 65줄도 80줄도 한국어 가이드인 건 마찬가지입니다. 차이를 어떻게 알아챌까요.

해결은 글자 단위 비교 검증이었습니다. 80줄이면 80줄. 81줄도 79줄도 안 됨. 변수 보간이 새로 끼어들지 않았는지 확인. 따옴표 처리 일치. 결정적 코드가 줄 수를 세고, AI는 그 검증을 통과해야만 OK. 이 검증을 통과한 후로 프롬프트 옮기기 사고는 0건이었습니다.

배운 것: AI는 생성에 최적화돼 있습니다. 재생산이 아닙니다. 동일한 입력에 동일한 출력이 보장돼야 하는 작업(텍스트 옮기기, 키 검색, 정규식 매칭, 길이 계산)은 결정적 코드에 맡기세요. AI는 창의·craft·judgement가 필요한 영역에서만 쓰세요. 이 경계가 흐려지면 어디서 결함이 들어왔는지 추적할 수 없습니다. AI가 미세하게 다른 답을 낼 때마다 그게 의도된 차이인지 사고인지 알 수가 없거든요.


마치며 — 도구의 사각지대를 알기

지난 글에서 마이그라는 일 자체에 대해 배운 5가지를 정리했다면, 이번 글에서는 AI에게 그 일을 맡겼을 때 일어나는 일에 집중했습니다. 요약하자면 네 가지입니다.

  1. AI는 옛 코드를 안 읽고 추론한다. 명시적으로 직접 읽으라고 강제해야 한다.
  2. 빌드 통과 ≠ 기능 동작. 자동 검증의 사각지대를 의식하고 마지막엔 사람이 클릭해 본다.
  3. 룰은 강제로 채워야 하는 박스가 없으면 안 지켜진다. AI에게 prompt로 룰을 박지 말고 사람이 박스 채우게 한다.
  4. AI에게 글을 옮기게 시키면 슬쩍 줄여 쓴다. 결정적 작업은 코드, 창의는 AI.

이전 디자인 회고에서 짚었던 한 줄이 다시 떠오릅니다. Claude는 훌륭한 도구이지만, 알아서 다 해주지는 않는다. 빠르게 만들 수 있는 시대일수록, 내가 책임을 짊어진다는 사실은 더 분명해집니다. 비개발자 출신이 AI 에이전트와 함께 제품을 만들어 가는 길에서, 가장 자주 배워야 하는 한 가지가 있다면 그건 도구의 사각지대를 알기인 것 같습니다. 도구가 잘하는 영역에서는 마음 놓고 의지하되, 못하는 영역에서는 직접 들여다보는 안전장치를 준비해 두는 일.

이번 마이그 cycle에서 교훈 1 — AI에게 직접 읽으라고 명시적으로 강제하기 — 한 가지만으로도 사고의 절반은 사라졌습니다. 이건 비슷한 길을 가시는 분께 가장 먼저 권하고 싶은 한 가지입니다. 2.5주의 시행착오가 누군가의 한 시간이라도 줄여 드린다면 — 그것대로 의미는 충분합니다.


그리고 한 가지 고백

1편에서 왜 React인가를 짧게 설명드렸지만, 사실 마이그를 끝낸 지금 한 번씩 다른 생각이 듭니다. 처음부터 React로 시작했더라면 더 좋았을 텐데, 라는 생각이요. 다만 바이브코딩을 처음 시작할 무렵에는 그런 선택지가 있다는 사실 자체를 몰랐습니다. 왜 처음부터 React로 시작하지 않았느냐고 — 스스로에게도, 그때 옆에 있었던 AI에게도 — 한참 따져 봤습니다.

흥미로운 건, 그때의 AI도 처음부터 React를 권하지는 않았더라고요. 그러니 이번 마이그는 어떻게 보면 AI의 첫 결정에만 의존했을 때 빠질 수 있는 함정 하나에 잠시 빠졌다가, 나중에 따져 보고 되돌아 나온 사례이기도 합니다. AI에게 맡길 일AI에게 따져 볼 일은 분명히 다르다는 것을, 이번에 한 번 더 배웠습니다.

그래도 지금 돌아보니, 그 시간이 그저 시행착오의 비용만은 아니었던 것 같습니다. 개발자 분들이 짧지 않은 흐름 속에서 얼마나 빠르게 발전하면서 고생해 왔는지직접 따라가 본 시간이기도 했더라고요. 컴퓨터를 쓰기 위해 PC의 작동 원리를 꼭 알 필요는 없습니다. 하지만 그 흐름을 알고 있으면, 문제가 생겼을 때 직접 손을 보기도, 원하는 바를 위해 직접 손을 쓰기도 한결 수월해집니다. 이번 마이그가 저에게 남긴 이 그것이었습니다.


이 글에 대한 반응

읽으신 느낌을 표시해보세요 (본인 브라우저에 저장됩니다)

공유하기

주변에 알리고 싶다면

의견·질문이 있다면

아직 댓글 시스템은 없습니다. 메일로 보내주시면 답장드립니다.

✉️ 메일 보내기

메일 작성창이 뜨지 않는다면? 사이트에서 바로 작성