바이브 코딩, 주식 거래 관리 앱 개발 ④ — “바이브”의 한계

지난 글에서 주식 거래 관리 앱을 만드는 과정을 정리했습니다. 특히 시스템이 외부 세계와 연결된 후로 외부 시세를 이용해서 가치 평가가 가능해졌고, 증권사에서 거래내역을 직접 가져오고, 집 밖에서도 접속할 수 있게 되면서, 실제로 도움이 되는 시스템으로 매일 사용하는 도구가 되었습니다.

그런데 매일 사용하다 보니 초기 개발 단계에서는 보이지 않던 문제점들이 보이기 시작했습니다. 특정 계좌의 수익률이 비정상적으로 크게 나오거나, 화면을 열 때마다 반응이 느려지거나, 같은 기능인데 화면마다 동작이 미묘하게 다른 것을 발견했습니다. 또한 문제점들을 바로잡는 과정에서 바이브 코딩의 한계를 명확하게 확인할 수 있었습니다.

이번 글에서는 그동안 한 일과 함께 제가 생각한 바이브 코딩의 한계와 원인, 그리고 대책까지 정리해 보았습니다.


목 차


발견된 이슈 및 해결 과정

어떤 시스템이든 개발 단계에서 예측한 검증 과정이 실제 상황의 모든 문제점을 커버할 수는 없습니다. 크게 네 가지 관점에서 이슈들이 발생했고, 각 이슈에 대한 해결 과정은 아래와 같습니다.

데이터 정합

가장 먼저 발견된 문제점은 숫자의 정확성이었습니다.

타사에서 주식을 옮겨오면 원본 파일에는 “타사대체입고” 같은 이름으로 남습니다. 기존에는 이것을 매수의 일부로 취급하고 있었는데, 실제로는 돈을 주고 산 것이 아니므로 매수금액과 실현손익이 왜곡되는 것을 발견했습니다. 그래서 주식입고주식출고라는 거래구분을 따로 만들었습니다. 보유 수량과 장부가에는 반영하되 매수/매도 금액과 실현손익에서는 제외하고, 수익률 계산에서는 입금/출금과 같은 외부 현금흐름으로 다루도록 했습니다.

증권사 API의 날짜 문제도 있었습니다. 과거 거래를 조회해 보니 API의 날짜 필드가 실제 체결일이 아니라 거래 내역이 정산된 날짜인 경우가 있었습니다. 특히 같은 날 일어난 거래에 대해 매도-매수 순으로 반환을 해주는데, 같은 종목을 거래한 경우 보유 수량이 꼬일 수 있는 상황이었습니다. 실제 과거 데이터를 하나하나 대조해 확인한 뒤, 체결일 필드를 별도로 받아 계산 기준으로 삼고, 표시 순서와 계산용 순서를 분리했습니다.

해외 거래에서는 금액이 0으로 들어오는 문제가 발견됐습니다. 해외 매매 데이터의 원화 금액 필드가 0이었고 실제 값은 외화 필드에 들어 있었습니다. 외화 거래 금액과 통화를 그대로 보존하도록 수정했습니다.

데이터 관련 수정들은 계산 로직이 바뀌는 부분으로 평가금액과 수익률 등을 정확하게 계산하는 데 필수적인 것들이었습니다.

재계산 시점 조정

운영 중 성능과 관련하여 가장 문제가 됐던 부분입니다. 화면을 조회할 때마다 복잡한 계산을 다시 하고 있었는데, 개발 초기에 “한 번 계산한 것은 다시 계산하지 않는다”라는 원칙으로 계산한 값을 저장해 두도록 요구사항을 전달했으나, 세션을 이어가는 과정에서 해당 부분이 누락되었고, 매번 재계산을 하고 있었습니다.

