계획과 결과의 간극
원래 의도는 게임 캐릭터 애니메이션을 만드는 수준을 탐색하는 것이었다. 프레임별 스프라이트를 준비하고 애니메이션으로 연결했다. 과거 스프라이트 디자이너가 하던 일을 AI가 할 수 있을지 궁금했다. 나는 손이 삐꾸라서 이미 만들어진 스프라이트를 활용했다.
01번 프레임부터 순서대로 동작하는 GIF 파일을 만들어줘.
잘 만들어 준다. 그래서 중간에 점프 동작을 넣어 달라고 했다. 점프 프레임은 없었지만, AI는 앞뒤 프레임을 참고해 위화감이 크지 않은 장면을 만들었다.
01번과 02번 사이에 점프 모션을 추가하려고 해. 해당 스프라이트를 별도로 만들고, 이것을 합쳐 새로운 GIF 파일을 만들어줘.
이번에는 01번 그림 하나만 활용해 칼을 휘두르는 애니메이션을 만들어 달라고 했다. ‘휘두르다’가 모호한 것 같아 ‘베다’로도 바꿔 봤다. 불꽃 이펙트가 더해졌지만, 내가 기대한 차이는 거의 없었다.
그래서 요청을 프레임 단위로 쪼갰다. 준비 자세, 한 발 내딛기, 등 뒤에서 칼이 나오는 순간, 궤적을 그리며 내리치는 장면, 회전과 불꽃, 회수와 복귀까지 열 개의 상태를 순서대로 적었다.
결과는 훌륭했다. 각 프레임에 적어 둔 상태가 눈에 보였다. 하지만 디테일에 대한 다른 질문이 따라왔다. 팔아먹을 수 있겠나? 사람이 그린 스프라이트와 AI가 그린 스프라이트 중 무엇이 더 정교해 보이는가?
이 글에서 말하는 정교함
결과가 내가 의도한 허용 범위 안에 반복적으로 들어오는 정도. 의도와 결과 사이의 거리, 그리고 같은 조건에서 다시 얻을 수 있는 재현성을 함께 뜻한다.
한 번 그럴듯한 결과가 나온 것만으로는 정교하다고 부를 수 없다. 우연히 가까워진 결과와, 다시 만들어도 유사한 결과는 다르다. 여기서 멈추고, 이 과정에서 배운 것을 공유하려한다.
나는 소비자가 되었다
나는 C에서 시작해 Python, Java, C#, C++을 두루 섭렵했다. 기술 스택이 쌓이는 나 자신을 보며 성취감을 느꼈고, 성장과 발전이라는 뿌듯한 과정을 지나왔다. 프로젝트 매니저로 역할을 바꾼 뒤에도 최신 기술을 따라가는 일을 취미처럼 즐겼다. 여기까지가 성장이라는 맥락으로 이어져 온 나의 직업 인생이다.
그런데 지금은 무엇이 성장인지, 내가 성장하고 있는지 의심하기 시작했다. 신기술의 세부 스펙을 몰라도 한두 마디면 구현되는 시대다. 기술은 발전하는데 나는 그 흐름에 참여하고 있다는 기분이 들지 않는다.
직접 코딩할 때 나는 생산자였고, 프로젝트를 관리할 때는 설계자였다. 지금은 개발자도 비발자도(비개발자의 요즘 은어)도 아닌 소비자가 된 듯하다. 모델의 기능을 구경하고, 결과를 고르고, 마음에 들지 않으면 다시 뽑는다. 성장의 감각이 소비의 감각으로 바뀌었다.
그렇다면 나는 무엇을 발전시켜야 하는가. 내 기량을 발전시킬 부분이 남아 있기는 한가. 아니, 그럴 필요는 있는가.
구체성의 목적지가 바뀌었다
LLM 등장 초기에는 모델이 못 알아들으니 내가 떠먹여 줘야 했다. 프롬프트의 구체성은 모델 성능의 제약 때문에 요구되었다.
지금은 다르다. 모델은 적당한 요청만 있어도 추론하고 결정해 꽤 완성도 높은 결과를 만든다. 그런데 적당한 요청만으로는 그저 그런 비발자가 될 뿐이다. 지금 구체성이 필요한 이유는 모델의 이해력이 아니라 내 요구의 일관성이다.
목적지가 모델에서 나로 옮겨왔다. 예전에는 모델이 못 알아들을까 봐 자세히 썼고, 지금은 내가 무엇을 원하는지 내가 몰라서 자세히 쓴다.
모델이 채우는 빈칸이 늘어날수록 그 빈칸에 내가 원하지 않던 것이 들어올 가능성도 커진다. “어제 만들어진 화면이 더 좋아 보이는데 재현할 수는 없습니다”라는 말을 고객에게 할 수는 없다. 바뀌지 말아야 할 것, 바뀌어도 되는 것, 실패로 볼 조건을 먼저 정해야 한다.
모델이 더 좋아지면?
모델은 계속 좋아질 것이다. 대충 말해도 알아서 잘한다. 그렇다면 정교함은 결국 LLM의 몫이 아닌가.
나는 그렇게 생각하지 않는다. 모델이 알아서 채워도 되는 영역은 대체로 내가 크게 신경 쓰지 않는 영역이다. 내가 신경 쓰는 것은 목적, 제약, 트레이드오프, 판단 기준, 실패 조건이다. 그것은 더 좋은 모델도 나 대신 결정할 수 없다. 결정할 수는 있어도, 그 결정은 내 의도가 아니라 모델이 추정한 의도다.
점프 프레임이 자연스러웠던 것은 AI가 전후 프레임 정보를 활용했기 때문이다. 하지만 어떤 장면이 캐릭터 설정을 깨는지, 어떤 속도가 게임의 손맛을 망치는지, 어디까지 변형을 허용할지는 여전히 내가 규정해야 한다.
이 글에서 말하는 언어
국어 실력이나 화려한 어휘가 아니다. 목적·제약·판단 기준·실패 조건을 구조화해 타인과 AI가 검증 가능한 형태로 만드는 명세(specification) 능력이다.
그래서 언어의 역할은 사라지지 않는다. 지시하는 문장에서, 경계를 정하고 판단 기준을 밝히는 문장으로 이동한다.
개발자의 전문성과 인지부채
맥락을 주입하는 방식은 결국 언어다. 내가 소프트웨어를 만들기 위해 AI에 사용하는 언어가 보통 사람과 다르지 않다면 나는 전문가인가. 보통의 언어로 충분한 소프트웨어가 나온다면 우리 직업은 존재 가치가 있는가.
전문성은 어려운 코드를 직접 타이핑하는 데만 있지 않다. 요구사항 뒤에 숨은 충돌을 발견하고, 선택의 대가를 설명하고, 결과가 맞는지 판정하는 데 있다. 고객이 “제가 이렇게 해보니까 더 잘 나오는데요”라고 말하는 순간 사라지는 것은 개발자라는 직업이 아니라, 판단 근거 없이 결과만 전달하던 개발자의 자리다.
인지부채를 해소해야 한다
“AI가 도출한 내용을 어디까지 알고 있나?” 이 질문에 답하지 못한 채 결과를 쌓으면 인지부채가 생긴다. 코드는 늘었지만 이해는 늘지 않은 상태다. 지금은 빨라 보이지만, 수정과 리뷰와 장애 대응의 순간에 이자가 붙는다.
인지부채는 언어를 몰라서 생기는 것만은 아니다. 내가 무엇을 모르는지 설명하지 못하고, 결과를 검증할 기준을 만들지 못할 때 쌓인다. 정확한 언어는 도메인 이해의 함수다. 이해하지 못한 것은 제대로 명세할 수 없고, 제대로 명세하지 못한 것은 검증할 수도 없다. 코드를 이해하라는 말과 언어를 갈고닦으라는 말은 결국 같은 말이다.
내 한국어는 몇 개 국어인가
자연어가 중요해졌다고 해도 자연어를 더 갈고닦을 결심은 좀처럼 서지 않는다. 모국어를 불편함 없이 쓰고 있으니 이미 고수준 사용자라고 생각하기 때문이다. 정말 그럴까.
우리가 모두 한국어를 쓴다고 해서 AI에게 요청하는 한국어가 하나의 버전인 것은 아니다. 차이는 사투리나 어휘보다 논리 전개의 순서에 있다. 어떤 사람은 목적부터 쓰고, 어떤 사람은 화면부터 쓰며, 어떤 사람은 예외부터 쓴다. 같은 문장을 써도 무엇을 먼저 고정하고 무엇을 열어 두는지가 다르다. 그래서 결과도 달라진다.
정교한 조각상을 만들려면 끌의 날도 용도에 따라 달라야 한다. 머리카락을 표현하려면 날 끝이 바늘처럼 가늘어야 하지 않겠는가. 내 언어의 정교함이 결국 AI에게 요청한 결과의 섬세함과 재현성을 결정한다.
주사위
정교함을 결정할 수 없다면 우연으로 얼마나 버틸 수 있겠는가. 우연히 튀어나온 좋은 결과를 기대한다면 납기는 어떻게 맞출 것인가. 우리는 자꾸 주사위를 굴리고 있다.
실력이란 주사위를 잘 굴리는 능력이 아니라, 굴리지 않아도 되게 만드는 능력이다.
그 능력은 결과를 한 점으로 고정하는 통제 욕구가 아니다. 허용할 변주와 허용하지 않을 실패를 구분하는 일이다. 좋은 명세는 창의성을 없애지 않는다. 창의성이 움직일 수 있는 울타리를 만든다.
병목은 이동한다. 그 병목이 우리가 활동할 필드다.
어떤 직업이 사라질지 예측하는 일은 별로 유용하지 않다. 직함은 바뀔 수 있다. 웹마스터라는 직함은 사라졌지만 IT 직업군이 사라진 것은 아니다. 한 직업 안의 일부 행위가 대체된 뒤, 역할이 어떻게 다시 묶일지는 미리 알기 어렵다.
제본스 역설을 대입해 보면 소프트웨어 하나를 만드는 데 필요한 자원이 줄어든다고 해서 소프트웨어의 총소비가 줄어드는 것은 아니다. 더 싸게 만들 수 있으면 우리는 더 많이 만들려고 할 것이다.
그러면 병목이 이동한다. 만드는 일이 싸지면 무엇을 만들지 규정하는 일이 비싸진다. 열 개를 만들 수 있게 된 조직이 부딪히는 벽은 구현 속도가 아니라, 그 열 개가 각각 무엇이어야 하는지 말하고 서로의 충돌을 조정할 수 있는 사람의 수다. 그 능력이 이 글에서 말하는 언어다.
‘고객 문의 게시판을 만들어줘’라고 말하는 수준에 머물 수는 없다. 누구의 문의를 어떤 상태로 나누고, 어떤 권한으로 보고, 무엇을 처리 완료로 판단하며, 어떤 실패를 막아야 하는지 말할 수 있어야 한다. 구현의 비용이 내려갈수록 이 문장들의 가격은 올라간다.
그래서 무엇을 하는가
인풋의 증가 없이 자연어 코딩 전문가가 될 수는 없다. 그런데 사람과 협의하고 반박을 듣는 일이 줄면 내 언어는 갱신을 멈춘다. 갱신을 멈춘 언어로 계속 갱신되는 모델을 상대하는 것. 이것이 지금 우리가 처한 퇴화되기 직전의 상태이다.
- 동사를 상태와 기준으로 바꾼다. ‘멋지게’, ‘깔끔하게’, ‘휘두르게’에서 멈추지 않는다. 시작 상태, 변화, 종료 상태, 허용 범위와 실패 조건을 적는다.
- 유사어가 아니라 차이를 묻는다. 모델에게 다른 표현을 요청하고, 각 표현이 결과에서 어떤 차이를 만드는지 확인한다. 도메인의 과학·기술 용어도 함께 찾는다.
- 한 번의 성공보다 반복을 시험한다. 같은 명세를 여러 번 실행해 결과의 분산을 본다. 좋은 결과 하나를 고르는 대신, 계속 나쁜 결과가 나오는 빈칸을 찾는다.
- 결과를 다시 말로 되먹인다. 마음에 든 부분과 틀린 부분을 문장으로 설명한다. 설명할 수 없는 만족은 다음 작업에 재사용하기 어렵다.
- 도메인 이해를 빚으로 남기지 않는다. AI가 만든 코드와 설계를 내가 설명할 수 있는지 확인한다. 설명하지 못하면 채택하기 전에 더 읽고, 묻고, 줄인다.
객체지향언어에서 등장한 디자인 패턴처럼, 위와 같은 프롬프트 교정 패턴들을 방법론화 할 때다. 방법은 공유할 수 있지만 어휘는 그대로 공유되지 않는다. 어휘는 각자의 도메인에서 자란다. 금융을 하는 사람의 정교한 언어와 제조를 하는 사람의 정교한 언어는 다른 단어와 실패 조건으로 이루어진다. 남이 대신 길러 줄 수는 없다.
결과는 알겠는데, 과정을 모르겠다
결과에 대한 예측은 쉽다. 우리가 방황하는 이유는 그 결과에 닿기까지의 과정을 예측하기 어렵기 때문이다. AI와 로봇이 보급된 사회의 모습은 아이작아시모프 같은 SF작가가 쓴 오래전 소설들에서도 볼 수 있다. 하지만 그곳까지 가는 동안 직업과 전문성이 어떤 순서로 바뀌는지는 쓰여 있지 않다.
AI의 추론 능력으로 전문성의 의미는 언젠가 다시 정의될 것이다. 그래도 그곳에 다다르기 전까지 우리는 살아 있어야 한다. 그 과정에서 개발자의 삶을 유지한다면, 나는 구체화된 언어의 양과 질을 높이는 일이 우리 직업군의 실력이 될 것이라 판단한다.
이 말은 내가 이십 년 쌓은 기술이 무효가 되었다는 뜻이 아니다. 요구사항의 모순을 찾고, 실패를 예상하고, 시스템의 경계를 정하던 능력은 그대로 남는다. 다만 그것을 표현하는 첫 번째 매체가 어셈블리에서 C로 고급화 됐듯이, 코드에서 자연어 기반의 명세로 조금 고급화 되었을 뿐이다.
내 언어의 한계가 내 기술의 한계다
AI의 발전이 우리의 업을 세상에서 지울 것이라는 두려움은 남아 있다. 하지만 그 시점이 오면 그것은 개발자만의 문제도 아닐 것이다. 사람의 행동 패턴을 돌아보면, AI가 컴퓨터로 하는 모든 일을 대신해 준다고 해도 자기 직업에 필요한 소프트웨어를 직접 만드는 사람이 갑자기 모두가 되지는 않을 것이다. 개발자인 우리조차 필요한 모든 도구를 직접 만들어 쓰지는 않는다.
그래서 막연한 낙관이나 비관보다 꾸준히 자신을 연마하는 편이 합리적이라고 믿는다. 다만 이제 연마해야 할 것은 새 도구의 사용법만이 아니다. 내가 원하는 것, 원하지 않는 것, 감수할 대가, 실패로 볼 조건을 더 정확히 말하는 능력이다.
스프라이트 한 장을 움직이려 했을 뿐인데, 결국 움직여야 했던 것은 내 언어였다.