회고

20220703 TIL #불변 객체를 사용하는 이유

paran21 2022. 7. 5. 00:38

개발을 시작하고 코딩을 하면서,

이 책에서는 몇 번을 읽어도 이해가 안되던 설명이 우연히 다른 걸 공부하다가  '아, 이런 뜻이었구나' 할 때가 있다.

 

자바를 공부하면서 이해가 잘 안되는 용어 중 하나가 '불변 객체'를 사용하는 것이었다.

 

그런데 김영한님의 JPA 강의를 듣다가 왜 불변객체를 권장하는지 조금 이해하게 된 것 같다.

모두 다 정확하게 이해한 건 아니지만, 앞으로 공부하는데 실마리가 될 것 같아서 기록해둔다.

 

primitive type과 달리 객체는 참조가 가능하다.

즉, 각각의 변수들이 같은 객체를 참조하고 있을 수 있다.

 

예를 들어, 새로운 Value a를 만들고, b가 a를 가리킨다면 둘은 같은 객체를 참조하게 된다.

public static void main(String[] args) {
    Value a = new Value(10);
    Value b = a;
}

따라서 둘의 hashCode를 출력해보면 동일한 hashCode를 갖는 것을 확인할 수 있다.

System.out.println("a : " + a.hashCode());
System.out.println("b : " + b.hashCode());

 

같은 객체를 가리키고 있기 때문에 a와 b모두 값은 10이다.

그리고 Setter를 사용해서 a의 값을 변경하면 a와 b 모두 변경된 값을 갖게된다.

System.out.println("a : " + a);
System.out.println("b : " + b);

a.setValue(20);

System.out.println("AFTER USING SETTER TO CHANGE VALUE");
System.out.println("a : " + a);
System.out.println("b : " + b);

 

만약에  a의 값 변경이 이 메서드가 아니라 다른 메서드에서 이루어졌다면 어떻게 될까?

a와 b가 같은 객체를 가리키고 있다는 사실을 모른다면 개발자는 의도치 않게 a뿐만 아니라 b의 값도 변경할 수 있다.

 

이렇게 개발자가 의도하지 않은 side effect를 방지할 수 있는 방법 중 하나는 Value를 불변객체로 만들어서 값이 변경되지 않도록 만드는 것이다.

값의 변경이 필요하다면, 해당 인스턴스의 값을 수정하는 것이 아니라 아에 새로운 인스턴스를 선언해야 한다(String이 대표적!).

 

이러한 맥락에서 setter를 권장하지 않는다고 볼 수 있다.

setter를 public으로 만들어 외부에서 해당 객체의 값을 수정할 수 있게 만들면 위와 같은 문제가 발생할 수 있다.

그래서 객체의 값을 수정할 수 있는 메서드는 만들지 않거나, private으로만 선언해서 외부에 노출하지 않도록 할 수 있다.

 

객체의 값을 수정할 수 없는 불변객체를 만들면 이런 문제를 더 원천적으로 차단할 수 있다.

그렇지만 이 경우 값을 수정할 때마다 새로운 인스턴스가 생성되므로 값의 수정이 잦은 경우에는 주의가 필요할 것 같다.

(일례로, String의 값을 + 경우 매번 새로운 String 인스턴스가 생성되기 때문에 StringBuilder와 같은 다른 객체를 사용하는 것이 낫다.)

 

 


 

 

코딩을 할 때, 개발자가 통제가 불가능한 혹은 인지하지 못하는 상황을 최소화하려는 노력이 중요한 것 같다.

이렇게 불변객체를 사용하고, setter와 같은 메서드는 주의하여 사용하는 것도 모두 의도하지 않은 상황이 발생하지 않도록 하려는 것이다.

나는 단지 지금 내가 코드를 짜고 있는 이 부분을 수정하거나 값을 바꿔준 것인데, 내가 생각하지 않은 곳에서 원하지 않은 로직이 발생한다면 결국 프로그램에 에러가 발생할 것이다.

특히 프로그램 규모가 방대해지면 무엇이 원인인지 찾기 어려울 것이다.

 

JPA를 사용할 때도 의도치 않은 쿼리가 발생하는 경우를 주의해야 하는데 비슷한 맥락에서 이해할 수 있을 것 같다.