데이터가 적을 때는 속도를 인지하지 못했으나, 실제 운영을 하면서 각종 통계기능까지 추가하고 나니 성능이 떨어지는 것을 체감할 수 있었고, 재계산이 길어지면 DB에 락이 걸려 다른 작업까지 막혔습니다. 원인을 따라가 보니 업로드, 삭제, 거래내역 조회 등 여러 경로에 데이터 재계산 로직이 숨어 들어가 있었습니다.

그래서 통계 데이터 재계산과 관련된 원칙을 명확하게 정리했습니다. 먼저 각종 조회 화면은 기존에 계산된 데이터를 읽어올 뿐 절대로 계산을 다시 하지 않습니다. 그리고, 데이터가 입력되거나 수정된 경우 “재계산 필요”라는 플래그를 통해 사용자에게 상황을 알리고 실제 재계산은 사용자가 명시적으로 요청할 때만 실행하도록 했습니다.

결과적으로 관련된 성능 이슈는 해결할 수 있었고, 보다 쾌적한 사용 환경이 만들어졌습니다.

자산 분류 기능 추가

기존 대시보드는 지금 얼마를 가지고 있고, 얼마나 벌었나를 보여주었습니다. 그리고 보다 실용적인 주식 관리 시스템이 되려면 자산의 분포를 볼 수 있는 기능도 필요했습니다. 국내와 해외, 유가증권과 ETF의 비중 같은 것들입니다. 이는 추후 금융 관련 소득이나 세금을 계산하는 기능으로 확장될 예정입니다.

그래서 각 종목마다 상장시장, 상품유형, 지역 정보를 추가로 저장하고, 화면에는 국내 유가증권, 국내 ETF, 국내상장해외ETF, 해외 유가증권, 해외 ETF 등으로 표시하게 했습니다. 분류 정보는 별도 저장소에 두고 기존 거래와 종목, 스냅샷 계산은 건드리지 않았습니다. 이 분류 위에 기준일 자산 구성, 기간별 배당 구성, 연도별 배당 요약 화면을 추가했고, 배당 주기와 종목 식별자를 공공데이터로 채우는 메타데이터 관리도 더했습니다.

사용성 개선

계좌가 늘면서 원하는 계좌만 선택해서 보기 위한 필터기능이 불편해졌습니다. 여러 개의 드롭다운에서 원하는 조합을 찾는 일이 점점 번거로워져, macOS Finder의 열 탐색처럼 사용자, 소유자, 증권사, 국내/해외, 일반/연금 순서로 왼쪽에서 오른쪽으로 좁혀가는 구조로 필터를 다시 만들었습니다. 왼쪽을 바꾸면 오른쪽 선택만 초기화됩니다. 이 밖에 증권사 인증이 만료됐을 때 화면 안에서 바로 갱신하는 버튼, 삭제 요청과 취소와 완전 삭제의 상태 정리 같은 개선도 있었습니다.

이런 개선은 릴리즈 노트에 한 줄로 남지만, 매일 쓰는 사람의 마찰을 가장 크게 줄입니다.


바이브 코딩의 한계

여기까지 진행한 일들을 되짚어 보면 공통점이 있습니다. 대부분이 바이브 코딩으로 빠르게 구현한 부분에서 발생한 오류를 바로잡는 일이었다는 점입니다. 그 과정에서 제가 느낀 바이브 코딩의 한계는 크게 세 가지입니다.

첫째, 동작 여부와 옳고 그름은 다릅니다.
현물 입출고를 매수로 처리하던 코드는 정상적으로 동작했고 테스트도 통과했습니다. 체결일 대신 정산일로 계산하던 코드도 마찬가지입니다. 그러나 숫자는 틀려 있었습니다. AI가 작성한 코드는 테스트 범위 내에서만 옳습니다. 해외 계좌의 0원 금액처럼, 테스트에 없던 현실은 실제 데이터를 가져와 대조하기 전까지 드러나지 않았습니다. 그리고 이 필드가 체결일인지 정산일인지 같은 도메인의 미묘함은 API 문서를 읽는 것만으로는 알 수 없었습니다.

