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