AI는 당신의 코딩 약점을 숨겨주지 않습니다. 오히려 증폭시킵니다.
요약
AI는 코딩의 구문(Syntax) 문제를 해결해주지만, 개발자의 설계 결함이나 모호한 지식을 숨겨주지 않고 오히려 증폭시킵니다. AI는 사용자가 던진 질문을 실행하는 데는 탁월하지만, 올바른 설계를 위해 필요한 질문을 대신 던져주지는 않으므로 개발자의 비판적 사고와 설계 능력이 더욱 중요해졌습니다.
핵심 포인트
- AI는 구문 작성의 부담을 줄여주지만, 개발자의 논리적 허점과 모호함을 드러내는 돋보기 역할을 함
- AI 모델은 사용자가 요청한 명령을 수행할 뿐, 설계의 완성도를 높이기 위한 역질문을 던지지 않음
- AI가 생성한 코드는 겉보기에 완벽하고 타입 체크를 통과하더라도, 논리적으로는 완전히 잘못된 결과를 초래할 수 있음
- AI 시대의 코딩은 단순히 코드를 작성하는 것이 아니라, 정확한 질문을 던지고 생성된 결과물의 논리적 일관성을 검증하는 설계 능력이 핵심임
우리가 코딩을 배우던 시절에는 어셈블리(Assembly)로 시작했습니다. 그다음은 C, 그다음은 C++, Java, Python, 그 뒤에 나오는 어떤 구문(Syntax)이든 마찬가지였습니다. 새로운 언어를 배울 때마다 흥미로운 것을 작성하기 전에 지불해야 하는 새로운 세금과 같았습니다. 우리는 불평했고, 지불했습니다. 그것이 규칙임을 알고 있었습니다. 이제 우리는 AI를 배우고 있습니다. 재미있는 점은, 이제 구문(Syntax) 부분은 그리 중요하지 않다는 것입니다. AI는 당신이 타이핑하는 것보다 더 빠르게 코드를 작성합니다. (당신이 올바르게 타이핑하는 것보다 더 빠르게 말이죠. 제 코드를 보셨다면 아시겠지만, 이건 낮은 기준입니다.) 그래서 저는 이 AI라는 존재가 저에게 날개를 달아준 줄 알았습니다. 하지만 알고 보니 그것은 저에게 돋보기를 준 것이었습니다. AI는 제가 모르는 것을 숨겨주지 않습니다. 오히려 그것에 집중합니다. 제가 가진 모든 모호한 생각, 제가 그동안 교묘히 넘겨왔던 모든 지름길,
제가 필요했던 설계는 "이 저장소(repo)에서 의존성 업데이트(dependency update)의 생명주기(lifecycle)는 어떻게 되는가, 그리고 깨진 락파일(lockfile)이 정확히 어디를 통해 몰래 들어올 수 있는가"였습니다. AI는 첫 번째 질문을 도와주는 데에는 매우 기꺼이 응했습니다. 두 번째 질문에 대해서도 기꺼이 도와주었을 것입니다. 제가 단지 묻지 않았을 뿐입니다. 이것이 바로 아무도 말해주지 않는 AI와 함께 코딩할 때의 문제입니다. 모델은 당신이 가져온 질문을 실행하는 데 믿을 수 없을 정도로 뛰어납니다. 하지만 모델이 당신에게 질문을 던져주지는 않습니다. 질문을 던지는 것은 당신의 몫입니다. (기억하세요, 이것은 프로그래밍에서 더 쉬워져야 했던 부분입니다.) 코드 (또는: 빈 거래 목록 문제) 그다음 코드는 당신이 적어 내려간 설계와 일치해야 합니다. 그리고 바로 이 지점에서 AI는 창의력을 발휘합니다. AI는 한 줄 한 줄 보기에는 괜찮아 보이지만, 끝에 가서는 완전히 다른 숲으로 헤매어 버린 코드 더미를 만들어내는 것을 매우 즐거워합니다. 실제 사례를 하나 보여드리겠습니다. 저는 백테스트 엔진(backtest engine)을 위한 전략 템플릿을 생성하고 있었습니다. 그 전략은 롱 진입(entering long), 숏 진입(entering short), 그리고 포지션 종료(closing positions)를 지원해야 했습니다. 세 가지 상태(states)가 필요했죠. 결코 미묘한 작업이 아니었습니다. 결과물은 훑어봤을 때 올바르게 보였습니다. 함수들은 적절한 위치에 있었고, 타입(types)은 일치했으며, 명백한 악취(smells)도 없었습니다. 저는 그것을 프레임워크(framework)에 배포하고 백테스트를 실행했습니다. 엔터를 눌렀습니다. 진행 표시줄을 지켜보았습니다. 백테스트가 끝났습니다. 에러도 없었습니다. 경고도 없었습니다. 거래 목록(trades list): 비어 있음. 이 상황을 잠시 그대로 두겠습니다. 백테스트는 완료되었습니다. 단지 실제로 거래를 수행하지 않았을 뿐입니다. 저는 다시 돌아가 생성된 코드를 더 천천히 읽어보았습니다. 제가 발견한 것은 다음과 같습니다:
def check_open_conditions ( self ) -> tuple [ bool , bool ]: long_signal = self . cumsum [ 0 ] > 0 short_signal = False # <-- 이 부분 return long_signal , short_signal
모델은 "롱과 숏을 지원하라"는 말을 듣고, 자기만의 신경망(neural network) 안에서 이 전략이 아마도 롱 전용(long-only)일 것이라고 멋대로 결정한 모양입니다. 그래서 short_signal = False라고 하드코딩(hardcoded)하고 자기 할 일을 계속한 것입니다. 보기에는 괜찮았습니다. 컴파일도 잘 되었습니다. 타입 체크(type checks)도 통과했습니다. 반대 신호 종료 경로(reverse-signal exit path) 전체를 조용히 집어삼켜 버린 것입니다. (분명히 말씀드리지만, AI가 악의적으로 이런 행동을 한 것은 아닙니다.)
AI는 다른 모든 일을 할 때와 마찬가지로 똑같이 쾌활하고 자신만만하게 이 일을 해냈습니다. 바로 그 점이 상황을 더 악화시킵니다.) 두 번째 사례도 있었습니다. 해당 프레임워크에는 손절(stop-loss)과 익절(take-profit)을 위한 check_close_conditions() 메서드가 있었습니다. 생성된 서브클래스(subclass)는 이를 구현했습니다. 하지만 베이스 클래스(base class)는 이를 전혀 호출하지 않았습니다. AI가 기능의 앞부분만 연결해 두고 뒷부분은 조용히 누락시킨 것입니다. 마치 의자를 주문했는데, 완전히 조립된 상태로 배달되었지만 좌판(seat)만 있는 것과 같습니다. 다리도 없고, 등받이도 없습니다. 거실 바닥에 놓인 평평한 나무 원판일 뿐입니다. 기능적으로 의자인가요? 물론, 기술적으로는 그렇습니다. 이것이 바로 돋보기(magnifying glass)가 작동하는 방식입니다. 직접 손으로 코드를 작성했다면, 10분 안에 거래 내역이 비어 있다는 것을 발견했을 것이고 어떤 파일을 열어야 할지도 정확히 알았을 것입니다. 하지만 AI 버전은 아무런 경고가 뜨기 전까지 "성공적으로 실행됨, 거래 내역 0건" 단계까지 저를 그대로 끌고 갔습니다. 유일하게 도움이 되는 방법, 정말로 유일한 방법은 모델에게 자신이 작성한 내용을 조각조각 설명하게 하고, 진행하면서 하나씩 확인하는 것입니다. 그것은 느리고, 지루합니다. 제가 계속 건너뛰고 싶어 하는 부분이자, 건너뛰었다가 계속해서 대가를 치르게 되는 바로 그 부분입니다. 테스트(또는: 함수가 실행되었으니 작동한다): 테스트는 단순히 함수가 에러를 던지지 않고 실행되는지 확인하는 것이 아니라, 설계가 의도했던 것과 동일한 의도를 검증해야 합니다. 위의 빈 거래 내역 사례에서 바로 이 지점에서 문제가 발생했습니다. 백테스트(backtest)는 실행되었습니다. 에러도 발생하지 않았습니다. 만약 제가 "백테스트 중 예외(exception) 없음"을 단언하는 테스트를 작성했다면, 그 테스트는 통과했을 것이고 저는 우주의 열적 죽음(heat death of the universe)이 올 때까지 모든 포지션을 유지하는 전략을 배포했을 것입니다. 의도는 "이 전략이 진입하고, 청산하며, 종료된 거래 목록을 생성한다"는 것이었습니다. 실제로 필요한 테스트는 "거래 목록이 비어 있지 않으며, 각 거래는 진입 타임스탬프와 청산 타임스탬프를 모두 가지고 있다"에 더 가까운 것입니다. 완전히 다른 테스트입니다. 더 어려운 것이 아니라, 단지 다를 뿐입니다. 그리고 제가 이 테스트를 직접 작성해야 합니다. 왜냐하면 AI는 "함수가 작동한다"와 "함수가 내가 의도한 일을 수행한다" 사이의 차이를 추측할 수 없기 때문입니다.
만약 AI가 방금 생성한 코드를 바탕으로 테스트를 작성하게 둔다면, 당신은 아무것도 테스트하고 있는 것이 아닙니다. 당신은 그저 그것을 공증(notarizing)하고 있을 뿐입니다. 하드코딩된 short_signal = False는 문서화된 동작이 되어버립니다. 누락된 check_close_conditions() 호출은 사양(spec)이 됩니다. 축하합니다, 이제 버그를 보호하는 테스트가 생겼군요. 참고로, 이러한 단계들은 실제로 순차적이지 않습니다. 순차적인 것처럼 보일 뿐입니다. 실제로는 그렇지 않습니다. 테스트가 당신이 건너뛰었던 결정을 강요하기 때문에 당신은 다시 설계(design) 단계로 돌아갑니다. 그러면 코드가 변합니다. 그러고 나서 테스트가 다시 변합니다. 어느 날 아침 제가 급하게 패치했던 CI 실패 사례요? 그것을 제대로 되돌리려면 리포지토리(repo)를 통해 의존성(dependencies)이 흐르는 방식에 대한 설계를 다시 작성해야 했고, 이는 락파일(lockfile)이 검증되는 방식을 바꾸었으며, 결과적으로 pre-commit hook이 무엇을 확인하는지를 바꾸었습니다. 설계가 더 이상 움직이지 않고 코드와 테스트가 마침내 자신들이 무엇을 해야 하는지에 대해 합의할 때까지 이 과정은 계속 튕겨 다닙니다.
AI가 루프(loop)에 포함되었을 때 변하는 것은 이 구조 중 어느 것도 아닙니다. 변하는 것은 이 세 가지 중 어느 하나라도 소홀히 했을 때 발생하는 비용입니다. 손으로 코드를 작성하는 것은 관대했습니다. 머릿속에서 모호하게 생각하더라도 타이핑하는 과정에서 정리되거나, 컴파일러가 해결해주거나, 혹은 몇 줄 이내에 버그를 발견할 수 있었습니다. AI는 그 모든 관용적인 메커니즘을 제거합니다. AI는 당신이 준 모호한 것을 그대로 실행하여 그럴싸해 보이는 결과물을 만들어내며, 오직 실제 테스트만이 당신이 사실은 자신이 무엇을 원하는지 몰랐다는 사실을 알려줍니다. 저도 가끔은 그냥 AI가 알아서 하게 내버려 두는 실수를 범하곤 합니다. 여전히 그 부분을 고쳐나가는 중입니다.
사다리와 돋보기
이런 일이 반복되다 보면, 실패 모드(failure mode)는 더 이상 버그처럼 보이지 않게 됩니다. 그것은 다른 무언가처럼 보이기 시작합니다. 잠시 뒤로 물러나 봅시다. 우리가 올라온 사다리를 보세요. 어셈블리(Assembly). C. C++. Java. Python. JavaScript. 지난주에 사용했던 어떤 프레임워크든 말이죠. 그리고 이제 AI가 있습니다. 계단 하나하나가 세상을 조금씩 더 선명하게 만들었습니다. 더 많은 것들이 가능해졌습니다. 소프트웨어는 더 다채롭고, 더 기묘하며, 더 생동감 있게 변했습니다. 우리가 서 있는 곳에서 올려다본 소프트웨어의 미래는 훨씬 더 다채로워 보입니다.
하지만 여기서 아무도 대놓고 말하지 않는 사실이 있습니다. 그 모든 다채로움은 인간의 머리에서 나왔다는 점입니다. 모든 단계의 풍요로움은 어딘가에 앉아 자신이 존재하기를 바라는 무언가에 대해 치열하게 고민하던 누군가로부터 비롯되었습니다. C가 C++를 발명한 것이 아닙니다. C++가 사람들이 그것으로 만든 것들을 발명한 것도 아닙니다. 언어는 결코 근원이 아니었습니다. AI도 같은 사다리 위에 있습니다. 심지어 같은 칸(rung)에 있죠. 사람들은 마치 AI가 방정식 자체를 바꾼 것처럼 이야기하곤 합니다. 하지만 그렇지 않습니다. AI는 또 다른 언어일 뿐입니다. 어쩌면 더 기묘한 언어일 수는 있겠지만, 결국 언어입니다. 만약 당신의 머릿속에 있는 무언가가 모호하다면, AI는 그것을 당신을 위해 날카롭게 다듬어 줄 의무가 없습니다. 그렇게 훈련되지 않았기 때문입니다. 돋보기 효과 (당신이 제공하는 무엇이든 확대하는 방식)는 바로 그 훈련 과정에서 선택된 결과입니다. AI가 실제 거울처럼 당신 자신의 모습을 보여줄 수 없다는 사실 또한 훈련 과정에서 선택된 결과입니다. C도 당신 자신의 모습을 보여주지 않았습니다. Java 역시 마찬가지였습니다. 단지 언어들이 충분히 느렸기에 우리가 스스로 그 간극을 채웠고, 그래서 눈치채지 못했을 뿐입니다. 적어도 저는 그렇게 보게 되었습니다. 제가 도구에 너무 많은 의미를 부여하고 있는 것일지도 모릅니다. 하지만 저는 계속해서 이 결론에 도달하게 됩니다. 그래서 사람들이 이 미래에 인간 프로그래머의 자리가 여전히 있는지 물을 때, 저는 질문이 거꾸로 되었다고 생각합니다. 돋보기가 빛 없이 초점을 맞출 수 있을까요? 잠시 이 질문을 곱씹어 보십시오. 거울 앞에 아무도 서 있지 않을 때, 거울이 얼굴을 보여줄 수 있을까요? Find me on GitHub | Substack | StratCraft
AI 자동 생성 콘텐츠
본 콘텐츠는 Dev.to AI tag의 원문을 AI가 자동으로 요약·번역·분석한 것입니다. 원 저작권은 원저작자에게 있으며, 정확한 내용은 반드시 원문을 확인해 주세요.
원문 바로가기