중요한 것은 바이브 코딩의 특성상 도메인 지식을 전부 알지 못한 채로 구현을 시작하고, 잘 동작하는 결과를 보면 옳게 구현되었다고 착각을 하게 됩니다. 하지만 동작 여부와 옳은 구현은 전혀 다른 문제입니다.

둘째, 빠른 구현, 기술 부채도 빠르게 쌓입니다.
거래내역, 계좌별 요약, 자산 통계, 대시보드는 모두 비슷한 조회 필터를 씁니다. 그런데 화면을 하나씩 빠르게 만들다 보니 같은 필터가 화면마다 조금씩 다르게 중복 구현됐습니다. 사용자와 계좌를 고르는 같은 일인데 화면마다 동작이 미묘하게 달랐고, 하나를 고치려면 네 군데를 고쳐야 했습니다. 여러 번의 리팩토링을 거쳐 공통 필터 구조 하나로 통합하고서야 바로잡을 수 있었습니다. 재계산도 같은 패턴이었습니다. 기능을 붙일 때마다 재계산을 하는 로직이 각 경로에 개별로 심어진 결과였습니다.

AI는 “이 화면에 필터를 붙여줘”라는 요청을 매번 성실하게 수행했습니다. 그러나 “이미 다른 화면에 같은 것이 있으니 공통화하자”는 판단은 하지 않습니다. 요청 단위로는 전부 성공인데, 시스템 단위로는 기술 부채가 쌓입니다. 비슷한 일은 기존 모듈을 먼저 찾아 확장한다는 가드레일을 명문화했지만, 이 부분은 매번 신경써야 하는 부분입니다.

셋째, 조용하게 오염됩니다.
같은 계좌에 API 연결이 중복으로 만들어져 데이터가 이중으로 들어간 일이 있었고, 특정 거래가 잘못된 구분으로 분류된 채 운영되던 일도 있었습니다. 모든 작업은 “성공”으로 끝났습니다. 오류 메시지도, 실패 로그도 없었습니다. 숫자의 흐름이 이상한 것을 눈치채고 숫자를 확인한 후에야 문제점을 발견할 수 있었습니다.

결국 바이브 코딩의 빠른 구현 속도는 분명합니다. 모르는 영역도 만들 수 있게 해줍니다. 그러나 그 속도로 만든 것이 옳은지, 겹치지 않는지, 오염되지 않았는지는 AI가 알려주지 않습니다.


AI에 대한 인식의 문제

사실, AI는 성실하게 제 요구사항을 수행했습니다. 그렇다면 왜 위와 같은 한계를 드러낸 걸까요? 결국 문제는 AI를 사용하는 사람에게 있다고 생각합니다. 제가 이 시스템을 바이브코딩으로 구현하면서 경험한 과정에 따르면, AI에 대한 인식의 변화가 가장 큰 이슈인 것 같습니다.

시작할 때는 AI를 도구로 대했습니다. 요구사항을 최대한 자세히 정리해서 주고, 구현 기준을 문서로 정리하고, 결과를 검증했습니다. 그런데 AI와 협업을 지속해 가면서 제 인식이 조금씩 바뀌었습니다. AI와의 대화가 유창하고, 맥락을 이해하는 것처럼 보이고, 지난번에 잘 처리했으니 이번에도 알아서 할 것 같습니다. 어느 순간부터 사람 동료에게 하듯 말하고 있었습니다.

예를 들면 “이번 XX 기능은 그거 지난번처럼 처리해줘”라고 말합니다. 그거가 무엇인지, 지난번이 언제인지 명시하지 않습니다. 요구사항 정리를 생략하고 “이 화면이 좀 이상한데 고쳐봐”라고 결론만 던지기도 합니다. 그리고 결과를 확인하는 대신 “잘했겠지”라고 넘어가는 경우도 있었습니다.

