근래 배운 몇 가지 패턴 정리: Provider, Builder, Delegation

Provider

정확히 말하면 디자인 패턴은 아니라고 한다. 자세한 설명은 [1]에 있다. Factory 패턴과 유사하나 외부 설정에 따라 다른 객체를 생성하는 패턴을 칭한다. 나쁜 패턴이라며 [1]과 함께 Constructor Injection 같은 방법을 써야 한다는 주장이 있지만, 실제로 잘 작성된 오픈소스 프로젝트들에서도 이러한 구현을 꽤 많이 볼 수 있다.

Builder

생성자에 전달되어야 할 파라메터가 다양해서 골치 아픈 경우 Builder 패턴이 좋은 해결책이 된다. 방법은 Builder 객체를 만들고 setter 를 통해 필요한 파라메터를 설정 한 후에 build() 메소드 호출을 통해 실제 객체를 생성한다.

Delegation

처음 Delegation 패턴을 봤을 때는 Interface의 구현과 차이점을 잘 발견하지 못했었다. 위키 피디아에도 설명이 있지만 언제 써야 하는지가 설명되어 있지 않았다. [3] 에서 이유를 찾았는데. 요약을 해보면,

  • 원래 있는 객체의 동작을 그대로 유지하면서 동작의 앞뒤에 처리를 추가하고 싶을 때
  • 호환되지 않는 인터페이스를 위한 Proxy 를 구현할 때
  • 실제 구현 사용 시 복잡도가 높은 콜 루틴을 단순하게 제공하려고 할 때

경우에 따라 서브클래싱과 함께 쓸 수 있을 것 같으며 데코레이터 패턴에서 주로 나타나는 패턴인 것 같다.

See Also

[1] Provider Model Design Pattern and Specification, Part 1
[2] Provider is not a pattern
[3] http://stackoverflow.com/questions/7168714/what-is-the-purpose-of-a-delegation-pattern/7168737#7168737

Advertisements

Jni Native를 통한 Rust 함수 호출

회사 허락을 맡아 홀로 프로젝트를 하나 시작했다. 큰 그림은 일부 컴포넌트를 Rust로 구현하고 컴포넌트간 연결은 rpc로 하는 것인데 아직 Rust 로 rpc 구현을 하기에 시간이 더 필요하다. 임시적인 수단으로 JNI를 통해 기존 컴포넌트에 연결을 하려고 한다.

그 외 프로젝트에 자세한 이야기는 나중에 설명하고 위 목적으로 Stackoverflow 에서 참고하고 https://github.com/Monnoroch/RustJni 를 참고해서 JNI를 테스트를 해봤다.

C 바인딩이 쉬운것은 Rust의 장점 중 하나인데 JNI 바인딩 역시 순조로웠다. 방법은 우선 아래와 같이 native 함수 인터페이스를 작성하고

아래와 같이 Rust 코드를 작성하면 된다.

이게 전부다. 위에서 사용된 chars_to_str와 str_to_jstring 는 아래 github repository에 있다.

https://github.com/hyunsik/jni-rs/blob/master/src/helper.rs

위 repository 는 https://github.com/Monnoroch/RustJni를 fork 해서 JNI 뿐 아니라 JNI 프로그램 작성 중에 반복되는 코드들에 대한 유틸리티 함수들을 추가할 계획이다.

그리고 아래는 JNI Native + Rust 를 위한 템플릿 프로젝트이다.

https://github.com/hyunsik/rust-jni-template


Oracle이 고려 중인 Java 9의 Unsafe API 제거 계획

성능이 중요한 꽤 많은 자바 프로젝트 (하둡 등 데이터 처리 프로젝트들 역시)이 Java Unsafe API에 의존하고 있다. Unsafe API는 JVM에서 공식적으로 제공하는 API가 아닌 Oracle JDK에서 내부적인 사용을 목적으로 제공하는 API이다. JNI와 다른 기술이며 콜 오버헤드 없이 직접 native 코드로 실행된기 때문에 빠르고, C 와 같이 메모리를 동적할당할 수 있으며 bounding check 없는 배열 접근 등 다소 위험하지만 성능 좋은 API를 100여가지 제공한다.

붙인 링크는 Oracle에서 JVM9 에서 Java Unsafe API 정말 제거하려는 계획과 지워질 경우 일어날 재앙에 대해서 언급한다. 아직까지는 계획일 뿐이고 계획을 직접 훑어보니 어느 정도의 대체 API도 고려하는 것 같기는 하다. 그럼에도 불구하고 그런일이 실제로 일어난다면 많은 자바 프로젝트들은 큰 변화를 겪어야 할 수 도 있다. 어쩌면 자바로 작성한 것이 의미가 없어질 정도로.. 어떤 프로젝트들은 헤비한 JNI 사용을 해야 할 것 이며 어떤 프로젝트들은 C++이나 기타 시스템 프로그래밍 언어로 이동을 해야 할지도 모르겠다.


해쉬 함수 구현 (hash function implementation) 링크 정리

이것도 한 3-4년전에 정리했다가 가끔 업데이트 한 것 같은데… 나름 괜찮은 링크가 몇 개 있어 공유한다. 이것도 앞으로는 이 페이지에서 업데이트를 하겠다. 오래 지나다보니 인터넷에 있는 정보라도 링크가 깨진 것들이 많아 지웠는데 아쉽다. 다행히 이 페이지는 web archive에서 찾을 수 있어 다행이다 싶다.


General

SW-based Implementations

HW-based Implementations


float과 long 타입의 implicit casting

4 byte 짜리 float이 8 byte 짜리 long보다 widen 더 넓은 범위를 표현하는 type 이었다. 지금까지 Tajo에서 float 과 long의 산술 연산에서 둘다 double로 casting 하고 처리했었는데 사실은 long을 float으로 casting 한 후 해야 IEEE 754에 기반한 결과가 나오는 것이었음.

(4월 28일 Updated ) precision은 당연히 64bit인 long이 더 높다. 하지만 수의 표현 범위만 봤을 때는 float이 더 넓다. 따라서 float과 long의 산술 연산은 long이 float으로 implicit conversion 되어진 후 계산된다.

  • float.MaxValue ~= 3.402823+e38
  • long.MaxValue ~= 9.223372+e18

(4월 28일 Update 2) 정밀도(precision)의 차이가 낮기 때문에 int, long에서 float 또는 long에서 double로 변환될 때 값이 손실 될 수 가 있다. 그러나 항상은 아님.

A widening conversion of an int or a long value to float, or of a long value to double, may result in loss of precision – that is, the result may lose some of the least significant bits of the value. In this case, the resulting floating-point value will be a correctly rounded version of the integer value, using IEEE 754 round-to-nearest mode (§4.2.4).