“WAT”이라는 단어, 들어보셨나요? 단순한 오타가 아닙니다. 코드를 실행했는데 눈앞에 펼쳐진 결과가 도저히 이해되지 않을 때, 전 세계 개발자들이 공통적으로 내뱉는 그 탄성이에요. 2012년, 개발자 Gary Bernhardt는 CodeMash 컨퍼런스에서 단 4분짜리 발표 하나로 전 세계를 발칵 뒤집어 놓았습니다. 제목은 딱 하나였죠, “WAT”. 지금도 수백만 명이 본 전설의 발표로 회자되고 있어요. 오늘은 그 발표에서 소개된 것들을 포함해, 개발자들이 실제로 경악한 프로그래밍 언어의 충격적인 실제 동작 TOP 5를 소개해 드릴게요. 준비되셨나요?
🍌 1위: 코드에서 바나나가 자랐다 — JavaScript의 “baNaNa” 현상
JavaScript 콘솔을 열고 이걸 한번 입력해 보세요. "b" + "a" + + "a" + "a". 결과가 뭐가 나올 것 같으세요? 그냥 “baaa”? 아니면 에러? 천만에요. 실제로 출력되는 값은 바로 “baNaNa”입니다. 믿기 어렵죠? 코드에 알파벳 ‘b’와 ‘a’ 네 개만 넣었는데 어디서 “NaN”이 튀어나온 걸까요?
트릭은 바로 두 번째 +에 숨어 있어요. + "a"처럼 문자열 앞에 단항 + 연산자가 붙으면, JavaScript는 그 문자열을 숫자로 변환하려 시도합니다. 그런데 “a”는 숫자가 될 수 없으니 NaN(Not a Number)이 탄생하는 거예요. 그 결과, 뒤따르는 문자열 연결 연산이 “ba” + NaN + “a”로 이어지고, NaN도 문자열로 바뀌면서 최종적으로 “baNaNa”가 완성됩니다. 마치 JavaScript가 몰래 과일 장난을 치는 것 같지 않나요?
이 현상이 단순한 웃음거리가 아닌 이유가 있어요. 실제 코드에서 사용자 입력값을 검증 없이 숫자 변환했다가 NaN이 섞여 들어가면, 조용히 버그가 발생할 수 있거든요. 숫자인 줄 알고 계산했더니 결과가 “NaN원”이 돼 버리는 실수, 실무에서 생각보다 자주 일어난다고 해요.
🔄 2위: 순서 하나 바꿨을 뿐인데 — [] + {}와 {} + []의 엇갈린 운명
이번엔 더 짧고 강렬합니다. JavaScript에서 [] + {}를 입력하면 "[object Object]"가 나옵니다. 그런데 두 항목의 순서만 바꾼 {} + []를 입력하면요? 놀랍게도 숫자 0이 출력됩니다. 같은 값들인데 순서만 바꿨는데 결과가 완전히 달라지는 거예요. 처음 보면 “이게 말이 돼?”라는 말이 절로 나오죠.
그 비밀은 JavaScript 엔진이 코드를 해석하는 방식에 있어요. [] + {}에서는 두 항목 모두 값(value)으로 해석됩니다. 빈 배열은 문자열 ""으로, 빈 객체는 "[object Object]"로 변환되어 합쳐지죠. 반면 {} + []에서는 맨 앞의 {}가 객체가 아니라 빈 코드 블록으로 인식되어 버립니다. 그 다음 +[]만 남게 되고, 빈 배열에 단항 +를 붙이면 0이 되는 거예요. 마치 같은 식재료인데 요리 순서가 달라져서 완전히 다른 음식이 나오는 것과 비슷합니다.
이 황당한 현상은 JavaScript의 문맥 의존적 파싱(context-sensitive parsing) 때문에 발생해요. 개발자 커뮤니티에선 이걸 “JavaScript의 정체성 혼란”이라고 부르기도 한다고 해요. 언어 자체가 같은 기호를 상황에 따라 완전히 다르게 해석하는 거니까요.
🤯 3위: 자기 자신을 부정하는 값 — NaN은 NaN이 아니다
수학 세계에서 어떤 값이 자기 자신과 같지 않을 수 있을까요? 현실에선 불가능하죠. 하지만 프로그래밍 언어에선 가능합니다. JavaScript에서 NaN === NaN을 입력하면 결과는 false예요. NaN은 자기 자신과도 같지 않다는 거예요. 처음 보는 분들은 화면을 두 번 쳐다보게 된다고 해요.
이게 단순한 버그가 아니라는 점이 더 놀랍습니다. 이 동작은 의도적으로 설계된 거예요. IEEE 754라는 국제 부동소수점 표준에 명시된 규칙인데, NaN은 “숫자가 아닌 값”이라는 개념 자체이기 때문에, NaN끼리 비교하는 건 의미가 없다고 본 거죠. 예를 들어 0/0의 결과와 Math.sqrt(-1)의 결과가 둘 다 NaN이지만, 그 두 연산이 “같은” 무의미함인지는 정의할 수 없다는 철학이 담겨 있어요.
덕분에 실제 코딩에서 꽤 골치 아픈 상황이 벌어지곤 해요. 변수가 NaN인지 확인하려고 x === NaN을 썼다간 항상 false만 나오거든요. NaN을 제대로 감지하려면 Number.isNaN(x)나 isNaN(x)를 써야 합니다. 이 사실을 몰랐다가 밤샘 디버깅을 한 개발자들의 후기가 개발자 커뮤니티에 넘쳐난다고 해요.
👻 4위: 30년을 살아남은 버그 — typeof null === "object"
JavaScript에서 typeof null을 입력하면 "object"가 반환됩니다. null은 분명 “아무것도 없음”을 의미하는데, 왜 객체 타입으로 나오는 걸까요? 이건 실수일까요, 아니면 설계일까요? 정답은 둘 다예요. 정확히는 1995년에 만들어진 버그가 지금까지 살아있는 것입니다.
JavaScript가 처음 만들어졌을 때, 값의 타입을 내부적으로 태그(tag)라는 숫자로 구분했어요. 객체의 태그 값이 0이었는데, null의 내부 표현도 마침 0이었죠. 그래서 typeof 연산자가 null을 객체로 오인해 버린 거예요. 이 실수는 너무 이른 시기에 발생했고, 이미 수많은 코드가 이 동작에 의존하게 되어 버렸어요. 결국 ECMAScript 위원회가 수정 제안을 냈지만, 호환성 문제로 기각되었습니다. 이 버그는 태어난 지 30년이 넘었는데도 버젓이 살아있는 거예요.
어떤 의미에서는 이 “버그”가 웹의 역사를 증언하는 화석 같은 존재라고 할 수 있어요. 인터넷 초창기의 엉성한 결정이 수십억 개의 웹페이지에 녹아들어, 이제는 손댈 수조차 없게 된 거니까요. 실제로 null 체크를 할 때는 value === null로 직접 비교하는 게 정석이라고 전문가들은 강조합니다.
🐍 5위: Python의 조용한 덫 — 가변 기본 인수의 함정
Python은 배우기 쉽고 직관적인 언어로 알려져 있죠. 그런데 이 함정 앞에서는 베테랑 개발자도 무너진다고 해요. 아래 코드를 보세요.
def add_item(item, cart=[]):
cart.append(item)
return cart
print(add_item("사과")) # ['사과']
print(add_item("바나나")) # ['사과', '바나나'] ← 어?!
두 번째 호출에서 빈 카트가 나와야 할 것 같은데, 이전 호출에서 담긴 “사과”가 그대로 남아있어요. 믿기 어렵죠? 이건 Python이 함수의 기본 인수를 함수가 정의되는 순간 딱 한 번만 생성하기 때문이에요. 즉, 리스트 []는 함수가 호출될 때마다 새로 만들어지는 게 아니라, 처음 딱 한 번 만들어진 뒤 계속 공유됩니다.
이 함정이 특히 위험한 이유는 에러 메시지가 전혀 없다는 점이에요. 코드는 아무 문제 없이 실행되고, 결과만 이상합니다. 그래서 원인을 찾기까지 한참 걸리는 경우가 많아요. 해결책은 간단합니다. 기본값으로 None을 쓰고, 함수 내부에서 새 리스트를 생성하면 돼요. 이 패턴은 Python 커뮤니티에서 “가변 기본 인수 안티패턴”이라는 이름까지 붙어 공식적으로 경계 대상이 됐다고 해요.
재미있는 건, 이 동작 자체는 버그가 아니라는 거예요. Python 개발자 Guido van Rossum은 “이건 설계된 동작”이라고 공식적으로 밝힌 바 있습니다. 다만 그 설계가 직관에 너무 반해서 수많은 개발자들이 트랩에 걸리게 됐을 뿐이죠.
🎯 마치며 — WAT은 두려움이 아닌 이해의 시작
오늘 소개한 다섯 가지 WAT 현상들, 어떠셨나요? 처음엔 황당하고 어이없게 느껴지지만, 사실 그 하나하나에는 언어가 설계된 역사, 표준 위원회의 고민, 그리고 현실적인 타협의 흔적이 담겨 있어요. JavaScript의 이상한 동작들은 웹 초창기의 빠른 개발 속도와 하위 호환성의 무게를 보여주고, Python의 함정은 직관적인 문법 뒤에 숨은 정밀한 내부 동작을 가르쳐 줍니다.
개발자로 성장하는 과정에서 WAT 순간을 만나는 건 부끄러운 일이 아니에요. 오히려 그 순간을 “왜?”라고 파고드는 사람이 결국 더 깊이 언어를 이해하게 됩니다. Gary Bernhardt의 4분짜리 발표가 수백만 명의 개발자 마음속에 남아있는 것처럼, 오늘의 황당함이 내일의 통찰로 이어지길 바랍니다. 다음에 콘솔에서 이상한 결과를 만나도 당황하지 마세요. 그건 버그가 아니라, 언어가 당신에게 건네는 퀴즈일지도 모르니까요. 😄
Photo by Van Tay Media on Unsplash