사람 동료라면 통하는 방식입니다. 사람은 맥락을 축적하고, 모르면 되묻고, 이상하면 이상하다고 말합니다. 그런데 AI는 다릅니다. 세션이 바뀌면 기억이 없고, 문서에 없는 맥락은 존재하지 않으며, 모호한 지시를 그럴듯한 추측으로 채워 넣습니다. 추측이 틀렸을 때만 위험한 것이 아닙니다. 추측이 맞으면 “역시 알아듣는구나”라는 인식이 굳어져 다음번에는 맥락을 더 줄이게 됩니다. 틀렸을 때는 앞서 본 조용한 오염이 됩니다.

왜 이렇게 흘러갈까요. 몇 가지 이유가 있다고 생각합니다.

유창함의 착시입니다.
말이 사람 같으면 이해도 사람 같을 것이라고 믿게 됩니다. 사람을 상대로는 대체로 맞는 추론이라 뿌리가 깊습니다. 최근 PNAS에 실린 연구에 따르면, 지금 세대의 언어 모델은 진짜 공감이나 사회적 이해 없이도 사람과 구별하기 어려울 만큼 설득력 있는 대화를 구사하며, 연구진은 이런 시스템을 “의인화된 대화 에이전트”라고 부르면서 그 위험성을 함께 경고합니다. 유창함은 실제 능력입니다. 다만 유창하다고 해서 맥락을 기억하거나 스스로 판단하고 있다는 뜻은 아닙니다.

성공 경험의 누적입니다.
적게 설명해도 잘 처리된 경험이 쌓이면 “다음엔 조금 덜 설명해도 되겠지”가 반복되고, 맥락을 조금씩 덜 제공하게 됩니다. 실패가 바로 드러나면 고쳐지겠지만, 오류는 조용히 쌓이다 한참 뒤에야 발견되므로 바로잡을 계기가 생기지 않습니다. 자동화 시스템 연구에서 오래 확인된 현상이기도 합니다. 자동화 연구자 파라수라만과 만자이의 통합 연구에 따르면, 자동 시스템의 결과를 독립적으로 검증하지 않고 수용하는 경향은 초보자만이 아니라 전문가에게도 나타나며, 단순한 연습으로는 극복되지 않습니다.

정리 비용의 회피입니다.
요구사항을 정리하는 일은 귀찮고, 개발이 급할수록 생략의 유혹이 커집니다. 말로 하면 되는데 굳이 문서로 쓸 필요가 있나 싶어집니다. 그렇게 문서화가 조금씩 뒷전으로 밀립니다.

여기서 한 가지 역설적인 생각도 하게 됩니다. 지금까지는 경험 많은 엔지니어나 리더가 AI를 더 잘 쓸 것이라는 의견이 있었습니다. 요구사항을 정리하고, 위임하고, 검증하는 것은 리더십의 기술이니까요. 이 시리즈의 앞선 글들도 사실 그 가설의 증거였습니다. 그런데 AI에 대한 의인화를 일으키는 것이 바로 그 경험 때문이라면 어떨까요.

사람과 협업한 세월이 길수록, 유창하게 말하는 상대를 맥락을 공유하는 동료로 대하는 인식도 강해집니다. 즉 불필요한 인식이 그만큼 많은 셈입니다. 사람과의 협업 경험이 적고, 처음부터 AI를 상대로 일을 시작한 젊은 세대는 오히려 이런 인식의 변화가 적을 것 같습니다. 그들에게 AI는 처음부터 세션이 리셋되고, 맥락을 줘야 하고, 검증해야 하는 도구입니다.

물론, 빠르게 오류를 인식하는 능력은 다양한 경험에서 나옵니다. 수익률이 이상하다, 이 날짜가 실제와 다르다는 의심은 도메인을 아는 사람만 할 수 있고, 위에서 다룬 여러 문제들도 결국 사람이 발견했습니다. 유리한 것은 세대의 문제라기보다는 AI시대에 꼭 필요한 역량의 조합일 것입니다. 판단과 검증의 능력을 갖추되, AI에 대한 의인화를 하지 않는 능력이 필요합니다.


