
제목
"for 루프 최적화한다고 `i++` 치고 계신가요? 죄송하지만 헛수고하셨습니다."
본문
솔직히 고백하겠습니다. 저는 주니어 시절, 동료 개발자가 올린 PR(Pull Request)에 for...of 구문이 보이면 반려를 누르곤 했습니다. 당시 스타트업에서 트래픽과 사투를 벌이던 저에게, 자바스크립트의 성능 최적화는 일종의 신앙과도 같았습니다. "Iterator 프로토콜이 매번 객체를 생성하는 오버헤드를 아시나요? for (let i = 0; ...)으로 바꾸세요."라고 코멘트를 달며, 마치 제가 대단한 성능 수호자가 된 듯한 착각에 빠져 있었죠. 지금 생각하면 얼굴이 화끈거리는 '성급한 최적화'의 전형이었습니다.
최근 흥미로운 벤치마크 결과를 접하고, 제 과거의 아집이 얼마나 부질없었는지 다시 한번 뼈저리게 느꼈습니다. 'JavaScript의 for-of 루프는 사실 빠르다'라는 주제의 리포트였는데, 결론부터 말씀드리면 V8 엔진은 생각보다 훨씬 똑똑했습니다. 우리가 관습적으로 "느리다"고 믿어왔던 for...of 루프가, 가장 빠르다고 알려진 '길이 캐싱된 클래식 for 루프(Cached Length Loop)'와 거의 대등한 성능을 낸다는 사실입니다.
우리가 for...of를 기피했던 논리는 명확했습니다. 내부적으로 next() 메서드를 호출하고 { value, done } 형태의 객체를 반환하는 과정이 낭비라고 여겼기 때문입니다. 하지만 최신 V8 엔진(Chrome 143 기준)에서의 테스트 결과를 보면, 배열 크기가 5,000건이나 50,000건 수준일 때 for...of의 성능은 클래식한 i++ 루프와 오차 범위 내에서 동일했습니다. 심지어 배열을 역순으로 순회하는 i-- 방식이나, 함수 호출 비용이 발생하는 forEach보다 훨씬 우수한 성능을 보여주었습니다.
물론 500,000건 이상의 대용량 데이터를 다룰 때는 미묘한 차이가 있었습니다. 초기 실행 시에는 for...of가 최적화(Optimization) 되기까지 시간이 걸려 약간 뒤처지는 모습을 보입니다. 하지만 JIT(Just-In-Time) 컴파일러가 코드를 '워밍업'하고 나면, 결국 클래식 for 루프의 성능을 거의 완벽하게 따라잡습니다. 즉, 엔진이 반복되는 패턴을 감지하고 내부적으로 최적화를 수행하여 Iterator의 오버헤드를 상쇄시켜 버리는 것입니다. 반면 for...in은 여전히 끔찍한 성능을 보여주었고, forEach는 편의성 대비 성능 비용이 꽤 높은 편이었습니다.
대기업으로 이직 후 레거시 시스템을 다루면서 더 절실히 느끼는 점이 있습니다. 코드는 기계가 실행하지만, 결국 사람이 읽고 유지보수한다는 점입니다. for (let i = 0; i < arr.length; i++)은 변수 i를 관리해야 하고, 인덱스로 배열에 접근해야 하는 인지적 부하를 줍니다. 반면 for (const item of items)는 "아이템들을 순회한다"는 의도를 명확히 드러냅니다. 성능 차이가 미미하다면, 우리는 마땅히 가독성을 택해야 합니다. 0.1ms를 줄이겠다고 가독성을 해치는 것은, 협업하는 동료의 리소스를 낭비하는 행위나 다름없기 때문입니다.
물론, 초당 수백만 건의 트랜잭션을 처리하는 코어 로직이나 렌더링 루프처럼 극한의 성능이 요구되는 '핫 패스(Hot Path)'에서는 여전히 클래식 for 루프가 유효할 수 있습니다. 하지만 우리가 작성하는 대부분의 비즈니스 로직에서 그 정도의 마이크로 최적화가 필요한 경우는 극히 드뭅니다. 오히려 Cursor나 Copilot 같은 AI 도구들이 제안하는 깔끔한 for...of 구문을 의심 없이 받아들이고, 비즈니스 로직의 정합성을 검증하는 데 시간을 쏟는 것이 훨씬 생산적입니다.
이제 막 개발을 시작했거나, 저처럼 성능 강박에 시달리는 분들께 말씀드리고 싶습니다. 엔진을 믿으세요. 그리고 여러분의 코드를 읽을 동료를 믿으세요. "반복문 하나도 최적화 못 하는 개발자"라는 소리를 들을까 봐 두려워 억지로 인덱스 변수 i를 선언하고 계셨다면, 이제 그 짐을 내려놓으셔도 좋습니다. 기술은 우리를 더 편하게 만들기 위해 발전하고 있으니까요. 대신 절대로 쓰지 말아야 할 것은 for...in뿐이라는 것만 기억하면 됩니다.


