본문 바로가기

개발/이펙티브 자바

Effective Java ( 이펙티브 자바 ) - 아이템 76

가능한 한 실패 원자적으로 만들라

호출된 메서드가 실패하더라도 해당 객체는 메서드 호출 전 상태를 유지해야 한다. 이러한 특성을 실패 원자적이라고 한다.

 

메서드를 실패 원자적으로 만드는 방법은 다양하다.

  1. 가장 간단한 방법은 불변 객체로 설계하는 것이다.
  2. 흔한 방법은 작업 수행에 앞서 매개변수의 유효성을 검사하는 것이다. 내부 상태 변경 전에 잠재적 예외의 가능성 대부분을 걸러낼 수 있는 방법이다.
    • public Object pop() {
         if (size == 0)
            throw new EmptyStackException();
         Object result = elements[--size];
         elements[size] = null; // 다 쓴 참조 해제
         return result;
      }
    • 처음의 if 문에서 size 값을 확인하여 예외를 던진다. 물론 없더라도 ArrayIndexOutOfBoundsException이 발생하겠지만, 추상화 수준이 상황에 어울리지 않다고도 볼 수 있다.
    • 비슷한 취지로 실패할 가능성이 있는 모든 코드를, 객체의 상태를 바꾸는 코드보다 앞에 배치하는 방법도 있다.
  3. 객체의 임시 복사본에서 작업을 수행한 다음, 작업이 성공적으로 완료되면 원래 객체와 교체하는 것이다.
  4. 작업 도중 발생하는 실패를 가로채는 복구 코드를 작성하여 작업 전 상태로 되돌리는 방법

실패 원자성은 일반적으로 권장되지만 항상 달성할 수 있는 것은 아니다. 그리고 항상 그리 해야 하는 것도 아니다. 실패 원자성을 달성하기 위한 비용이나 복잡도가 아주 큰 연산도 있기 때문이다. 

메서드 명세에 기술한 예외라면 설혹 예외가 발생하더라도 객체의 상태는 메서드 호출 전과 똑같이 유지돼야 한다는 것이 기본 규칙이다. 지키지 못한다면 실패 시의 객체 상태를 API 설명에 명시해야 한다.