Ruby 예외의 이해와 처리
Ruby에서 예외는 프로그램 실행 중 발생하는 오류나 예기치 않은 상황을 나타내는 객체입니다. 0으로 나누기, 존재하지 않는 파일 접근, 네트워크 오류 등 문제가 발생하면 Ruby는 예외를 발생시키며, 처리되지 않을 경우 프로그램이 오류 메시지와 함께 종료됩니다.
예외 발생 (Raising Exceptions)
오류나 예기치 않은 조건이 발생했음을 알리는 과정으로, Ruby는 raise 메서드를 제공합니다.
-
raise메서드: 인자 없이 사용하면RuntimeError를 발생시키고, 메시지나 특정 예외 클래스를 지정할 수 있습니다.ruby raise # => RuntimeError raise "Something went wrong!" # => RuntimeError: Something went wrong! raise ArgumentError, "Invalid input provided" # => ArgumentError: Invalid input provided -
사용자 정의 예외 클래스:
StandardError를 상속받아 애플리케이션별 오류를 정의하여 특정 오류를 분리하여 처리할 수 있습니다.ruby class AuthenticationError < StandardError; end # ... raise AuthenticationError, "Invalid credentials" -
예외의 원인 (Cause): 예외에 원인(cause)을 첨부하여 디버깅에 유용하게 활용할 수 있습니다.
e.cause를 통해 원본 예외에 접근합니다.
예외 처리 (Rescuing Exceptions)
프로그램 충돌을 방지하고 오류를 우아하게 처리하기 위해 begin/rescue 블록을 사용합니다.
-
begin/rescue블록: 기본적으로StandardError및 그 서브클래스를 포착합니다.ruby begin result = 10 / 0 rescue puts "An error occurred!" end -
특정 예외 처리:
rescue절에 특정 예외 클래스를 지정하여 처리할 수 있으며, 예외 객체를 캡처하여 검사할 수 있습니다.ruby begin raise ArgumentError, "Invalid input" rescue ArgumentError => e puts "Error: #{e.message}" end -
else및ensure:else는 예외가 발생하지 않았을 때 실행되고,ensure는 예외 발생 여부와 관계없이 항상 실행되어 리소스 정리 등에 유용합니다. -
retry키워드: 예외가 포착된 후begin블록을 다시 시도할 수 있게 해주며, 네트워크 요청 재시도와 같은 시나리오에 유용합니다.
모범 사례 및 실제 예시
-
특정 예외 처리: 모든
StandardError를 포착하는 일반적인rescue대신 예상되는 특정 예외를 지정합니다. -
작은
rescue블록 유지: 예외가 발생할 가능성이 있는 코드만 감싸 가독성을 높이고 무관한 오류 포착을 방지합니다. -
의미 있는 오류 메시지: 디버깅에 도움이 되는 명확하고 실행 가능한 메시지를 포함합니다.
-
사용자 정의 예외: 애플리케이션별 오류에 대해 사용자 정의 예외 클래스를 생성하여 코드의 표현력과 유지보수성을 높입니다.
-
ensure를 통한 리소스 정리: 파일, 데이터베이스 연결 등 리소스를 항상 닫도록ensure를 활용합니다.
실제 예시로는 파일 처리(Errno::ENOENT, Errno::EACCES), API 호출(HTTParty::Error, SocketError), 사용자 정의 결제 처리 클래스 내 예외(InsufficientFundsError, InvalidCardError) 등이 있습니다.
고급 예외 처리
-
중첩된
rescue: 다른 수준에서 예외를 처리하기 위해begin/rescue블록을 중첩할 수 있습니다. -
예외 계층 구조:
Exception은 모든 예외의 루트 클래스이며,StandardError는 대부분의 내장 예외가 상속받는 기본 클래스입니다. -
Rails의
rescue_from: Ruby on Rails에서는 컨트롤러에서rescue_from을 사용하여 예외를 전역적으로 처리할 수 있습니다.
피해야 할 일반적인 함정
-
맹목적인 예외 포착: 특정 예외를 지정하지 않고
rescue를 사용하면 버그를 숨길 수 있습니다. -
retry남용: 무한 루프나 근본적인 문제를 가릴 수 있습니다. -
예외 세부 정보 무시: 디버깅을 위해 항상 예외 객체(
e.message,e.backtrace)를 검사해야 합니다. -
비표준 오류 발생:
StandardError를 상속받지 않는 예외는 기본rescue절에 의해 포착되지 않을 수 있습니다.