러버덕 디버깅은 왜 통할까

버그가 안 풀려서 옆자리 동료에게 물어보러 간 경험이 한 번쯤은 있을 것이다. 이 함수가 배열을 받아서 정렬한 다음 화면에 그린다고 설명을 시작한다. 그런데 세 번째 문장쯤에서 말이 멈추더니 "아, 알 것 같아요"라는 말이 먼저 튀어나온다. 동료는 한마디도 안 했는데 고맙다는 인사를 받는다. (동료 입장에서는 꽤 남는 장사다)
개발자들은 이걸 러버덕 디버깅이라고 부른다. 앤디 헌트(Andy Hunt)와 데이브 토머스(Dave Thomas)가 1999년에 쓴 『실용주의 프로그래머(The Pragmatic Programmer)』의 일화에서 온 이름이다. 그렉 퓨(Greg Pugh)라는 연구 조교가 고무 오리를 늘 들고 다니면서 막히는 문제를 오리에게 설명했다고 한다. 책은 설명을 듣는 상대가 한마디도 하지 않아도 된다고 말한다.
생각해 보면 좀 이상한 일이다. 오리는 코드를 모른다. 옆자리 동료도 그 코드를 그날 처음 봤다. 아무것도 모르는 상대 앞에서 말을 했을 뿐인데 왜 답이 나오는 걸까. 이번 포스팅에서는 이 질문을 조금 파 보려고 한다.
안다고 믿는 것과 설명할 수 있는 것
2002년 예일대의 레오니드 로젠블릿(Leonid Rozenblit)과 프랭크 케일(Frank Keil)은 사람들에게 지퍼, 수세식 변기, 원통형 자물쇠 같은 물건이 어떻게 작동하는지 얼마나 잘 아는지 물었다. 참가자들은 먼저 자기가 아는 정도를 1점부터 7점 사이로 매겼다. 그다음 작동 원리를 단계별로 글로 적게 한 뒤 점수를 다시 매기게 했다.
설명을 쓰고 난 뒤의 점수는 처음보다 낮았다. 지퍼라면 손잡이를 올리면 잠긴다는 데까지는 술술 쓰다가 양쪽 이가 어떻게 맞물리는지에서 손이 멈추는 식이다. 연구진은 이 현상에 설명 깊이의 착각(illusion of explanatory depth)이라는 이름을 붙였다. 네 번의 실험을 합쳐 보면 기계 장치에 대한 점수는 설명을 쓰고 나서 7점 만점에 평균 0.9점쯤 떨어졌다.
코드도 다르지 않다. 매일 보는 함수라 다 안다고 느끼지만 그 느낌은 대개 함수 이름과 대강의 흐름에서 온다. 한 줄씩 무슨 일이 일어나는지 말로 옮겨 보기 전까지는 그 느낌이 맞는지 확인할 길이 없다.
오리에게 한 줄씩 설명해 보면
예를 하나 들어 보자. 점수 목록을 오름차순으로 보여주는 코드를 짰는데 화면에 순서가 이상하게 나온다.
const scores = [100, 25, 9];
scores.sort();
console.log(scores);[ 100, 25, 9 ]머릿속에서 이 코드는 점수를 정렬해서 보여준다는 한 줄로 끝난다. 그 한 줄 안에는 틀린 곳이 없다. 이번에는 오리에게 소리 내어 한 줄씩 설명해 보자. 점수 배열을 받는다. sort 로 정렬한다. 숫자니까 작은 것부터 온다. 그런데 sort 는 뭘 기준으로 비교하더라.
자바스크립트의 sort 는 비교 함수를 넘기지 않으면 원소를 문자열로 바꿔서 비교한다. 문자열로 보면 100 은 첫 글자가 1 이라서 첫 글자가 2 인 25 보다 앞에 온다. 정렬은 제대로 됐다. 우리가 숫자로 비교하라고 시킨 적이 없을 뿐이다.
scores.sort((a, b) => a - b);문서를 다시 읽거나 디버거로 배열을 들여다봐도 찾을 수 있는 버그다. 다만 오리 앞에서는 세 번째 문장을 말하는 순간 걸린다. 숫자니까 작은 것부터 온다는 건 우리 머릿속에만 있던 가정이다. 코드에는 그런 말이 한 글자도 없다.
오리가 말을 하지 않아야 하는 이유
오리의 쓸모는 중간에 끼어들지 않는 데서 나온다. 동료에게 설명하다 보면 두 번째 문장쯤에서 "그거 sort 문제네요" 하고 답이 먼저 올 때가 있다. 문제는 빨리 풀린다. 그 대신 내가 무엇을 모르고 있었는지는 확인하지 못한 채 자리로 돌아온다. 오리 앞에서는 설명을 끝까지 해야 하니 빈칸을 직접 밟게 된다.
Stack Overflow 는 2018년 만우절에 이 농담을 그대로 구현한 적이 있다. Quack Overflow 라는 이름으로 화면 구석에 고무 오리를 띄워 놓고 고민을 들어 주는 기능을 내놨는데, 오리가 할 수 있는 대답은 꽥 소리 하나였다. 장난으로 만든 기능이지만 러버덕 디버깅이 왜 통하는지는 제대로 보여줬다. 대답이 없어야 설명이 끝까지 간다.
요즘은 오리가 말을 한다. 에러 메시지를 AI 채팅창에 붙여 넣으면 몇 초 만에 원인과 고친 코드가 나온다. 편하긴 하다. 다만 이렇게 하면 앞에서 본 설명 단계를 통째로 건너뛴다. 답은 얻었는데 세 번째 문장이 왜 틀렸는지는 모르는 채로 넘어가니 다음 주에 비슷한 버그를 또 붙여 넣어도 이상하지 않다.
그래서 필자는 말하는 오리도 말 못 하는 오리처럼 쓰는 편이 낫다고 생각한다. 질문을 보내기 전에 이 코드가 한 줄씩 무엇을 하는지부터 적는다. 무엇을 기대했는데 실제로 무엇이 나왔는지도 함께 적는다. 그렇게 적다 보면 전송 버튼을 누르기 전에 답이 나오는 일이 적지 않다. 답이 안 나와도 손해 볼 건 없다. 잘 정리된 질문을 받으면 AI 의 대답도 대체로 나아진다.
모니터 위에 오리가 없다면 아무 물건이나 괜찮다. 위키백과에 따르면 오리 대신 곰 인형을 쓰는 경우도 특히 많다고 한다. 곰 인형이든 화분이든 설명만 끝까지 하면 된다.