HomeAboutMeBlogGuest
© 2025 Sejin Cha. All rights reserved.
Built with Next.js, deployed on Vercel
🛁
공부기록
/
📚
책 정리
/
🎨
Item76 - 가능한 한 실패 원자적으로 만들라
🎨

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

속성
9장
가능한 한 실패 원자적으로 만들라메서드를 실패 원자적으로 만드는 방법.1️⃣  불변 객체로 설계하자.2️⃣ 매개변수의 유효성을 검사하자.3️⃣  객체의 임시 복사본에서 작업을 수행한 후 성공하면 원래 객체와 교체하자.4️⃣  작업 도중에 발생하는 실패를 가로채는 복구 코드를 작성하여 작업 전 상태로 되돌리자.실패 원자성을 항상 달성시켜야 하는 것일까?실패 원자성을 만들 수 있으면 항상 만들어야 할까?결론
 

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

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

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

1️⃣  불변 객체로 설계하자.

  • 불변객체는 태생적으로 실패 원자적이다. 메서드가 실패하면 새로운 객체로 만들어지지 않을 수 있으나 기존 객체가 불안정한 상태에 빠지는 일은 없다.
  • String 클래스의 subString 메서드를 살펴보면 실패 원자적으로 만들어져 있습니다.
    • 기존 객체가 불안정한 상태에 빠지지 않는다.
    • 시작 인덱스가 0보다 작거나, 시작 인덱스가 끝 인덱스보다 크거나, 끝 인덱스가 현재 문자 길이보다 긴 경우에는 예외가 발생한다.
notion image
notion image
 

2️⃣ 매개변수의 유효성을 검사하자.

  • 객체의 내부 상태를 변경하기 전에 잠재적 예외의 가능성을 대부분 걸러낼 수 있다.
  • 아래는 stack의 pop 메서드이다. 코드를 보면 작업을 수행하기 전 index가 현재 원소의 수를 비교하는 작업을 진행하여 검사를 하고 있다.
notion image
notion image
 
  • 실패할 가능성이 있는 모든 코드를 객체의 상태를 바꾸는 코드보다 앞에 배치하는 방법도 존재한다.
    • 로직을 수정하기 전에 인수의 유효성을 검사하기 어려울 때 사용할 수 있으며 TreeMap을 예로 들어 잘못된 타입의 원소를 추가할 때 트리를 변경하기에 앞서 해당 원소가 들어갈 위치를 찾는 과정에서 ClassCastException을 던질 것이다.
 

3️⃣  객체의 임시 복사본에서 작업을 수행한 후 성공하면 원래 객체와 교체하자.

  • 데이터를 임시 자료구조에 저장해 작업하는게 더 빠를 경우 적용하기 좋은 방식이다.
  • 예를들어 List의 Sort 메서드가 해당된다 정렬하기 전에 원소들을 배열에 옮겨 닮고 그 다음에 정렬을 수행하도록 되어있다.
notion image
 

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

  • 이 방법은 주로 디스크 기반의 내구성을 보장해야 하는 자료구조에 쓰이게 되는데 자주 쓰이는 방법은 아니다.
 

실패 원자성을 항상 달성시켜야 하는 것일까?

  • 실패 원자성은 일반적으로 권장되는 부분이지만 항상 달성할 수 있는 것은 아니다.
    • 두 스레드가 동기화 없이 같은 객체를 동시에 수정한다면 그 객체의 일관성이 깨질 수 있다.
    • Error는 복구할 수 없기 때문에 AssertionError에 대해서는 실패 원자적으로 만들려는 시도조차 할 이유가 없다.
 

실패 원자성을 만들 수 있으면 항상 만들어야 할까?

  • 실패 원자적으로 만들 수 있더라도 항상 정답은 아니다.
    • 실패 원자성을 달성하기 위한 비용이나 복잡도가 아주 큰 연산도 있기 때문이다.
      • 그럼에도 문제가 무엇인지 알고 나면 실패 원자성을 공짜로 얻을 수 있는 경우가 많다.
    • 메서드 명세에 기술한 예외라면 설혹 예외가 발생하더라도 객체의 상태는 메서드 호출 전과 똑같이 유지되어야 한다는 것이 기본 규칙이다.
      • 이 규칙을 지키지 못한다면 실패 시의 객체 상태를 API 설명에 명시해야 한다. 이것이 이상적이나 아쉽게도 API 문서 상당이 잘 지켜지지 않고 있다.
 

결론

  • 실패 원자적은 호출된 메서드가 실패하더라도 해당 객체는 호출 전 상태를 유지해야하는 특성이다.
  • 그 특성을 갖기 위한 방법은 크게 네가지가 있었다.
    • 불변객체
    • 매개변수 검사
    • 임시복사본 만들기
    • 복구코드 작성
  • 원자성을 보장할 수 없을 때가 있다.
    • 두 스레드가 동기화 없이 같은 객체를 동시에 수정할 때
    • Error
  • 원자성을 최대한 보장해주는게 좋지만 항상 그런것은 아니다 비용이 높거나 복잡하다면 한번 더 생각해보자.
    • 또한 그러한 부분은 API 명세에 적어두자 (지키지 않는곳이 많다고 하니 우리는 작성합시당…😎)