행복한 아빠

Java Jigsaw가 도대체 뭐지? - Java9의 핵심 본문

잡다한기록

Java Jigsaw가 도대체 뭐지? - Java9의 핵심

행복한아빠 2016. 9. 27. 00:57


Java 9 이야기가 솔솔 들립니다. Java 9의 특징 중 가장 주목할 만한 것이 Java jigsaw라는 프로젝트에서 착안한 모듈화 시스템이라는데 대충 소개한 글로는 뭔 소리인지 몰라서 한 번 찾아봤습니다. 자세한 스펙이나 기능요소보다는 Java Jigsaw가 말하려는 개념을 구체적으로 이해할 수 있도록 정리합니다.


새로운 모듈 시스템?

Java는 패키지의 name space나 패키징 방법을 제공하는 JAR 그리고 Maven이나 Gradle 같은 모듈 관련 기능 및 생태계가 비교적 잘 되어 있다고 믿었는데 난데없이 왜 새로운 모듈 시스템을 들고 나왔는지 이해가 안 갑니다.

그래서 Project Jigsaw DRAFT 문서의 프로젝트의 목적을 살펴봤습니다. (http://openjdk.java.net/projects/jigsaw/goals-reqs/03)

  • SE 플랫폼과 JDK를 작은 컴퓨터 디바이스에 보다 쉽게 경량화(scalable down)할 수 있게 한다.
  • Java SE 플랫폼의 전반적인 구현 부분과 특히 JDK 부분의 보안성과 유지관리성(maintainability)을 향상시킨다.
  • 애플리케이션의 성능을 높일 수 있게 하고
  • Java SE 그리고 EE 플랫폼에서 개발자들이 라이브러리와 애플리케이션 구성과 유지를 쉽게 만들어 준다.
음... 모듈화 잘 해서 위와 같이 한다는데 좋은 소리인데 뭘 어케하겠다는 건지...


뭐가 문제였나?

기존의 Java 패키징 메커니즘의 문제로 JAR/Classpath hell, 보안, performance 등의 문제도 지적하지만 이 모든 것의 원인은 캡슐화 지원이 부족한 것 때문이 아닌가 합니다. Java는 public, private과 같은 클래스 수준의 가시성 한정자(visibility modifier)가 있습니다. 그러나 이것은 클래스까지만 유효하지 패키지를 넘어서는 힘을 잃어버리게 됩니다.

예를 들어 우리는 JAR로 제공된 패키지의 클래스를 보면 어느 클래스를 써야할 지 알 수가 없습니다. 대부분의 클래스가 public이고 접근이 가능합니다. 그 안에는 API 설계자가 내부 구현을 위해 만든 내부용 API도 있을 겁니다. 기존에는 이 내부용 API(public 이라면) 접근이 가능합니다, JAR 로 제공되고 문서화가 잘 되더라도 클래스와 메소드가 public이라면 여러가지 이유로 API 설계자가 의도하지 않은 호출이 발생할 수 있습니다.

문제는 API 제공자가 기능 향상이나 리팩토링을 위해 이러한 내부용 API를 바꾸고 싶을 때 입니다. 누가 쓸 지 알 수 없는 상황에서 쉽게 바꿀 수 없는 노릇입니다.


Java Jigsaw는 어떻게 이 문제를 푸는가?

모듈을 만들고 모듈에 명시적으로 외부에서 호출할 수 있는 API를 선언합니다. 언어레벨에서 API 작성자가 외부에 노출한 API외에는 접근할 수가 없습니다.
뿐만 아니라 모듈은 그 모듈에서 사용할 다른 모듈을 선언합니다. JDK는 이 기능(feature)을 통해 모든 내부 API를 캡슐화하여 구성합니다.

모듈 선언 예) $ cat src/com/mycompany/module-info.java

1
2
3
4
5
6
module com.mycompay {
    // com.yourcomapny 를 사용할 거야
    requires com.yourcompany;
    // com.mycompany를 사용할 수 있어
    exports com.mycompany;
}
cs


경험담

