FAQ - 자주 묻는 질문

=으로만 의존성을 설정하면 안 되나요?

Q: gem을 고정할 만한 가치가 있다고 생각합니다만, =으로만 버전을 적어 모든 의존성을 Gemfile에서 해결하고 Gemfile.lock을 안 쓸 수는 없을까요?

A: gem은 각각의 의존성을 가집니다. 그리고 gem은 =으로 의존성을 설정하지 않을 가능성이 있습니다. 더욱이, 모든 *gem들*의 의존성을 너무 엄격하게 고정하는 것은 좋은 생각이 아닙니다. Gemfile.lock은 마지막으로 정상적으로 동작할 때의 애플리케이션의 모든 서드파티 코드를 정확히 기억하는 대신에, 애플리케이션에서 필요로 하는 의존성의 버전을 Gemfile에 지정할 수 있도록 합니다.

nokogiri ~> 1.4.2처럼 Gemfile에서 느슨하게 의존성을 지정하면 bundle update nokogiri를 실행해 ~> 1.4.2의 요구 버전 범위를 여전히 만족하는 nokogiri와 의존 gem**만** 업데이트할 수 있게 됩니다. 또, 정확한 버전 번호를 모르더라도 Gemfile에서 gem 'nokogiri'라고 적어 "난 nokogiri의 최신 버전을 쓰고 싶어."라고 말할 수 있습니다. 이 경우에도 여전히 애플리케이션이 서드파티 코드와 정확히 같은 버전으로 동작하는 것이 보장됩니다.

모든 걸 서브모듈로 관리하면 안 될까요?

Q: 왜 gem을 관리하는데 번들러가 필요한지 이해하지 못하겠습니다. 그냥 gem을 받아서 서브모듈로 지정하고 각각의 서브모듈에 로드 경로를 지정하면 안 될까요?

A: 불행히도 그 해결책은 의존성의 의존성을 포함해서 모든 의존성을 수동으로 해결해야 할 필요가 있습니다. 한 번은 성공했다 하더라도, gem을 부분적으로 업데이트 할 때마다 재작업이 필요합니다. 예를 들어 rails gem을 업데이트 하려 한다면 레일스의 의존성을 위한 모든 gem(rack, erubis, i18n, tzinfo 등)을 찾고 새 버전의 레일스의 의존성을 만족하는 버전을 찾을 필요가 있습니다.

솔직히, 이 문제는 컴퓨터가 풀기 좋은 문제입니다. 개발자가 시간을 낭비할 필요는 없죠.

더 걱정되는 것은, 수동 의존성 해결 과정에서 실수를 하면, 다른 의존성 간의 충돌에 대한 피드백 대신에 미묘한 런타임 에러를 받게 된다는 점입니다. 예를 들어 서브모듈에서 실수로 잘못된 rack 버전을 사용한다면, 레일스나 다른 의존성 관계의 gem이 존재하지 않는 메소드를 호출하려 해 정상적으로 실행되지 않습니다.

결론: 처음엔 간단해 보일지 몰라도 확실히 더 복잡합니다.

왜 번들러가 --without 그룹 안에 있는 gem을 다운로드하죠?

Q: bundle install --without production을 실행했지만 번들러가 여전히 :production 그룹에 있는 gem을 다운로드 합니다. 왜죠?

A: 번들러의 Gemfile.lock은 넘기는 옵션에 관계없이 Gemfile의 모든 의존성에 대한 정확한 버전정보를 가지고 있습니다. 그렇게 안 한다면 프로덕션에 배포할 때 모든 의존성을 바꾸게 되고, 번들러의 장점을 없애게 될 것입니다. 더 이상 애플리케이션에서 개발, 테스트에 사용하는 gem이 프로덕션에서 사용하는 gem과 같은 gem이라는 확신을 못하게 됩니다. 덤으로 프로덕션의 의존성 추가는 배포 불가능 상태를 만들 수도 있습니다.