인식 되돌리기

만약 이러한 인식의 변화가 자연스러운 심리 과정이라면, 의지로 막기는 어렵습니다. 정신을 차리자고 다짐하는 것으로는 부족합니다. 필요한 것은 인식을 되돌리기 위한 장치입니다.

저맥락을 강제하는 문서 체계.
협업 규칙, 버전별 요구사항과 설계와 회고, 인수인계 문서 등 문서를 통해서 “그거 알잖아” 대신 “문서의 이 기준대로”라고 요구해야 합니다. 기존에는 문서가 AI를 위한 메모리라고 했는데, 문서는 AI만을 위한 것이 아닙니다. 사람이 고맥락으로 흘러가는 것을 막는 장치이기도 합니다. 문서화하는 과정에서 암묵지를 최소화하고 맥락을 명시할 수밖에 없기 때문입니다.

정답이 있는 검증.
기대값이 분명한 테스트와 기준 출력물을 잘 정의해야 합니다. 단순히 “잘했겠지”라는 신뢰를 “확인했다”라는 사실로 바꿉니다. 개발 내용이 축적되고 기능이 많아질 때마다 이어진 방식이고, 위의 오류들을 잡을 때도 수정 전후를 판정한 것은 결국 이 장치였습니다.

세션의 리셋을 받아들이는 절차.
작업 내용을 다른 세션으로 넘길 때마다 인수인계 문서를 갱신합니다. 이 절차를 통해 “AI는 기억하지 않는다”는 사실을 스스로 알아차려야 합니다.

멈추는 버전.
결과가 이상하면 새 기능 추가를 멈추고 원인을 추적해야 합니다. 기능 강화는 절대로 스스로 일어나지 않으므로, 기능을 쌓지 않는 버전, 리팩토링 버전을 의도적으로 만들어가면서 부채들을 정리해야 합니다.

사실 업계가 같은 방향으로 수렴하고 있습니다. 요즘 AI 개발에서 자주 언급되는 하네스(harness)와 루프(loop) 같은 기법들입니다. 하네스는 AI를 신뢰의 대상이 아니라 검증의 대상으로 두고, 기계적 검증으로 경계를 강제합니다. 에이전트 루프의 핵심도 실행이 아니라 검증이 루프 안에 박혀 있다는 데 있습니다. 사람이 매번 확인하겠다는 의지를 내는 것이 아니라, 루프가 돌 때마다 검증이 자동으로 일어납니다. 사람의 의지를 구조로 대체한 것입니다. 이러한 방향성 자체가 AI를 사람처럼 신뢰하면 안 된다는 것을 집단적으로 학습한 결과라고 볼 수 있습니다.


맺음말

네 편에 걸쳐 하나의 시스템이 자라는 과정을 정리해 왔습니다. 자동화에서 시작해 서비스가 되고, 외부와 연결되고, 이번에는 운영을 거치며 안정적인 시스템으로 발전했습니다.

이번 단계에서 확인한 것은 바이브 코딩의 장점과 한계가 사실은 하나라는 점입니다. 엄청나게 빠른 구현 속도는 분명한 장점입니다. 잘 모르는 영역도 쉽게 만들 수 있게 해줍니다. 그러나 동작하는 것과 옳은 것은 다르고, 빠른 만큼 부채가 쌓이며, 아주 조용하게 오염됩니다. 이러한 바이브 코딩의 한계를 명확하게 이해하고, AI를 사람 동료가 아닌 도구로서 인식할 때 바이브 코딩의 활용성을 극대화할 수 있습니다. 이를 위해 문서와 검증과 절차라는 시스템이 꼭 필요합니다.

속도는 AI가 만들지만, 신뢰는 시스템이 만듭니다.

ChulJoo Kim (김철주)


참고문헌

ckarch.kr © 2026 is licensed under CC BY-NC-SA 4.0 CC BY NC SA

댓글 남기기