Zeitwerk는 본질적으로 제로-설정 파일 기반의 자동 로더로 작동하며, 다음과 같은 핵심 원리를 기반으로 합니다.
Zeitwerk의 내부 작동 방식
- 파일-상수 매핑:
app/services/payment/processor.rb
파일은Payment::Processor
상수를 정의할 것으로 예상합니다. - 지연 로딩 (Lazy loading): 상수는 접근될 때만 로드되어 애플리케이션 부팅 시간을 단축합니다.
- 즉시 로딩 (Eager loading): 프로덕션 환경에서는 모든 파일을 미리 로드하여 성능을 최적화합니다.
- 스레드 안전성 (Thread safety): 다중 스레드 환경에서도 안전한 상수 해석을 보장합니다.
Zeitwerk는 Ruby의 const_missing
및 autoload
메커니즘을 활용하여 런타임에 정의되지 않은 상수를 동적으로 해석합니다. 로더는 디렉토리 레지스트리를 유지하고 변경 사항을 모니터링하여 개발 환경에서 코드 리로딩을 가능하게 합니다.
고급 Zeitwerk 설정
- 커스텀 로드 경로: Rails가 자동으로
app/
디렉토리를 설정하지만,lib/
또는app/services/
와 같은 추가 디렉토리는 명시적인 로딩이 필요할 수 있습니다.ruby loader = Zeitwerk::Loader.new loader.push_dir("lib/custom") # 비표준 디렉토리 추가 loader.setup
- 비표준 구조를 위한 네임스페이스 해결: 레거시 프로젝트에서
services/
아래의 네임스페이스가 기본 Rails 규칙과 일치하지 않는 경우,loader.inflector.inflect("payment_processor" => "PaymentProcessor")
와 같이 인플렉터(inflector) 규칙을 정의하거나 파일 구조를 리팩토링할 수 있습니다. - 깔끔한 네임스페이스를 위한 모듈 축소 (Collapsing Modules): 깊은 모듈 구조를 평면화하고 싶을 때
loader.collapse("app/models/concerns")
를 사용하여app/models/concerns/logging.rb
가Concerns::Logging
대신Logging
으로 정의되도록 할 수 있습니다.
Zeitwerk 문제 디버깅
- 로드된 파일 확인: 상수가 로드되지 않을 경우
bin/rails zeitwerk:check
명령어를 통해 모든 상수가 올바르게 해석되는지 확인할 수 있습니다. - 로드된 파일 로깅: 디버깅 모드를 활성화하여 파일 해석 과정을 추적할 수 있습니다.
ruby Zeitwerk::Loader.eager_load_all Zeitwerk::Loader.logger = method(:puts)
- NameError 및 초기화되지 않은 상수 해결:
NameError: uninitialized constant
오류 발생 시, 파일 경로와 예상 상수 이름의 일치 여부, 인플렉터 규칙 오버라이드 여부,require_relative
또는 수동require
호출로 인한 자동 로딩 충돌 여부를 확인해야 합니다. 개발 환경에서 수정된 파일을 수동으로 다시 로드하려면Rails.autoloaders.main.reload
를 사용합니다.
대규모 코드베이스에서 Zeitwerk 모범 사례
- 표준 명명 규칙 준수: 파일 이름과 클래스/모듈 이름을 일관되게 유지합니다.
- 인플렉터 재정의 최소화: 레거시 구조를 다루는 경우가 아니라면 불필요한 커스텀 인플렉션을 피합니다.
- Concerns 및 유틸리티에
collapse
활용: 공유 모듈을 적절히 평면화합니다. - 프로덕션에서 즉시 로드:
Rails.application.config.eager_load = true
설정을 통해 최적의 성능을 보장합니다. zeitwerk:check
정기적 활용: 배포 전 자동 로딩 무결성을 검증합니다.