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

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

메서드를 실패 원자적으로 만드는 방법

불변 객체로 설계

불변 객체는 태성적으로 실패 원자적이다. 메서드가 실패하면 새로운 객체가 만들어지지는 않을 수 있으나 기존 객체가 불안정한 상태에 빠지는 일은 결코 없다.

매개변수의 유효성 검사

작업 수행에 앞서 매개변수의 유효성을 검사해서 메서드를 실패 원자적으로 만들 수 있다. 객체의 내부 상태를 변경하기 전에 잠재적 예외의 가능성 대부분을 걸러낼 수 있는 방법이다.

public Object pop() {
    if(size == 0)
        throw new EmptyStackException();
    Object result = elements[--size];
    elements[size] = null;
    return result;
}

이와 비슷한 취지로 실패할 가능성이 있는 모든 코드를, 객체의 상태를 바꾸는 코드보다 앞에 배치하는 방법도 있다. 계산을 수행해보기 전에는 인수의 유효성을 검사해볼 수 없을 때 앞의 방식에 덧붙여 쓸 수 있는 기법이다.

객체의 임시 복사본에서 작업 수행

객체의 임시 복사본에서 작업 수행한 다음, 작업이 성공적으로 완료되면 원래 객체와 교체하는 방법이다. 데이터를 임시 자료구조에 저장해 작업하는 게 더 빠를 때 적용하기 좋은 방식이다.

실패를 가로채는 복구 코드 작성

작업 도중 발생하는 실패를 가로채는 복구 코드를 작성하여 작업 전 상태로 되돌리는 방법이다. 주로 내구성을 보장해야 하는 자료구조에 쓰이는데, 자주 쓰이는 방법은 아니다.

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

Comments