컴퓨터 프로그램을 고유의 기능으로 나누는 동작을 권장하는 원칙. 패키지 구분으로 그룹을 나눌 수 있다고 생각할 수 있지만, 모듈은 클래스가 어떤 다른 클래스를 볼 수 있는지를 컴파일 시간에 정교하게 제어할 수 있다.
세부 구현을 숨기도록 장려하는 원칙. 소프트웨어를 개발할 때 요구사항은 자주 바뀐다. 세부 구현을 숨김으로 프로그램의 어떤 부분을 바꿨을 때 다른 부분까지 영향을 미칠 가능성을 줄일 수 있다.(캡슐화: 특정 코드 조각이 애플리케이션의 다른 부분과 고립되어 있음을 의미)
잘 설계된 자바 소프트웨어는 관심사 분리와 정보 은닉 원칙을 잘 따라야한다. 요즘에는 자바 애플리케이션이 커지면서 접근제한자를 이용해 메서드나 필드 클래스의 접근을 제한하는 방식에 한계를 느끼게 되었고, 모듈 기능이 나오게되었다.
자바 9 이전까지는 모듈화된 소프트웨어 프로젝트를 만드는 데 한계가 있었다. 자바는 클래스, 패키지, JAR 세 가지 수준의 코드 그룹화를 제공한다. 클래스는 접근 제한자와 캡슐화를 지원했지만, 패키지와 JAR 수준에서는 캡슐화를 지원하지 않았다.
패키지의 경우 다른 패키지에서 사용하기 위해서는 내부 요소들을 public으로 선언해줘야한다. 즉, 해당 패키지의 클래스와 인터페이스가 모두에게 공개된다. 내부에서만 사용할 목적으로 만들었어도 임의적으로 조작할 수 있게 된다.
자바는 클래스를 모두 컴파일한 다음 보통 한 개의 JAR 파일에 넣고 클래스 경로에 이 JAR 파일을 추가해 사용한다. 그러면 JVM이 동적으로 클래스 경로에 정의된 클래스를 필요할 때 읽어 사용한다.
클래스 경로에는 같은 클래스를 구분하는 버전 개념이 없다. 이 경우 서로 다른 버전의 같은 라이브러리가 존재하면 어떤 일이 벌어질지 예측할 수 없다.
또 클래스 경로는 명시적인 의존성을 지원하지 않는다. 각 JAR에 있는 모든 클래스는 classes라는 한 주머니로 합쳐진다. 한 JAR가 다른 JAR에 포함된 클래스 집합을 사용하라고 명시적으로 의존성을 정의하는 기능을 제공하지 않는것이다.
Maven이나 Gradle 같은 빌드 도구는 이런 문제를 해결하는데 도움을 준다. 하지만 자바 9이전에는 자바, JVM 누구도 명시적인 의존성 정의를 지원하지 않았다. 결국 JVM이 ClassNotFoundException 같은 에러를 발생시키지 않고 애플리케이션을 정상적으로 실행할 때까지 클래스 경로에 클래스 파일을 더하거나 클래스 경로에서 클래스를 제거해보는 수밖에 없다. 모듈 시스템을 이용하면 컴파일 타임에 이런 종류의 에러를 모두 검출할 수 있다.
(나중에 다시 읽기)