Java ‐ 가능한 한 실패 원자적으로 만들라[Effective Java Item 76] - thought-corner/Backend-PlayGround GitHub Wiki

실패 원자적 (failure-atomic)인 메서드

  • 실패 원자적인 메서드란, 호출된 메서드가 실패하더라도 해당 객체는 메서드 호출 전 상태를 유지해야 하는 메서드를 말한다.

실패 원자적인 메서드를 어떻게 만들까?

1. 불변 객체로 만들기

  • 불변 객체는 태생적으로 실패 원자적이다.
  • 메서드가 실패하면 새로운 객체가 만들어지지는 않을 수 있으나 기존 객체가 불완전한 상태에 빠지는 일은 결코 없게 된다. 불변 객체의 상태는 생성 시점에 고정되어 절대 변하지 않기 때문이다.

2. 가변 객체의 메서드인 경우 작업 수행 전 매개변수의 유효성을 검사하기

  • 객체의 내부 상태를 변경하기 전에 잠재적 예외 가능성 대부분을 걸러낼 수 있는 방법이다.
public Object pop() {
    if (size == 0)
        throw new EmptyStackException();
    Object result = elements[--size];
    elements[size] = null; // 다 쓴 참조 해제
    return result;
}

3. 객체의 임시 복사본에서 작업을 수행한 다음, 작업이 성공적으로 완료되면 원래 객체와 교체하는 것

  • 데이터를 임시 자료구조에 저장해 작업하는게 더 빠를 때 적용하기 좋은 방식
  • 어떤 정렬 메서드에서 정렬을 수행하기 전에 입력 리스트의 원소들을 배열로 옮겨 담는다. 배열을 사용하면 정렬 알고리즘의 반복문에서 원소들에 훨씬 빠르게 접근할 수 있다.
  • 정렬에 실패하더라도 입력 리스트는 변하지 않는 효과를 덤으로 얻게 된다.

4. 작업 도중 발생하는 실패를 가로채는 복구 코드를 작성하여 작업 전 상태로 되돌리는 방법

  • 내구성을 보장해야 하는 자료구조에 쓰이는데 자주 쓰이는 방법은 아니다.

실패 원자성은 항상 달성할 수 있는가?

  • 실패 원자성은 일반적으로 권장되는 덕목이지만 항상 달성할 수 있는 것은 아니다.
  • Error는 복구할 수 없으므로 AssertionError에 대해서는 실패 원자적으로 만들려는 시도조차 할 필요가 없다.

그럼 실패 원자성을 항상 보장해야 할까?

  • 실패 원자적으로 만들 수 있더라도 항상 그리 해야 하는 것은 아니다. 실패 원자성을 달성하기 위한 비용이나 복잡도가 아주 큰 연산도 있기 때문이다.
  • 메서드 명세에 기술한 예외라면 설령 예외가 발생하더라도 객체의 상태는 메서드 호출 전과 똑같이 유지되어야 하는 것이 기본 규칙이다. 이 규칙을 지키지 못한다면 실패 시의 객체 상태를 API 설명에 명시해야 한다.