이 글에서는 Ruby에서 클래스와 모듈을 자동으로 불러오는 '자동 로딩(Autoloading)' 메커니즘에 대해 알아봅니다. 특히 Rails 6부터 도입된 새로운 자동 로딩 시스템인 Zeitwerk 젬(gem)까지 함께 다룹니다.
왜 자동 로딩이 필요할까요?
먼저 간단한 질문부터 시작해 보겠습니다.
여러 개의 소스 코드 파일을 하나로 합치려면 어떻게 해야 할까요?
답은 require를 사용하는 것입니다.
파일을 require하면 Ruby가 해당 파일을 읽고 그 안의 코드를 실행합니다. 하지만 프로젝트가 커지면 수십, 수백 개의 파일을 전부 require해야 할까요?
물론 아닙니다. 실제로는 모든 파일을 한 번에 로드할 필요가 없습니다. 적어도 애플리케이션 시작 시점에는 말이죠.
그렇다면 파일을 필요한 순간에만 로드해서 애플리케이션을 더 빠르게 시작하려면 어떻게 해야 할까요?
바로 이럴 때 필요한 것이 자동 로딩(Autoloading)입니다!
Ruby 기본 자동 로딩 사용법
Ruby에는 자동 로딩 기능이 내장되어 있습니다.
이 기능은 상수(Constant)를 기반으로 동작합니다.
Coconut 같은 상수가 코드에서 처음 발견되면, Ruby는 해당 상수와 연결된 파일을 찾아 로드하려고 시도합니다.
하지만 그 전에 먼저 해야 할 일이 있습니다.
상수와 파일 이름을 미리 등록해 주어야 합니다.
다음과 같이 말이죠:
autoload :Coconut, "lib/coconut.rb"
이렇게 등록해 두면 이후 Coconut 클래스나 모듈을 사용하고 싶을 때마다 Ruby가 어디서 찾아야 하는지 알게 됩니다.
그런데 더 좋은 방법이 있다면 어떨까요?
상수를 일일이 수동으로 등록하지 않아도 Ruby가 모든 것의 위치를 정확히 파악한다면 얼마나 편리할까요?
실제로 Rails가 바로 그렇게 동작합니다. 하지만 Rails 6 이전 버전에서는 이 autoload 메커니즘을 사용하지 않았습니다.
Rails 6 이전의 자동 로딩 방식
Rails는 autoload 대신 const_missing 훅(hook)을 활용해 프로젝트 내의 파일을 자동으로 찾아 로드했습니다.
이게 왜 유용할까요?
Rails 프로젝트에서 일일이 require를 작성하지 않아도 되기 때문입니다.
바로 '관습은 설정보다 우선한다(Convention over Configuration)'는 철학이죠.
규칙만 잘 지키면 모든 과정이 자동으로 처리됩니다.
그 규칙은 다음과 같습니다:
- 파일을 찾을 수 있는 위치에 둡니다 (
ActiveSupport::Dependencies.autoload_paths에 정의된 경로) - 한 파일당 하나의 클래스 또는 모듈만 정의합니다
- 클래스 이름을 따라 파일 이름을 스네이크 케이스(underscore)로 지정합니다 (
UsersController→users_controller.rb)
이렇게만 하면 코드에서 해당 클래스 이름을 참조하는 순간 Rails가 어디서 파일을 찾아야 하는지 알아냅니다.
정말 편리한 기능이죠.
Rails 6 이후의 자동 로딩: Zeitwerk
Rails 6에서는 완전히 새로운 상수 자동 로딩 메커니즘이 도입되었습니다.
바로 Zeitwerk입니다.
기존의 '클래식' Rails 자동 로딩과 무엇이 다를까요?
구버전 Rails가 사용한 const_missing 방식은 모듈 중첩(nesting) 정보가 부족해 여러 가지 제약이 있었습니다.
반면 Zeitwerk는 Ruby의 autoload를 직접 활용합니다.
새 구현 역시 비슷한 파일 명명 규칙을 따릅니다.
흥미로운 점은:
Zeitwerk는 파일 이름으로부터 클래스 이름을 추론합니다. 즉, users_controller → UsersController처럼요.
기존 방식과 정확히 반대되는 접근입니다.
참고로 autoload_paths는 여전히 사용할 수 있지만, "/lib/**" 같은 세부 경로가 아니라 "/lib"처럼 기본(base) 경로만 추가하는 것이 좋습니다.
그 이유가 무엇일까요?
네임스페이스와 중첩 구조가 처리되는 방식 때문입니다.
"lib"를 autoload 경로에 추가했다면,Fruit::Orange클래스를 정의할 때 파일 경로는 반드시"lib/fruit/orange.rb"여야 합니다.- 반대로
"lib/fruit"를 autoload 경로에 추가하면, 같은 클래스를 위해"lib/fruit/fruit/orange.rb"라는 중복된 폴더 구조를 만들어야 합니다.
가장 좋은 점은 무엇일까요?
이 새로운 기능은 Rails에 종속되어 있지 않다는 것입니다. 따라서 Rails를 사용하지 않는 순수 Ruby 프로젝트에서도 Zeitwerk를 활용할 수 있습니다!
정리
지금까지 Ruby의 모듈 자동 로딩이 정확히 무엇이고, 어떻게 동작하는지 살펴보았습니다.
이제 이 개념을 이해했으니, Ruby 프로젝트를 가장 효율적인 방식으로 구조화할 수 있을 것입니다.
이제 여러분 차례입니다. 에디터를 열고 직접 실험해 보며 즐거운 코딩 시간을 보내세요!