불변 객체(Immutable Object)

3

개념정리

목록 보기
5/10
post-thumbnail

사랑이 아니라 스뎅이니까!

왜 불변 객체에 관심이 생긴거야?

지난번에 엘레강트 오브젝트를 읽고 글을 썼는데, 거기서 불변 객체에 대해 깊은 감명을 받았지만, 다른 사람에게 왜 불변 객체를 써야 하는지 설명하려니 못할 것 같다는 말을 했었다.

그래서 나도 더 자세히 알고싶고, 다른 사람에게도 후에 설명할 일이 있다면 이 글을 보여주고 싶어서 관심을 가지고 작성하게 되었다.

시작하기 전에 포인트 정리

  1. 객체의 상태가 변함으로 인해 생기는 문제가 발생하지 않는다.
    • 그로 인한 부수효과도 존재하지 않기에 문제가 발생했을 때 발생 지점이 명확해진다.
    • 별도의 처리 없이도 원자성을 얻을 수 있다.
  2. 아무리 많은 스레드가 객체에 접근해도 스레드 안전(Thread safe) 하다.
  3. NULL 참조 같은 불필요한 행위를 하지 않게 된다.
  4. 생성자로만 초기화가 가능하기 때문에 시간적인 결합이 사라지고, 코드가 작고 단순해진다.
  5. 결론적으로 유지보수 하기가 쉬워진다.

위키백과에서 말하는 불변 객체

위키백과 불변 객체 링크

객체 지향 프로그래밍에 있어서 불변객체(immutable object)는 생성 후 그 상태를 바꿀 수 없는 객체를 말한다.

불변 객체는 멀티 스레드 프로그래밍에서도 유용하다. 데이터가 불변 객체에 저장돼 있다면 복수의 스레드에 의해서 특정한 스레드의 데이터가 변경될 우려없이 데이터에 접근할 수 있다. 즉, 배타 제어(mutual exclusion)를 할 필요가 없다. 쉽게 말해 불변 객체가 가변 객체보다 스레드 세이프(Thread-safe) 하다고 생각하면 된다.

불변이란, 객체가 컴퓨터의 메모리 내에서 쓰기를 할 수 없다는 뜻이 아니다. 오히려 불변은 컴파일 시의 문제이며, 프로그래머가 「무엇을 해야하는가」 이지 반드시 「무엇이 가능한가」가 아니다.

엘레강트 오브젝트에서 읽은 불변 객체

모든 클래스를 상태 변경이 불가능한 불변 클래스(immutable class)로 구현하면 유지보수성을 크게 향상시킬 수 있습니다.

가변 객체는 전반적인 객체 패러다임의 오용입니다.

  • 식별자 가변성(Identity Mutability)
    • 불변 객체를 사용하면 객체를 생성 한 후에는 상태 변경이 불가능하기 때문에 '식별자 가변성' 문제가 발생하지 않습니다.
  • '실패 원자성(Failure Atomicity)'이란 완전하고 견고한 상태의 객체를 가지거나 아니면 실패하거나 둘 중 하나만 가능한 특성입니다.
    • 가변 객체를 사용하더라도 '실패 원자성'이라는 목표를 당성할 수 있지만, 이를 위해서는 특별한 주의를 기울여야 합니다.
    • 반면에 불변 객체를 사용하면 별도의 처리 없이도 원자성을 얻을 수 있습니다.
  • 시간적 결합(Temporal Coupling)
    • 가변 객체의 수가 많은 상황에서 가변 객체들을 처리하는 연산들의 순서를 일일이 기억해야 한다면 유지보수에 있어 어려움이 얼마나 클지 한 번 상상해 보기 바랍니다.
    • 불변성을 활용하면 코드 전반적으로 구문 사이에 존재하는 시간적인 결합을 제거할 수 있습니다.
  • 부수효과 제거(Side effect-free)
    • 객체가 가변적일 때는 기본적으로 누구든 손쉽게 객체를 수정할 수 있습니다.
    • 클래스를 불변으로 만들면 어떤 누구도 객체를 수정할 수 없습니다. 그리고 객체의 상태가 변하지 않았다고 확신할 수 있습니다. 코드가 제대로 동작하지 않는 경우에도 부수효과가 발생한 위치를 찾을 필요가 없습니다.
  • NULL 참조 없애기
    • 코드가 if name != null이라는 문장으로 가득 찰 것입니다.
    • NULL의 존재 자체가 이런 형편없는 프랙티스를 따르도록 조장합니다.
    • 모든 객체를 불변으로 만들면 객체 안에 NULL을 포함시키는 것이 애초에 불가능해집니다. 다시 말해서 작고, 견고하고, 응집도 높은 객체를 생성할 수 밖에 없도록 강제되기 때문에 결과적으로 유지보수하기에 훨씬 더 쉬운 객체를 만듭니다.
  • 스레드 안정성(Thread Safety)이란 글자 그대로 객체가 여러 스레드에서 동시에(concurrently) 사용될 수 있으며 그 결과를 항상 예측가능하도록 유지할 수 있는 객체의 품질을 의미합니다.
    • 이와 같은 병행성 이슈는 발견하고, 디버깅하고, 해결하기 가장 어려운 문제 중 하나입니다. 재현이 매우 어렵기(때로는 아예 불가능하기) 때문입니다. 테스트를 여러 번 실행해야 하며, 그렇게 한다고 해도 문제가 겉으로 드러난다는 보장이 없습니다.
    • 불변 객체는 실행 시점에 상태를 수정할 수 없게 금지함으로써 이 문제를 완벽하게 해결합니다. 어떤 스레드도 객체의 상태를 수정할 수 없기 때문에 아무리 많은 스레드가 객체에 접근해도 문제가 없습니다.
  • 더 작고 더 단순한 객체
    • 객체가 더 단순해질 수록 응집도는 더 높아지고, 유지보수하기는 더 쉬워집니다.
    • 불변 객체가 작은 이유는 생성자 안에서만 상태를 초기화할 수 있기 때문입니다. 인자를 10개씩이나 받는 생성자를 만들려는 사람은 없습니다.

마무리

그러니까 불변 객체를 사용합니다.
불변 객체 뿐만 아니라 불변성도 지키도록 노력합시다.

OOP에서도 FP에서도 강조하는 공통적인 키워드는 '불변(Immutable)' 입니다.

profile
지상 최강의 개발자 쥬니니

0개의 댓글