프로젝트를 하면서 컴포넌트 기반 개발(CBD)을 위한 아키텍처를 구성하고 개발을 해 왔습니다. CBD의 일반적인 아키텍처는 컴포넌트의 인터페이스를 정의하고 이 인터페이스의 구현을 제공하는 것입니다. 외부 클라이언트는 이 인터페이스를 통해서만 그 기능을 호출하는 것이죠.


예를 들어 위의 구성을 가지면 UserService 인터페이스로 이 컴포넌트를 사용해야 합니다. 그런데 누군가 내부 구현을 위한 UserHelper 클래스에 유용한 API가 있어 이것을 사용하게 되었습니다. 말릴 수가 없습니다. 그리고 이 컴포넌트 설계자는 누군가 UserHelper 를 호출 했을지도 모른다는 두려움에 기능 개선을 위해 UserHelper 클래스를 변경할 수가 없습니다.

이러한 제약은 아키텍처 문서나 개발자 가이드에 적시하여 규칙으로 관리할 수 밖에 없습니다. 그러나 누군가는 약속되지 않은 API 호출을 하고는 합니다.
Java jigsaw의 모듈화 시스템은 이러한 문제를 깔끔하게 해결합니다.


지금까지 잘 살고 있는데 왜?

뭐 설계상의 난점과 그와 관련된 문제도 있지요. 그러나 그러지 않아도 Java 는 잘 돌고 있는데 위험(아래에 설명)을 무릅쓰고 이와 같은 큰 변화를 시도하는 이유가 뭘까요?

Project Jigsaw의 주요 목표는 한마디로 유연한 런타임 이미지를 만들 수 있도록 Java 플랫폼을 모듈화하는 것입니다. 즉 필요한 모듈만으로 경량화된 이미지를 만들기 위함입니다.

기존에는 JRE 일부분만 배포할 수가 없었습니다. 애플리케이션이 사용하지 않더라도 XML, SQL, Swing 같은 패키지는 항상 같이 배포되었습니다.
언어 레벨에서 모듈간의 의존성을 알 수 있으니 애플리케이션이 사용하는 모듈만 모아서 런타임 환경(이미지)를 만들 수 있습니다.

https://bugs.openjdk.java.net/secure/attachment/57772/jdk.png

JDK의 모듈 구조는 위와 같은 형태로 작게 나뉘어 질 것이며, 표준 API(SE, EE)뿐만 아니라  3rd party 라이브러리 심지어 우리가 만든 라이브러리에서도 필요한 것만 골라서 배포할 수 있습니다.

런타임 이미지가 작아진다는 것은 아래 이야기 하는 것들이 가능하다는 이야기입니다.


소형 디바이스

서버 사이드야 용량도 크고 성능도 좋아 상관없지만 라우터나 셋톱박스 같은 작은 디바이스는 괴롭습니다. 런타임 이미지가 작아지면 소형 디바이스에 여러모로 유리합니다.


서버 아키텍처

서버 쪽은 도커에 의해 애플리케이션이 컨테이너화 되는 추세입니다. 런타임 이미지가 작다면 경량의 도커 이미지가 가능하고 배포하고 관리하기 유리해집니다.
클라우드 컴퓨팅, 마이크로 서비스 등의 아키텍처 트랜드에 맞추기 위해, 런타임의 경량화 기반을 준비하는 것으로 볼 수 있습니다.


스타트업 시간과 성능

현재는 필요한 클래스를 순차적으로 로드하느라 JVM 구동 타임에 시간이 걸립니다. 또한 암시적으로 모든 클래스를 동적으로 호출할 수 있는 구조입니다. 모듈화 시스템은 필요한 모듈을 알기에 그것만 로드할 수 있습니다. 또한 모듈간의 호출구조가 정의되어 있기에 성능향상을 위한 기회를 얻을 수 있습니다.


JDK, JRE 통합?

JRE와 JDK는 사용목적에 따라 다르게 배포하고 있습니다. JDK가 JRE를 포함하여 추가적인 패키지를 더 제공하고 있죠. 모듈화 시스템을 제공하면 이러한 분리가 필요 없고 두 플랫폼은 같은 구조를 가지게 된다고 합니다.