프로덕션에서만 사용하는 gem rack-debugging이 있다고 해봅시다. rack-debuggingrack =1.1에 의존합니다. bundle install --without production으로 실행할 때는 프로덕션 그룹이 평가되지 않지만, 애플리케이션을 배포할 때 rack-debuggingrails와 충돌한다는 메시지를 받게 될 것입니다. 왜냐하면 rails가 의존하는 actionpackrack ~> 1.2.1을 필요로 하기 때문입니다.

다른 예로 Gemfilegem 'rack'이 있는 간단한 Rack 애플리케이션이 있다고 해봅시다. 거기의 :production그룹에 rack-debugging을 넣었다고 하죠. bundle install --without production을 통해 설치했을 때는 :production 그룹은 평가되지 않고 애플리케이션은 개발환경에서 rack 1.2.1을 사용하게 됩니다. 그리고 이 상황은 이미 배우셨지만, rack-debugging이 테스트했던 Rack의 버전과 충돌하게 됩니다.

반면에, bundle install을 호출할 때 환경에 상관없이 **모든** 그룹을 평가하면, rack-debugger의 의존성을 발견하고 rack 1.1을 합니다. rack 1.1Gemfile 안의 gem 'rack'과도 호환되죠.

요약하자면, Gemfile 안의 의존성과 관계없이 모든 의존성을 항상 평가함으로써, 다른 환경에서 다른 그룹들을 사용하다 특정으로 환경을 바꾸려 할 때 발생할 수 있는 불편한 점을 미리 방지할 수 있습니다. 그리고 gem을 설치하지 않고 다운로드만 하므로, 프로덕션이나 개발 환경에서 gem의 **설치** 프로세스가 어려워질 것을 걱정할 필요가 없습니다.

설치할 때 특별한 플래그가 필요한 C 확장이 있습니다.

Q: mysql과 같은 설치할 때 특별한 플래그를 필요로 하는 C 확장 gem이 있습니다. 설치할 때 어떻게 플래그 값을 넘길 수 있을까요?

A: 먼저, mysql gem의 대용품(drop-in replacement)인 mysql2 gem을 사용하면 문제 없습니다. 일반적으로 요즘 C 확장들은 필요한 헤더를 찾을 수 있습니다.

만약 정말로 플래그를 넘길 필요가 있다면, bundle config 명령어를 사용하시면 됩니다.

$ bundle config build.mysql --with-mysql-config=/usr/local/mysql/bin/mysql_config

번들러는 ~/.bundle/config에 설정을 저장할 것이고, 이 설정은 같은 사용자가 bundle install을 하면 매번 사용될 것입니다. 결과적으로 한 번만 필요한 gem에 빌드 플래그를 지정하면 그 gem은 언제나 성공적으로 설치 할 수 있습니다.

인터넷에 접속할 수 없는 상황인데 계속 gem 서버에 연결을 시도합니다.

Q: 지금 인터넷에 접속할 수 없지만, 이전에 gem을 설치해 두었습니다. 어떻게 하면 번들러에서 gem 서버에 접속하지 않고 로컬 gem 캐시를 사용하게 할 수 있을까요?

A: bundle install 할 때 --local 플래그를 사용하시면 됩니다. --local 플래그는 번들러에게 원격 gem 서버 대신 로컬 gem 캐시를 사용하게 합니다.

$ bundle install --local

RubyGems 서버에서 번들러를 실행하면 매우 느립니다.

Q: rubygems 서버에서 번들러를 실행하면 매우 느립니다. 좀 더 빠르게 할 수는 없을까요?

A: rubygems 서버에서 번들러를 실행할 때 --full-index 플래그를 사용하세요. 이렇게 하면 api에 매번 요청을 보내는 대신에 모든 인덱스를 한 번에 다운로드합니다.

$ bundle install --full-index
Fork me on GitHub
Docs: Previous Version (v1.10) Current Version (v1.11)