2016년 11월 29일 화요일

Immutability

Converter utility class 에서 convert table 에 대한 immutable collection을 사용하는 게 필요한지, 필요하다면 왜 필요한지 검토해 볼까한다. 제대로 결론이 나올지 모르겠지만...

converter utility class 란?

health project에서 clean architecture(onion architecture) 를 적용하면서 각 layer 간의 data type 변환을 위해서 만들어 놓은 utility class 이다.
일반적으로 다음과 같은 형태를 가진다.

class XXXConverter {
   final Map<A, B> XXXMap = Map.create().put(a, b).put(a1, b1).put(a2, b2);

   B convert(A a) {
       return XXXMap.get(a);
   }

   A convert(B b) {
       return XXXMap.reverse().get(b); // guava bimap 사용시
   }
}

health project의 production code 에서는 Map<A, B> 대신에 Guava library 의 ImmutableMap / ImmutableBiMap 을 이용하여 코드가 작성되어 있다.

Guava ImmutableCollections

Guava library 에서 설명하는 guava 의 immutable objcet 의 장점은 아래와 같다.
(https://github.com/google/guava/wiki/ImmutableCollectionsExplained)

  • Safe for use by untrusted libraries.
  • Thread-safe: can be used by many threads with no risk of race conditions.
  • Doesn't need to support mutation, and can make time and space savings with that assumption. All immutable collection implementations are more memory-efficient than their mutable siblings (analysis)
  • Can be used as a constant, with the expectation that it will remain fixed
이에 비해서 jdk 에서 제공하는 Collections.unmodifibleXXX() 는 다음과 같은 단점이 있다고 한다.

  • unwieldy and verbose; unpleasant to use everywhere you want to make defensive copies
  • unsafe: the returned collections are only truly immutable if nobody holds a reference to the original collection
  • inefficient: the data structures still have all the overhead of mutable collections, including concurrent modification checks, extra space in hash tables, etc.

Converter에서 ImmutableCollections

다시 converter 로 돌아와서 converter 에서 ImmutableMap 을 사용하는 게 의미가 있을까?
내가 내린 결론은,
Converter 목적상으로는 사용의 의미가 없다. 해당 map 을 copy 해서 사용할 이유도 없고 외부에 open 할 이유도 없다. 단순히 Converter class 내에서 matching table 역할만 하기 때문에 동작중에 내용이 변경되지 않는다고 가정할 수 있다.(100%???) matching table 의 크기도 크지 않기 때문에 속도나 메모리의 잇점도 크지 않다. 따라서 반드시 사용할 이유는 없어 보인다. Collections.unmodifiableXXX() 만으로도 충분하다. 
게다가 Guava 사용시에 proguard 사용하지 않으면, method 갯수 limit 도 신경써야 한다.(이 부분은 guava 에서는 android에서는 proguard 사용을 당연히 가정하기 때문에 문제 안되는다고 명시되어 있다. proguard 를 잘 적용하면 문제 안되겠지...)


Immutable Object

Immutable object 를 어떻게 만드는지 설명하고 있다. Immutability 는 functional programming 에서는 가장 강조하는 개념(?)이다. multi-thread 환경에 가장 강점을 발휘한다. java 에서 immutable object 를 만들기 위해서는 아래와 같이 한다.

- 모든 member 를 final 로 지정하고,
- class 도 final 로 지정한다.
- 최소 1개의 constructor 를 제공
- no-argument constructor 는 제공하지 않는다.
- setter 를 제공하지 않는다.
- you need to make sure you defensively copy any object references you return from getXXX methods

< Immutable Address class >
public final class Address {
    private final String name;
    private final List<String> streets;
    private final String city;
    private final String state;
    private final String zip;

    public Address(String name, List<String> streets, 
                   String city, String state, String zip) {
        this.name = name;
        this.streets = streets;
        this.city = city;
        this.state = state;
        this.zip = zip;
    }

    public String getName() {
        return name;
    }

    public List<String> getStreets() {
        return Collections.unmodifiableList(streets);
    }

    public String getCity() {
        return city;
    }

    public String getState() {
        return state;
    }

    public String getZip() {
        return zip;
    }
}

장점
- Immutable classes make a host of typically worrisome things in Java go away.
- Immutable objects are also automatically thread-safe and have no synchronization issues.
- one of the best features of immutable classes is how well they fit into the composition abstraction.


from wikipedia(https://en.wikipedia.org/wiki/Immutable_object#Java)
final MyObject m = new MyObject(); //m is of reference type
m.data = 100; // OK. We can change state of object m (m is mutable and final doesn't change this fact)
m = new MyObject(); // does not compile. m is final so can't be reassigned


Google AutoValue


https://github.com/google/auto/tree/master/value


Generated immutable value classes for Java 1.6+ Kevin Bourrillion, Éamonn McManus Google, Inc.
원본 code :
https://github.com/google/auto/blob/master/value/userguide/builders.md

generated code :
https://github.com/google/auto/blob/master/value/userguide/generated-builder-example.md

최종 결론

Immutable 은 좋은 것이여!
Converter 에서도 쓰고, 모든 곳에서 사용하자. 
극단으로 사용해서 습관화하자.(??)

덧붙임.
Immutable class 를 많이 사용하면 GC 가 많이 돌수도 있다는 우려도 있다.
객관적인 자료는 없지만, 엄청나게 큰 시스템이 아니면 지금과 같은 h/w 사양에서 크게 문제가 되지는 않을 것 같다.
언어적으로는 memoization이 이런 문제에 대한 해결책 같은 걸까? 아니면 다른 개념인가...