Multi-Agent 05
오류 전파와 단일 흐름 디버깅의 어려움
최종 답변만 보면 문제 원인을 충분히 고칠 수 있다고 생각하기 쉽다.
근거 · 교안 p14
1장: 착각 깨기: 최종 결과만으로 알 수 없는 것
솔라의 펜 끝이 노트 위를 불안하게 맴돌았다. 깨끗한 페이지 한가운데에는 방금 온라인 강의에서 본 문장이 적혀 있었다.
“단일 Agent에서는 초기 판단 오류가 이후 결과 전체로 전파되고, 단계별 책임 구분이 없어 어디서 문제가 생겼는지 찾기 어렵다.”
솔라는 펜을 내려놓고 의자 등받이에 몸을 기댔다. 단어 하나하나는 알겠는데, 문장이 주는 느낌은 어딘가 이상했다. 결과가 틀렸으면 틀린 거지, 원인을 찾기 어렵다는 말이 왜 나올까?
“언니, 나 이거 좀 이상해.”
거실 테이블 맞은편에서 책을 읽던 루나가 고개를 들었다. 솔라는 노트를 루나 쪽으로 휙 밀었다.
“결과가 잘못 나왔으면, 그 잘못된 결과를 보면 되잖아. 답이 10인데 3이 나왔으면, 3이라는 결과를 뜯어보면 왜 틀렸는지 알 수 있는 거 아니야? 왜 찾기 어렵다는 거지?”
솔라의 목소리에는 ‘이건 너무 당연한데, 왜 어렵다고 할까?’ 하는 순수한 의아함이 묻어났다. 최종 결과는 모든 과정의 흔적을 담고 있는 결론이니까. 그 결론만 잘 분석하면 원인은 당연히 드러날 거라고, 솔라는 굳게 믿고 있었다.
루나는 솔라가 밀어준 노트를 잠시 들여다보더니, 말없이 자리에서 일어났다. 그리고는 새 종이 한 장과 펜을 가져와 솔라 앞에 앉았다.
“간단한 계산 한번 해보자.”
루나는 종이 위에 다섯 개의 지시사항을 차례로 적어 내려갔다.
- 숫자 10에서 시작하세요.
- 그 숫자에 5를 더하세요.
- 나온 결과에 2를 곱하세요.
- 거기서 7을 빼세요.
- 마지막으로 2로 나누세요.
“자, 내가 이 순서대로 계산을 할게. 솔라, 너는 내가 계산하는 동안 잠시 뒤돌아 있어. 중간 과정은 보여주지 않을 거야.”
“에이, 너무 쉬운 거 아니야?”
솔라는 피식 웃으며 의자를 돌려 등을 보였다. 등 뒤에서 루나의 펜이 종이에 스치는 소리가 사각사각 들렸다. 잠시 후, 루나가 말했다.
“다 됐어. 정답은 3이야.”
솔라는 의자를 돌려 루나가 내민 종이를 보았다. 지시사항 목록 아래에 큼지막하게 ‘결과: 3’이라고 쓰여 있었다. 솔라는 즉시 암산을 시작했다. 10 더하기 5는 15, 곱하기 2는 30, 빼기 7은 23, 나누기 2는… 11.5.
“틀렸네. 답은 11.5인데.” “응. 틀렸어. 그럼, 내가 다섯 단계 중에 어디서 실수했을까?”
“음… 어디 보자.”
솔라는 자신만만하게 펜을 들었다. 최종 결과 ‘3’. 이것이 모든 단서였다. 그녀는 역산을 시도했다. 마지막 단계가 ‘2로 나누기’였으니, 그전엔 6이었겠네. 그 전엔 ‘7을 빼기’였으니 13이었을 거고. 그 전엔 ‘2를 곱하기’였으니… 6.5? 잠깐, 그럼 시작이 1.5가 되는데? 솔라의 펜이 멈칫했다. 처음 생각처럼 간단하지 않았다.
“혹시 마지막 5단계에서 나눗셈을 잘못한 거 아니야?”
솔라가 첫 번째 추측을 던졌다.
“아니.”
루나의 대답은 단호했다.
“그럼… 3단계? 곱셈이 다른 계산보다 복잡하니까. 혹시 2가 아니라 엉뚱한 숫자를 곱했어?” “아니.”
솔라의 미간이 좁혀졌다. 최종 결과 ‘3’은 아무런 말을 해주지 않았다. 그냥 ‘틀렸다’는 사실만 알려줄 뿐, 어느 단계에서 어떤 종류의 실수가 일어났는지에 대한 정보는 조금도 담고 있지 않았다. 마치 굳게 닫힌 상자 같았다. 안에서 무슨 일이 있었는지는 모르고, 밖으로 나온 결과물만 덩그러니 놓여있는 느낌.
“모르겠어. 그냥 찍어야 하는 거잖아, 이건.”
솔라가 마침내 두 손을 들었다.
루나는 빙그레 웃으며 아까 계산했던 종이의 뒷면을 보여주었다. 거기에는 루나의 계산 과정이 단계별로 적혀 있었다.
- 10
- 10 + 5 = 15
- 15 - 2 = 13 (원래 지시: × 2)
- 13 - 7 = 6
- 6 ÷ 2 = 3
“3단계에서 곱셈 대신 뺄셈을 했어.”
“아!”
솔라의 입에서 짧은 탄성이 터져 나왔다. 중간 과정을 보는 순간, 모든 것이 명확해졌다. 문제의 원인은 너무나도 뚜렷하게 3단계에 있었다. 하지만 최종 결과 ‘3’만 봤을 때는 도저히 상상조차 할 수 없었던 실수였다.
솔라는 고개를 들어 자신이 처음에 적어두었던 문장을 다시 보았다.
”…단계별 책임 구분이 없어 어디서 문제가 생겼는지 찾기 어렵다.”
이제야 그 문장이 피부에 와 닿았다. 루나의 계산 과정이 바로 ‘단계별 책임 구분이 없는 단일 흐름’이었다. 각 단계가 어떤 결과를 만들었는지 투명하게 보이지 않으니, 마지막 결과만 보고는 오류의 주인을 찾을 수 없었던 것이다. 첫 실수의 그림자가 뒤따르는 모든 계산을 뒤덮어 버렸지만, 정작 마지막에 남은 그림자만 봐서는 처음 그 실수가 어떤 모양이었는지 알 길이 없었다.
“그렇구나… 최종 결과는 그냥 ‘뭔가 잘못됐다’는 신호일 뿐이네. 어디가, 어떻게 잘못됐는지는 전혀 다른 문제였어.”
솔라는 방금의 깨달음을 ‘오류 감지 센서’처럼 머릿속에 장착했다. 이제 결과가 틀렸다는 사실만으로 원인까지 알 수 있다는 섣부른 자신감은 사라졌다. 오히려 결과와 기대가 다르다는 사실 자체가, 보이지 않는 과정 속에 숨어있는 진짜 문제를 찾아 나서야 한다는 강력한 출발 신호로 느껴졌다.
그런데 문득 새로운 궁금증이 고개를 들었다.
“언니, 근데 이상하다. 3단계에서 겨우 ‘곱하기’를 ‘빼기’로 바꿨을 뿐인데, 최종 결과는 11.5에서 3으로 완전히 달라졌어. 마치 작은 실수가 뒤로 갈수록 점점 커지는 것 같아. 이건 뭐라고 불러야 하지?“
2장: 오류 전파: 나비 효과의 확장
솔라의 질문이 가라앉은 거실의 공기를 가볍게 흔들었다. “마치 작은 실수가 뒤로 갈수록 점점 커지는 것 같아. 이건 뭐라고 불러야 하지?”
루나는 대답 대신, 솔라가 뚫어지게 보고 있던 계산 종이 옆에 새 종이를 한 장 펼쳤다. 그리고는 종이 한가운데에 세로로 긴 선을 그어 두 개의 칸으로 나누었다. 왼쪽 칸의 맨 위에는 ‘정상 흐름’, 오른쪽 칸 위에는 ‘오류 흐름’이라고 적었다. 이전 장에서 사용했던 다섯 단계의 지시사항을 그대로 옮겨 적으며, 두 개의 흐름을 나란히 비교할 수 있는 표를 만들기 시작했다.
“네 질문에 대한 답은, 직접 눈으로 확인하는 편이 빠를 거야.”
루나는 1단계와 2단계의 계산을 두 칸에 동일하게 채워 넣었다.
| 단계 | 정상 흐름 | 오류 흐름 |
|---|---|---|
| 1. 시작 | 10 | 10 |
| 2. + 5 | 15 | 15 |
“자, 이제 3단계부터. 두 흐름의 차이를 네가 직접 채워볼래?”
솔라는 펜을 집어 들었다. 그녀의 머릿속에는 여전히 ‘작은 실수’가 어떻게 ‘완전히 다른 결과’를 낳았는지에 대한 의문이 맴돌고 있었다. 그저 결과가 틀렸다는 사실과는 다른, 무언가 더 근본적인 원리가 숨어있는 듯했다.
솔라는 먼저 ‘정상 흐름’ 칸을 채웠다. 15에 2를 곱하면 30, 7을 빼면 23, 2로 나누면 11.5. 익숙한 정답이었다.
문제는 ‘오류 흐름’ 쪽이었다. 3단계에서 루나는 곱셈 대신 뺄셈을 했다. ‘15 - 2 = 13’. 솔라는 오른쪽 칸에 13이라고 적었다. 바로 이 순간, 두 흐름의 운명이 갈라졌다. 정상 흐름의 값은 30이었지만, 오류 흐름의 값은 13이었다. 둘의 차이는 17.
솔라는 침을 한번 삼키고 다음 계산을 이어갔다. 이제부터의 계산은, 이 ‘13’이라는 숫자를 재료로 사용해야 했다. 4단계 지시는 ‘7을 빼는 것’. 솔라는 13에서 7을 뺐다.
‘13 - 7 = 6’.
오른쪽 칸에 ‘6’을 적는 순간, 솔라는 무언가 이상한 점을 깨달았다. 4단계의 ‘빼기 7’이라는 계산 자체는 아무런 잘못이 없었다. 하지만 정상 흐름이었다면 ‘30 - 7’을 계산해야 할 단계에서, ‘13 - 7’을 계산하고 있었다. 3단계의 실수가 4단계가 사용할 재료를 오염시킨 것이다. 잘못된 결과가 다음 단계의 입력값으로 고스란히 넘어갔다.
마지막 5단계. ‘2로 나누기’. 솔라는 방금 얻은 ‘6’을 2로 나누었다. 결과는 ‘3’. 루나가 처음 말했던 바로 그 숫자였다.
솔라는 완성된 표를 가만히 내려다보았다.
| 단계 | 정상 흐름 | 차이 | 오류 흐름 |
|---|---|---|---|
| 1. 시작 | 10 | 0 | 10 |
| 2. + 5 | 15 | 0 | 15 |
| 3. × 2 / - 2 | 30 | -17 | 13 |
| 4. - 7 | 23 | -17 | 6 |
| 5. ÷ 2 | 11.5 | -8.5 | 3 |
두 개의 흐름이 마치 평행선을 달리던 기차가 한순간 다른 선로로 들어선 것처럼, 3단계에서 갈라져 전혀 다른 종착역에 도착했다. 처음의 생각처럼 오류가 뒤로 갈수록 ‘점점 커지는’ 것은 아니었다. 3단계에서 17이었던 값의 차이는 5단계에서 8.5로 줄어들었다. 하지만 그게 중요한 게 아니었다.
“아…!”
솔라의 입에서 나직한 탄성이 흘러나왔다.
“3단계의 실수는 3단계에서 끝나지 않았어. 4단계 계산은 아무 잘못이 없는데도, 3단계가 넘겨준 ‘13’ 때문에 엉뚱한 결과를 냈어. 그리고 그 ‘6’이라는 엉뚱한 결과가 또 5단계로 넘어가서 최종 결과를 ‘3’으로 만든 거고.”
솔라는 펜으로 ‘오류 흐름’의 13에서 6으로, 다시 6에서 3으로 이어지는 화살표를 그었다. 마치 오염된 물이 상류에서 흘러들어 하류 전체를 뒤덮는 모습과 같았다. 첫 실수가 뒤따르는 모든 계산의 전제를 뒤틀어 버린 것이다.
“바로 그거야. 그걸 ‘오류 전파(Error Propagation)‘라고 불러.”
루나가 조용히 말했다.
“초기의 작은 판단 오류가 그걸 입력으로 삼는 다음 단계에 영향을 주고, 그 왜곡된 결과가 또 그다음 단계로 연쇄적으로 영향을 미치면서 전체 흐름을 장악하는 현상이지. 오류가 자신의 그림자를 드리우며 퍼져나가는 거야.”
“초기 판단 오류가 이후 결과 전체로 전파되고…”
솔라는 처음에 보았던 문장의 앞부분이 이제야 선명하게 이해되었다. ‘오류 전파’는 단순히 ‘결과가 틀렸다’는 상태를 말하는 게 아니었다. 오류가 살아있는 생물처럼 다음 단계, 그다음 단계로 자신의 영향력을 퍼뜨리는 과정 그 자체를 의미했다. 하나의 실수가 뒤따르는 모든 올바른 계산들을 무의미하게 만드는, 일종의 연쇄 파괴 효과였다.
“작은 실수 하나가 전체 시스템을 망가뜨리는 증폭기처럼 작동하는구나. ‘오류 증폭기’라고 불러도 되겠네.”
솔라는 고개를 끄덕였다. 이제 왜 최종 결과만으로는 원인을 알기 어려운지 조금 더 깊이 설명할 수 있게 되었다. 최종 결과는 이 모든 전파 과정이 끝난 뒤에 남은 마지막 흔적일 뿐, 어떤 오류가 어디서 시작되어 어떤 경로로 퍼져나갔는지는 알려주지 않기 때문이었다.
그런데 바로 그 순간, 또 다른 의문이 떠올랐다.
“언니, 오류가 이렇게 퍼져나가는 건 이제 알겠어. 그런데… 이게 왜 디버깅을 어렵게 만드는 결정적인 이유가 되는 거지? 지금 우리가 한 것처럼, 그냥 각 단계의 값을 전부 들여다보면 어디서부터 숫자가 달라졌는지 금방 찾을 수 있잖아. 오류가 전파되는 과정 자체는 무섭지만, 추적하는 게 그렇게까지 어려운 일인가?“
3장: 책임 구분 부재: 오류의 주인을 찾아서
솔라의 자신감 있는 목소리가 아직 거실에 떠다니는 듯했다. “그냥 각 단계의 값을 전부 들여다보면 어디서부터 숫자가 달라졌는지 금방 찾을 수 있잖아?”
루나는 대답 대신, 솔라가 가리키고 있는 비교표를 조용히 내려다보았다. 정상 흐름과 오류 흐름의 값이 단계별로 명확하게 나뉘어 적힌, 모든 과정이 투명하게 드러난 증거물이었다. 솔라의 말대로, 이 표만 있다면 오류 추적은 식은 죽 먹기였다.
루나는 펜을 들었다. 하지만 새로운 계산을 하는 대신, ‘오류 흐름’ 열의 3단계부터 5단계까지를 둘러싸는 커다란 네모 상자를 그렸다. 상자 안의 숫자 ‘13’과 ‘6’은 순식간에 보이지 않게 되었다. 루나는 상자 바깥 아래에 이전과 똑같이 ‘결과: 3’이라고만 적었다. 모든 중간 과정이 하나의 검은 상자 속에 갇혀버린 모양새였다.
“지난번엔 내가 오류의 전파 과정을 지도로 그려준 셈이야.”
루나가 입을 열었다.
“만약 우리가 볼 수 있는 게, 처음부터 이것뿐이었다면 어떨까?”
솔라는 미간을 찌푸렸다. “그건 반칙이지. 그건 그냥 1장으로 돌아가는 거잖아. 최종 결과만 보고 원인을 찍으라는 거니까. 하지만 실제로는 중간 단계들이 분명히 존재하잖아. 과정이 없는 결과는 없으니까.”
솔라의 목소리에는, 과정의 존재 자체를 믿는 단단함이 있었다. 오류가 전파되는 것을 봤으니, 그 전파되는 길목을 지키면 된다고 생각했다. 그냥 좀 더 꼼꼼히, 각 단계를 잘 살펴보면 될 문제라고 여겼다.
“과정이 존재한다는 건 맞아.” 루나가 고개를 끄덕이며 말했다. “하지만 우리가 그 과정을 항상 들여다볼 수 있는 건 아니야. 자, 다른 얘기를 해보자. 우리가 ‘세상에서 가장 완벽한 샌드위치 가게’를 열었다고 상상해 봐.”
루나는 계산표를 옆으로 치우고 새 종이를 꺼냈다.
“이 가게는 세 명의 전문가가 일해. A는 특제 소스를 만들고, B는 닭가슴살을 완벽하게 굽고, C는 채소를 손질하고 빵을 준비해. 나는 마지막에 그 세 가지를 받아서 조립만 하는 역할이야.”
루나는 종이 위에 A, B, C 세 사람의 역할을 간략히 그렸다.
A (소스) → 나 (조립) ← B (치킨) ↑ C (채소/빵)
“나는 세 사람에게 완벽한 레시피를 줬어. 그리고 중요한 규칙이 하나 있어. 나는 각 전문가가 작업하는 모습을 볼 수 없고, 그들이 건네주는 결과물—소스, 치킨, 채소—을 중간에 맛보거나 확인할 수도 없어. 그냥 믿고 받아서 합치기만 하는 거야.”
솔라는 흥미롭다는 듯 상상에 빠져들었다.
“드디어 완벽한 샌드위치가 완성됐어. 우리가 한입 베어 무는 순간, 얼굴을 찡그렸지. 너무 짜!”
루나는 솔라를 바라보며 물었다.
“자, 솔라. 누구의 실수일까?”
솔라는 즉시 대답했다. “일단 레시피를 봐야지! 누가 소금을 넣도록 되어 있었어?”
“좋은 지적이야.” 루나는 가상의 레시피를 읊었다. “소스 담당 A는 레시피에 ‘소금 1/2 티스푼’이 있었어. 치킨 담당 B는 닭가슴살 마리네이드에 ‘소금 1/4 티스푼’을 넣어야 했지. C가 준비한 빵은 원래 좀 짭짤한 사워도우 브레드였고.”
“음…”
솔라의 자신만만했던 기세가 한풀 꺾였다. 범인으로 의심되는 사람이 너무 많았다.
“A가 계량을 잘못해서 티스푼 대신 테이블스푼으로 넣었을 수도 있고. 아니면 B가 닭을 너무 오래 재워둬서 짜게 됐을 수도 있어. 혹은 A와 B는 완벽했는데 C가 가져온 빵이 유난히 짰던 날일 수도 있고… 아니, 어쩌면 모두가 레시피를 정확히 지켰는데, 그 결과물들이 합쳐지니 그냥 너무 짜게 된 걸 수도 있잖아?”
솔라의 말이 점점 느려졌다. 그녀는 깨달았다. 최종 결과물인 ‘짠 샌드위치’만으로는 범인을 지목할 수 없다는 사실을. 원인을 알기 위해서는, 조립 전에 소스만 따로 맛보고, 치킨만 따로 먹어봤어야 했다. 각자의 결과물을 따로따로 검증하는 절차가 필요했다.
“맞아. 지금 우리에겐 ‘샌드위치가 짜다’는 문제만 있지, 그 ‘짠맛’의 주인이 누구인지 알 수 없어.”
루나가 솔라의 생각을 정리해 주었다.
“소스 담당의 책임은 ‘레시피에 맞는 소스 만들기’에서 끝나. 치킨 담당의 책임은 ‘알맞게 구워진 치킨 만들기’에서 끝나고. 하지만 우리는 각자의 책임이 완수된 결과물을 확인하지 않고 하나로 합쳐버렸어. 그러니 이제 와서 이 짠맛의 책임을 누구에게도 물을 수가 없는 거야. 모두가 용의자이면서, 동시에 누구도 범인이라 단정할 수 없게 된 거지.”
그 순간, 솔라의 머릿속에서 모든 조각이 맞춰졌다. 그녀는 고개를 들어 맨 처음 봤던 문장의 뒷부분을 떠올렸다.
”…단계별 책임 구분이 없어 어디서 문제가 생겼는지 찾기 어렵다.”
“아! ‘책임 구분’이라는 게 그 뜻이구나!”
솔라의 목소리가 커졌다. ‘오류 전파’가 오류가 퍼져나가는 현상 그 자체라면, ‘책임 구분 부재’는 그 오류의 첫 시작점을 찾지 못하게 만드는 구조적인 문제였다. 각 단계가 자신의 결과물에 대해 명확한 책임을 지고, 그 결과가 검증된 후에야 다음 단계로 넘어가야 하는데, 단일 흐름은 마치 컨베이어 벨트처럼 모든 것을 한 번에 섞어버려 최초의 실수가 누구의 것이었는지 알 수 없게 만들었다. 잃어버린 책임을 찾을 방법이 없었다.
“이제 알겠어. 각 단계의 결과물을 따로 떼어내서 확인할 수 없다면, 그 단계들이 아무리 많이 있어도 결국은 거대한 하나의 덩어리일 뿐이야. 디버깅이 어려운 건, 문제의 주인을 찾을 수 없기 때문이었어.”
솔라는 ‘책임 분할 인식’이라는 새로운 감각을 얻었다. 이제 그녀는 복잡한 문제를 볼 때, 각 단계가 무엇을 하는지만큼이나 ‘각 단계의 책임은 어디까지이고, 그 결과를 독립적으로 확인할 수 있는가’를 먼저 따지게 될 터였다.
한참 동안 생각에 잠겨 있던 솔라가 문득 고개를 들었다. 그녀의 눈에는 새로운 종류의 의문이 담겨 있었다.
“언니, 그럼 샌드위치 가게 비유를 계속 써보자. 각자 만든 걸 중간에 맛보는 게 해결책이잖아. 그런데… 만약 우리 가게 공정이, 소스 담당 A가 소스를 만들자마자 B의 치킨 위에 바로 부어버리는 식이라면 어떡해? 중간에 소스만 따로 맛볼 시간이 아예 없는 거야. C가 손질한 야채도 바로 그 위에 뿌려지고. 이런 식으로 중간 결과물 자체가 하나의 독립된 형태로 존재하지 않고 다음 과정에 곧바로 흡수되어 버린다면, 그때는 책임을 어떻게 나눠야 해?“
4장: 블랙박스 현상: 투명하지 않은 과정
솔라의 질문이 남긴 생각의 파동이 거실의 정적 속에서 맴돌았다. 소스를 만들자마자 치킨 위에 부어버려 중간 맛을 볼 수 없는 샌드위치 가게. 각자의 책임은 있지만, 그 결과가 독립적으로 존재하지 않고 즉시 다음 과정에 흡수되어 버리는 상황.
루나는 솔라의 질문에 말로 답하는 대신, 자리에서 일어나 선반으로 향했다. 잠시 뒤, 그녀는 크기가 비슷한 두 개의 작은 상자를 들고 테이블로 돌아왔다. 하나는 속이 훤히 들여다보이는 투명한 아크릴 상자였고, 다른 하나는 평범한 골판지 상자였다. 루나는 두 상자를 나란히 테이블 중앙에 놓았다. 이 갑작스러운 물건의 등장은 방금 전까지의 추상적인 대화의 흐름을 단번에 끊고, 자매의 시선을 눈앞의 실체로 집중시켰다.
루나는 주머니에서 작은 구슬들이 든 주머니를 꺼냈다. 알록달록한 구슬 몇 개를 손바닥에 쏟아낸 그녀는, 솔라에게 간단한 작업을 제안했다.
“샌드위치 가게 대신, 이번엔 구슬 공장을 해보자. 규칙은 간단해.”
루나는 메모지에 세 단계의 지시를 적었다.
- 파란 구슬 3개를 넣는다.
- 노란 구슬 2개를 더한다.
- 파란 구슬 1개를 뺀다.
“내가 이 두 상자 안에서 똑같이 이 작업을 할게. 솔라, 너는 내가 규칙을 잘 따르는지 지켜봐 줘.”
솔라는 고개를 끄덕였다. 먼저 루나는 투명한 아크릴 상자를 집어 들었다. 그녀의 손이 상자 안으로 들어가 파란 구슬 세 개를 조심스럽게 내려놓는 것이 보였다. 이어서 노란 구슬 두 개가 더해졌다. 마지막으로, 루나는 파란 구슬 하나를 집어 밖으로 꺼냈다. 상자 안에는 파란 구슬 두 개와 노란 구슬 두 개가 남아있었다. 모든 과정이 수정처럼 투명하게 보였다.
“만약 내가 마지막 단계에서 파란 구슬 대신 노란 구슬을 뺐다면 어땠을까?”
“바로 알았겠지. ‘3단계에서 실수했네!’ 하고 말이야.”
솔라는 자신 있게 대답했다. 과정이 보이니까, 책임 소재는 명확했다.
문제는 다음이었다. 루나는 이번엔 불투명한 골판지 상자를 들었다. 상자에 뚫린 작은 구멍으로 손을 넣어 같은 작업을 반복했다. 달그락거리는 구슬 소리만 들릴 뿐, 안에서 무슨 일이 일어나는지는 전혀 보이지 않았다. 잠시 후, 루나는 작업을 마쳤다며 상자를 솔라 앞으로 내밀었다.
“자, 결과물이야.”
루나가 상자를 살짝 기울이자, 안에서 구슬들이 굴러 나왔다. 파란 구슬 세 개, 노란 구슬 한 개.
“어? 틀렸네. 파란 구슬 둘에 노란 구슬 둘이어야 하는데.”
“응, 틀렸어. 어디서 실수했을까?”
솔라의 얼굴에 지난 1장에서와 비슷한 당혹감이 스쳤다. 하지만 이번엔 달랐다. 그녀는 이제 ‘오류 전파’와 ‘책임 구분’의 개념을 알고 있었다. 그녀는 차분히 가능성을 따지기 시작했다.
“2단계에서 노란 구슬을 하나만 넣었을 수도 있고. 아니면 3단계에서 파란 구슬 대신 노란 구슬을 빼버렸을 수도 있어. 혹은… 1단계에서 파란 구슬을 네 개 넣고 3단계에서 하나를 뺐나? 경우의 수가 너무 많아.”
솔라는 불투명한 상자를 노려보았다. 상자는 굳게 입을 다문 채 아무런 단서도 주지 않았다. 바로 그 순간, 솔라는 깨달았다. 자신이 던졌던 질문과 눈앞의 이 상자가 정확히 같은 문제라는 것을.
“아…!”
솔라는 무릎을 쳤다.
“이 상자가 바로 내가 말한 그 샌드위치 가게구나! A가 소스를 만들고(1단계), B가 치킨을 구워(2단계) 그 위에 소스를 바로 부어버리는(결합) 과정 말이야. 각 단계의 작업자는 분명히 존재해. 하지만 한 단계의 결과물이 다음 단계와 곧바로 섞여버려서, 중간 결과물 자체가 독립적으로 존재하지 않아. 확인할 방법이 없는 거야.”
투명한 상자에서는 각 단계의 ‘결과’가 눈에 보였다. ‘파란 구슬 3개’라는 1단계의 결과. ‘파란 구슬 3개와 노란 구슬 2개’라는 2단계의 결과. 각 단계의 결과물이 다음 단계로 넘어가기 전에 독립된 형태로 관찰 가능했다.
하지만 불투명한 상자에서는 아니었다. 각 단계는 분명히 실행되었지만, 그 결과는 즉시 상자라는 어둠 속으로 사라졌다. 우리가 볼 수 있는 건 오직 최종 결과뿐. 모든 과정이 하나의 거대한 ‘블랙박스’처럼 작동해버린 것이다.
”…중간 결과가 명확히 분리되지 않음: 추론 과정이 하나의 블랙박스로 보임.”
강의에서 스쳐 지나갔던 문장이 이제야 실감 나게 다가왔다. 책임 구분이 서류상으로 존재하더라도, 각 책임의 결과물을 따로 떼어내어 검증할 수 없다면, 그 구분은 아무 의미가 없었다. 과정의 투명성이 확보되지 않으면, 아무리 단계를 잘게 나누어도 결국 거대한 하나의 비밀 상자를 상대하는 것과 같았다.
“책임을 나누는 것만으로는 부족했구나. 각 단계가 끝난 후, 그 결과가 ‘검증 가능한 상태’로 잠시 멈춰야 해. 과정의 투명성이 없으면, 책임은 길을 잃고 마는 거였어.”
솔라는 마치 시스템의 건강 상태를 측정하는 새로운 지표를 발견한 기분이었다. 그녀는 이것을 ‘과정 투명화 지수’라고 이름 붙이고 싶었다. 이 지수가 낮을수록, 시스템은 거대한 블랙박스에 가까워지고 문제 추적은 불가능의 영역으로 들어간다.
이제 모든 것이 명확해진 것 같았다. 해결책은 명쾌했다. 모든 과정을 투명한 상자 안에서 하듯 만들면 되는 것이다.
자신감을 되찾은 솔라가 루나에게 말했다.
“알겠어, 언니. 그럼 해결책은 간단하네. 어떤 시스템이든 이 투명한 상자처럼 만들면 되는 거잖아. 모든 중간 단계를 기록하고, 언제든 들여다볼 수 있게 만들면, 오류가 발생해도 금방 잡을 수 있겠지.”
그러자 루나는 조용히 골판지 상자를 다시 집어 들었다. 그리고는 조금 전과 똑같은 지시사항대로 구슬을 넣고 빼는 작업을 다시 한번, 천천히 보여주겠다고 했다.
“자, 다시 해볼게. 1단계, 파란 구슬 3개. 2단계, 노란 구슬 2개. 3단계, 파란 구슬 1개 빼기.”
루나는 작업을 마치고 상자를 기울였다. 이번에 나온 결과는 파란 구슬 두 개, 노란 구슬 두 개. 완벽한 정답이었다. 솔라는 어깨를 으쓱했다.
“이번엔 제대로 했네.”
“한 번 더 해볼까?”
루나는 같은 작업을 또 한 번 반복했다. 하지만 이번에 상자에서 나온 것은 파란 구슬 세 개와 노란 구슬 두 개였다.
솔라의 표정이 굳어졌다.
”…어? 방금 전이랑 똑같이 했다며. 근데 왜 결과가 또 달라?“
5장: 재현성 부족과 문제 해결의 열쇠
테이블 위에는 두 개의 상반된 결과가 놓여 있었다. 하나는 지시대로 완벽하게 수행되었을 때의 결과인 파란 구슬 두 개와 노란 구슬 두 개. 다른 하나는, 바로 직전에 똑같은 과정을 거쳤다고 했음에도 불구하고 나온 파란 구슬 세 개와 노란 구슬 두 개. 같은 입력, 같은 지시, 그러나 다른 결과. 이 명백한 모순이 솔라의 굳은 표정 위로 무겁게 내려앉았다.
솔라의 마음속에서는 ‘과정을 투명하게 만들면 모든 게 해결된다’는 시원한 결론이 뿌리째 흔들리고 있었다. 투명한 상자라면 모든 게 명확했을 것이다. 하지만 이 불투명한 골판지 상자 안에서는, 솔라가 믿었던 논리의 마지막 조각마저 사라져 버린 듯했다. 그녀의 당혹스러운 시선이 두 결과물 사이를 오갔다. 모든 조건을 통제했다고 생각했는데, 눈앞의 현실은 그 믿음을 비웃고 있었다. 한번 틀린 것은 다시 해보면 원인을 알 수 있을 거라는, 혹은 최소한 같은 실수가 반복될 거라는 상식적인 기대가 무너지는 순간이었다.
”…이해가 안 가. 똑같이 했는데, 왜 결과가 다르지?”
결국 솔라가 침묵을 깨고 물었다. 목소리에는 이제 당혹감을 넘어선 근본적인 의문이 담겨 있었다.
루나는 말없이 왼손을 폈다. 솔라의 시선이 그 손바닥으로 향했다. 그 위에는, 상자 안에서는 결코 보이지 않았을 아주 작은 주사위 하나가 놓여 있었다.
“비밀은 이거였어.”
루나가 조용히 말했다.
“지시는 똑같이 따랐어. 하지만 숨겨진 규칙이 하나 더 있었지. ‘3단계에서 파란 구슬을 뺄 때, 이 주사위를 몰래 굴려서 1이 나오면, 뺐던 구슬을 다시 슬쩍 집어넣는다’는 규칙.”
솔라의 눈이 동그래졌다.
“방금 마지막으로 했을 때, 주사위에서 1이 나온 거야. 그래서 나는 규칙대로 파란 구슬을 도로 집어넣었어. 결과적으로는 파란 구슬을 하나도 빼지 않은 셈이 된 거지.”
”…그럼 이건 실수가 아니잖아. 규칙이 원래부터 변덕스러웠던 거네.”
솔라는 허탈한 목소리로 중얼거렸다. 원인은 작업자의 실수가 아니었다. 시스템의 규칙 자체에 예측 불가능한 요소, 즉 ‘무작위성’이 포함되어 있었던 것이다.
이 작은 주사위의 존재는 솔라가 지금까지 쌓아 올린 모든 생각의 탑을 뒤흔들었다. 오류의 신호를 감지하고, 책임의 주인을 찾아내고, 심지어 과정 전체를 들여다볼 수 있게 만든다 해도, 이 작은 주사위 앞에서는 모든 것이 무력했다.
솔라는 소름이 돋는 기분을 느꼈다.
“만약 우리가 이 주사위의 존재를 몰랐다면… 영원히 원인을 못 찾았겠네. 오류가 나왔을 때 다시 한번 실행해서 확인하려고 해도, 다음번엔 주사위가 다른 숫자를 보여줘서 정상적인 결과가 나올 테니까. 오류가 똑같이 나타난다는 보장이 없는 거구나. 마치 유령 같아. 잡으려고 하면 사라져 버리는…”
바로 그 순간, 단일 흐름 디버깅의 마지막이자 가장 무서운 난관이 모습을 드러냈다. ‘재현성(Reproducibility) 부족’. 같은 입력과 같은 조건에서도 매번 다른 결과가 나올 수 있는 가능성. 이것은 문제 추적의 기반 자체를 무너뜨리는 치명적인 장애물이었다. 버그를 수정하려면, 먼저 그 버그를 안정적으로 재현할 수 있어야 한다. 나타났다 사라지는 유령을 잡을 수는 없는 노릇이니까.
솔라는 깨달았다. 이것들은 개별적인 문제가 아니었다. 서로 꼬리를 물고 이어지며 단일 흐름이라는 성을 난공불락의 요새로 만드는, 하나의 거대한 시스템이었다.
그러자 이상하게도 마음이 차분해졌다. 적의 정체를 완전히 파악한 기분이었다. 솔라는 조용히 펜을 들고, 며칠 동안 씨름했던 노트의 새 페이지를 펼쳤다. 그리고는 자신만의 ‘문제 추적 도구 세트’를 써 내려가기 시작했다. 이것은 루나가 준 것도, 강의에 나온 것도 아닌, 온전히 그녀가 험난한 여정을 거치며 스스로 얻어낸 전략 보고서였다.
단일 흐름 시스템 디버깅 전략:
- 단계 분리: 전체 과정을 독립적인 중간 단계들로 나눈다. (오류 전파의 연결고리 끊기)
- 책임 명확화: 각 단계가 어떤 입력을 받아 어떤 결과를 내야 하는지 명확히 정의한다. (잃어버린 책임의 주인 찾아주기)
- 결과 투명화: 각 단계의 결과물을 다음 단계로 넘기기 전에 독립적으로 확인하고 기록할 수 있어야 한다. (블랙박스에 창문 내기)
- 재현성 확보: 시스템에서 예측 불가능한 ‘주사위’를 제거하거나 통제하여, 같은 입력에 대해 항상 같은 결과를 보장해야 한다. (유령 잡을 덫 놓기)
펜을 내려놓은 솔라의 시선이 온라인 강의 노트의 한 구석으로 향했다. 이전까지는 그저 부가적인 어려움 중 하나라고 생각했던 문장이 눈에 들어왔다.
“재현성 부족: 같은 입력에도 매번 다른 결과 발생 가능”
이제 이 문장은 더 이상 최종 보스처럼 느껴지지 않았다. 오히려 그녀가 방금 수립한 네 번째 전략의 필요성을 명확히 설명해주는, 잘 정의된 목표처럼 보였다. 블랙박스는 열면 되고, 그 안에서 굴러다니는 주사위는 덫을 놓아 잡으면 되는 것이었다. 그녀는 이제 이 문장을 수동적으로 받아들이는 학습자가 아니었다. 이 문제에 대한 해결책을 가진 설계자의 관점에서 문장을 바라보고 있었다.
루나는 솔라가 적어 내려간 네 개의 전략을 조용히 지켜보았다. 그리고는 나지막이 말했다.
“이제 그 단단한 상자를 여는 법을 네 스스로 찾아낸 것 같네.”
솔라는 고개를 끄덕였다. 최종 결과만 보고 원인을 단정하던 처음의 순진한 생각에서 출발하여, 마침내 문제의 근원을 파헤치고 해결의 열쇠를 손에 쥔 것이다. 오류의 그림자는 길고 어두웠지만, 그 그림자를 걷어낼 방법은 결국 문제를 회피하지 않고 끝까지 파고드는 데 있었다. 이제 솔라에게 복잡한 시스템의 오류는 더 이상 미지의 공포가 아니었다. 그것은 풀어야 할, 그리고 풀 수 있는 하나의 퍼즐이 되었다.