넘어야 할 산들

언어 레벨에서 모듈간의 의존관계를 확실히 하면 이처럼 좋은 점이 많습니다. 그러나 넘어야 할 산들이 많습니다.

레가시 코드는 어쩌나

Java의 큰 장점 중 하나가 하위 호환성(Backward compatibility)인데, 이거 어떻게 풀지 두고 봐야겠습니다. Java 9에 레가시 코드를 쓸 경우 모듈화 시스템 관련 부분이 가장 큰 혼란이지 않을까 합니다.
Java 9을 쓴다면 자신의 코드 중 나도 모르게 내부 API 쓴 부분이 있는지 검사해야 할 듯 합니다. (컴파일러나 다른 도구가 체크하겠지만..)


com.sun.*

com.sun과 같은 비공식적인 API는 되도록 사용하지 말라고 경고했습니다. 그러나 성능 등의 많은 이유 때문에 비공식 API를 사용하고는 합니다.
이런 종류의 API를 쓴 코드는 그 대가를 치를지도 모르겠습니다만. com.sun.* 같이 특별한 이유로 흔히 사용했던 API에 대한 고민과 지원이 있을 듯 합니다.


개발도구들

lib/rt.jar나 lib/tool.jar 같은 내부 JAR파일들의 접근이 불가합니다. 이러한 JAR 파일은 IDE나 빌드도구들이 많이 사용하는데 개발도구들이 영향을 많이 받을 듯 합니다.

이와 같이 람다같은 기능과는 달리 레거시 코드에 상당한 영향을 줄 수가 있습니다. Java 9이 출시 되더라도 바로 Java 9으로 이전 하는 것은 위험요소가 있을 듯 합니다.



언어 레벨에서의 모듈화 시스템

언어 레벨에서 모듈화를 지원한다는 것은 도구 레벨에서 불가능한 것들을 가능하게 할 것입니다. 제일 큰 부분은 기본적으로 java runtime 부분을 쪼갤 수 없었던 것을 쪼갤 수 있게 한 것이죠. 이러면 배포시 사용하지 않는 Swing, XML, SQL 같은 패키지는 제외하고 배포할 것입니다.
이런 특징은 여러분의 프로젝트에서도 가능하여 최소한의 런타임 이미지를 배포하여 가볍게 운용할 수 있습니다.

지금처럼 굉장히 많은 클래스 집단이 하나의 JAR로 배포되고 관리되는 대신 굉장히 작은 모듈단위로 배포될 것입니다.
모듈의 단위가 작아질 때의 문제점은 모듈간의 의존관리가 어려워지고 매우 복잡해 진다는 것입니다.
잘못하면 cyclic dependency(모듈간 상호 참조)가 빈번히 발생할 가능성도 적지 않습니다. 필요한 API 있다고 마구 호출하지 말고 설계에 신경을 써야 할 것입니다.


그래서

제가 요즘, 규칙에 좀 관대한 언어를 쓰고 있지만 경우에 따라 Java와 같이 규칙이 엄격한 언어가 유리하기도 합니다.
개인적으로는 규칙이 엄격한 Java 언어에서 무척 반길 만한 내용입니다. 실제 어떻게 적용될 지, 그리고 이 방식의 API 구성이 얼마나 확산될 지 기대됩니다.

처음은 Java 클래스의 가시성 정도로 충분하다고 생각 했었지
그러나 프로그램이 커지다 보니 클래스의 묶음도 필요 했지
클래스 묶음 단위로 관리하고 싶었는데 클래스들 사이가 좋아 다른 동네의 클래스도 막 호출하는 거야
도대체 어떤 클래스가 어떤 클래스를 호출 하는지 알 수가 없네
안되겠어. 클래스 묶음에서 호출할 수 있는 대표를 정하고 대표 하고만 이야기 하도록 하자
그래 클래스 묶음 단위로 관리하려고 하는 거야.
그걸 모듈이라고 불러...

참조:

  • http://openjdk.java.net/projects/jigsaw/
  • http://blog.codefx.org/java/dev/motivation-goals-project-jigsaw/


7 Comments
댓글쓰기 폼