JAVA/Effective Java

[아이템 76] 가능한 한 실패 원자적으로 만들라

꾸준함. 2024. 3. 29. 12:39

실패 원자성

  • 호출된 메서드가 예외 발생으로 인해 실패하더라도 객체가 메서드 호출 전 상태를 유지하는 특성
  • 실패 원자성이 보장되면 Checked Exception을 던졌을 때 호출자가 오류 상태를 복구할 수 있으므로 유용함

 

메서드를 실패 원자적으로 만드는 방법은 총 네 가지가 있으며 다음과 같습니다.

  • 불변 객체로 설계
  • 매개변수 유효성 검사
  • 복사본에 로직을 수행 후, 성공적으로 수행이 완료될 경우에만 원본 객체와 Swap
  • 작업 도중의 에러를 가로채는 복구 코드를 작성하여 롤백

 

1. 불변 객체로 설계

 

  • 불변 객체는 생성 시점에 고정되어 절대 변하지 않기 때문에 태생적으로 실패 원자적
  • 메서드가 실패하면 새로운 객체가 생성되지 않을 수 있으나 기존 객체가 불안정한 상태에 빠지는 일은 없음

 

2. 매개변수 유효성 검사

 

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

 

 

  • 비슷한 취지로 실패 가능성이 있는 모든 코드를 객체의 상태를 바꾸는 코드보다 앞에 배치하는 방법도 존재
    • 계산을 수행해 보기 전 인수의 유효성을 검사해 볼 수 없을 때 앞서의 방식에 덧붙여 쓸 수 있는 기법
    • ex) TreeMap은 원소들을 어떤 기준으로 정렬하며 TreeMap에 원소를 추가하려면 해당 원소가 TreeMap의 기준에 따라 비교할 수 있는 타입임을 보장해야 함
      • 엉뚱한 타입의 원소를 추가하려들면 트리를 변경하기 앞서, 해당 원소가 들어갈 위치를 찾는 과정에서 ClassCastException 예외 던짐

 

TreeMap의 put 메서드
TreeMap의 compare 메서드

 

 

3. 복사본에 로직을 수행 후, 성공적으로 수행이 완료될 경우에만 원본 객체와 Swap

 

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

 

 

4. 작업 도중의 에러를 가로채는 복구 코드를 작성하여 롤백

 

  • 주로 (디스크 기반의) 내구성을 보장해야 하는 자료구조에 쓰이는데, 자주 쓰이는 방법은 아님

 

실패 원자성을 보장할 수 없거나 필요 없는 케이스

  • 실패 원자성은 일반적으로 권장되는 덕목이지만 항상 달성할 수 있는 것은 아님
  • ex) 멀티 쓰레드 환경에서 동기화 없이 같은 객체를 동시에 수정할 경우 해당 객체의 일관성이 깨질 수 있음
    • 따라서, ConcurrentModificationException을 잡아냈다고 해서 그 객체가 여전히 쓸 수 있는 상태라고 가정해서는 안됨

 

  • Error는 복구할 수 없으므로 AssertionError에 대해서는 실패 원자적으로 만들려는 시도조차 할 필요 없음
  • 실패 원자적으로 만들 수 있더라도 실패 원자성을 달성하기 위한 비용이나 복잡도가 아주 큰 연산일 경우 보장하지 않아도 됨
    • ex) 대용량 파일을 정렬하거나 검색할 때는 전체 파일을 메모리에 로드하는 것은 불가능할 수 있으며, 대신 파일을 여러 조각으로 나누어 처리해야 할 수 있음
    • 이러한 작업을 수행할 때 실패 원자성을 보장하는 것은 매우 어려울 수 있음

 

결론

  • 메서드 명세에서 기술한 예외라면, 예외가 발생하더라도 발생하기 전의 객체와 동등한 상황 즉 실패 원자성을 보장해야 함
  • 그러나, 실패 원자성을 담보할 수 없다면 예외 이후 객체의 상황을 API 설명에 명시해야 함

 

참고

이펙티브 자바

반응형