본문 바로가기
Homo Faber/Maven Definitive Guide

1장. 아파치 메이븐 소개

by javauser 2008. 10. 28.

비록 메이븐에 대해 수많은 참고들이 온라인 상에 있지만, 권위가 있는 참조와 소개로 제공되는 메이븐 소개에 대해 단일하고 잘 쓰여진 내용이 없다. 여러가지 애쓴 보람 끝에 유용한 참고 자료를 포함한 내용을 제공하는 것이다.

1.1 메이븐...무엇인가?

이 물음에 대한 대답은 여러분들의 관점에 달려있다. 대다수의 메이븐 사용자들은 메이븐을 소스 코드로부터 배포 가능한 산출물을 만드는데 사용되는 도구인 “빌드 도구”로 지칭하려 한다. 빌드 담당자와 프로젝트 관리자들은 메이븐을 프로젝트 관리 도구로 더 많은 이해가 필요한 것으로 참고하려고 한다. 차이가 무엇인가? 앤트와 같은 빌드 도구는 사전 프로세싱(preprocessing), 컴파일(compilation), 패키징(packaging), 테스팅(testing), 배포(distribution)에만 집중한다. 메이븐과 같은 프로젝트 관리 도구는 빌드 도구에서 발견되는 기능의 상위 개념을 제공한다. 빌드 기능을 제공하는 것 이외에, 메이븐은 레포트를 실행하고, 웹 사이트를 만들며, 작업 팀의 멤버 간의 커뮤니케이션을 촉진시킬 수 있다.

다음은 아파치 메이븐의 다소 공식적인 정의이다. 메이븐은 프로젝트 객체 모델 (Project Object Model), 표준들, 프로젝트 생명주기, 의존성 관리 시스템, 생명주기에 정의된 단계에서 플러그인 goal을 실행하는 로직을 포함하는 프로젝트 관리 도구이다. 메이븐을 사용할 때 잘 정의된 프로젝트 객체 모델을 사용한 프로젝트를 기술하며, 메이븐이 그 다음에 공유된(혹은 사용자가 만든) 플러그인들로부터 cross-cutting 로직을 적용한다.

메이븐이 “프로젝트 관리” 도구이다라는 사실로 인해서 멀리하지 마라. 만일 빌드 도구로만 생각한다면, 메이븐은 그 역할을 수행할 것이다. 사실, 2부의 처음 몇몇 장에서는 프로젝트 빌드와 배포를 위한 메이븐 사용이라는 가장 공통적인 유스케이스를 다룬다.

1.2 설정보다 규약 우위 (Convention over Configuration)

설정보다 규약 우위는 단순한 개념이다. 시스템, 라이브러리, 프레임워크들은 시스템은 “단지 동작해야” 한다는 불필요한 설정을 필요로 하지 않고 의미있는 기본값으로 간주해야 한다. Ruby on Rails와 EJB3와 같은 유명한 프레임워크는 초기 EJB 명세와 같이 설정의 복잡성의 반작용으로 이러한 원칙을 고수하는 것에서 시작했다. 설정보다 규약 우위의 예가 EJB3의 저장과 같은 것이다. 특정 빈을 저장으로 만드는데 필요하는 것은 해당 클래스를 @Entity로 표시하는 것이다. 프레임워크는 그 다음에 클래스의 이름과 속성의 이름으로부터 테이블 명과 컬럼명을 간주한다. 필요한 경우 이러한 이름을 겹쳐씀으로써 대체하는 기능이 제공되지만, 프레임워크에서 제공하는 기본값은 빠른 프로젝트 실행 결과를 낳는다는 것을 깨달을 것이다.

메이븐은 프로젝트에 대한 의미있는 기본 값을 제공함으로써 개념에 부합한다. 별도의 변경 없이 소스 코드는 ${basedir}/src/main/java 에 위치하는 것으로 가정하며 리소스는 ${basedir}/src/main/resources 에 위치하는 것으로 가정한다. 테스트는 ${basedir}/src/test 에 위치하는 것으로 가정하며, 프로젝트는 JAR (Java ARchive) 파일로 만들어지는 것으로 가정한다. 메이븐은 바이트 코드를 ${basedir}/target/classes 에 컴파일하고 그 다음에 ${basedir}/target 에 배포 가능한 JAR 파일을 생성하는 것을 원한다고 가정한다. 비록 이러한 것이 하찮은 것을 보이겠지만, 대부분의 앤트 기반 빌드가 모든 하위 프로젝트에 이러한 디렉토리의 위치를 정의해야 한다는 사실을 생각해보자. 메이븐의 설정보다 규약 우위에 대한 적용은 단순한 디렉토리 위치에만 국한되는 것은 아니다. 메이븐의 핵심 플러그인들은 소스 컴파일, 배포 패키징, 웹 사이트 생성, 그리고 많은 다른 프로세스에 대한 공통된 규약들을 적용한다. 메이븐의 강점은 “자기 주장이 강하다”라는 데에서 기인한다. 메이븐은 정의되어 있는 생명주기와 라이브러리들과 웹 어플리케이션을 빌드하는 방법을 아는 공통된 플러그인들을 가진다. 만일 규약을 따른다면, 메이븐은 거의 제로에 가까운 노력을 요할 것이다. – 소스를 정확한 디렉토리에 위치시키면, 메이븐이 나머지를 모두 수행하게 된다.

“설정보다 규약 우위” 라는 규칙을 따르는 시스템을 사용하는 한가지 부수 효과는 최종 사용자가 특정 셋업을 사용하도록 강요받는 느낌을 받는다는 것이다. 메이븐이 요지부동한 몇가지 중앙 설정을 가지고 있는 것이 확실히 사실이지만, 대부분의 기본값들은 변경이 가능하다. 예를 들어, 프로젝트의 소스 코드와 리소스의 위치는 변경이 가능하며, JAR 파일의 이름도 수정이 가능하고, 플러그인의 변경 개발을 통해 거의 대부분의 행위가 특정 환경의 요구사항에 맞게 변경할 수 있다. 만일 규약을 따르지 않는다면, 메이븐은 요구사항을 부합하기 위해서 기본값을 수정하도록 강요할 것이다.

1.3 공통 인터페이스

메이븐이 소프트웨어 빌드에 대한 공통 인터페이스를 제공하기 전에, 모든 단일 프로젝트에서는 누군가가 전적으로 완전한 사용자 개발 빌드 시스템을 관리하고, 개발자가 자신들이 기여하려는 각각의 새로운 프로젝트에 대한 특성을 배우기 위해 소프트웨어 개발과는 동떨어진 시간을 가졌어야만 했다. 2001년에 톰캣과 같은 프로젝트를 빌드하는 것보다 아파치의 터빈과 같은 프로젝트를 빌드하는 전혀 다른 접근방법을 접할 수 있었을 것이다. 만일 새로운 소스 분석 도구가 소스 코드에 대한 정적인 분석을 수행한다든지, 혹은 누군가가 새로운 단위 테스팅 프레임워크를 개발했다면, 모든 사람은 자신들이 하고 있었던 것을 버리고 각각의 프로젝트의 빌드 환경에 어떻게 적용할지를 이해하는 것이 필요할 것이다. 어떻게 단위 테스트를 실행할 것인가? 수천가지의 다른 답들이 있다. 도구와 빌드 절차에 대한 수많은 인자에 의해서 해당 환경을 결정했었다. 메이븐이전의 시대는 비효율의 시대였다. – “빌드 엔지니어”의 시대

오늘날 대부분의 오픈 소스 개발자들은 새로운 소프트웨어 프로젝트를 관리하기 위해 메이븐을 사용했거나 현재 사용 중이다. 이러한 추이는 한 빌드 도구에서 다른 것으로 이동하는 개발자가 적어지고 프로젝트 빌드에 대한 공통 인터페이스를 적용하기 시작하는 개발자가 많아진다는 것이다. 소프트웨어 시스템이 점점 더 모듈화 됨에 따라 빌드 시스템은 점점 더 복잡해지고 있으며, 프로젝트의 수는 급등하게 된다. 메이븐 이전에, 서브버전에서 아피치의 ActiveMQ나  ServiceMix와 같은 프로젝트를 체크아웃 받아서 소스에서 빌드하려고 할 때 각각의 특정 프로젝트에 대한 빌드 시스템을 이해하기 위해 한 시간 가량의 추가 작업을 했어야 했다. 프로젝트가 빌드에 필요한 것이 무엇인가? 다운로드 받을 필요가 있는 라이브러리가 어떤 것인가? 다운로드 받은 것을 어디에 넣어야 하는가? 빌드에서 어떤 goal을 실행할 수 있는가? 가장 좋은 경우에는 새로운 프로젝트의 빌드를 해결하는데 몇 분만 걸리며, 가장 안좋은 경우에는 (자카르타 프로젝트의 기존 서블릿 API 구현과 같은) 프로젝트의 빌드가 어려워서 새로운 개발자가 소스를 수정하고 프로젝트를 컴파일하는 지점에 도달하는데 수시간이 걸릴 수도 있다. 요즈음, 메이븐을 사용하면 소스를 체크아웃 받고, mvn install 을 실행하면 된다.

메이븐이 의존성 관리와 플러그인을 통한 공통 로직의 재사용을 포함하여 많은 장점을 가져다주지만, 성공할 수 있었던 핵심 근거는 소프트웨어를 빌드하는데 공통 인터페이스를 정의했다는 것이다. 아파치 Wicket과 같은 프로젝트가 메이븐을 사용하는 것을 살펴보면 소스를 체크아웃 받고 부담없이 mvn install을 사용해서 빌드한다는 것을 가정한다. 자동차 키를 어디에 꽂는지 알고 있으며, 가속 페달이 오른쪽에 위치하고 브레이크가 좌측에 위치한다는 것을 알고 있다.

1.4 Maven 플러그인을 통한 보편적인 재사용

메이븐의 핵심은 정말 아무런 처리 능력이 없다는 것이다. 몇 개의 XML 문서를 파싱하고 생명주기와 몇가지 플러그인의 추적을 유지하는 것 이외의 많은 것을 어떻게 처리할지 모른다. 메이븐은 대부분의 책임을 메이븐 생명 주기에 영향을 주고 goal에 대한 접근을 제공하는 메이븐 플러그인들에게 위임하도록 되어 있다. 메이븐의 대부분의 동작은 소스 컴파일, 바이트코드 패키징, 사이트 출판 등 빌드에서 발생되는데 필요한 기타 작업과 같은 내용을 다루는 플러그인 goal에서 발생된다. 아파치에서 다운받은 메이븐은 WAR 파일 패키징이나 JUnit 테스트 실행에 대해 거의 알지 못한다. 대부분의 메이븐 기능은 플러그인에 구현되어 있으며, 플러그인은 메이븐 레파지토리로부터 가지고 온다. 사실, 처음에 최신 메이븐을 설치하고 mvn install 과 같은 것을 실행했을 때, 중앙 메이븐 레파지토리로부터 핵심 메이븐 플러그인의 대부분을 가지고 온다. 이것은 메이븐의 배포판의 다운로드 크기를 최소화하는 기법 이상의 것이 있다. 이는 프로젝트의 빌드에 대한 기능을 추가하는 플러그인을 업그레이드가 가능하도록 하는 방법이다. 메이븐이 원격 레파지토리로부터 의존관계들과 플러그인들을 가지고 온다는 사실은 빌드 로직의 보편적인 재사용을 가능하게 해준다.

메이븐의 Surefire 플러그인은 단위 테스트를 실행하는 것을 담당한다. 버전 1.0과 오늘 널리 사용하는 버전 사이의 어느 시점에 누군가가 JUnit에 대한 지원과 같이 TestNG 단위 테스팅 프레임워크에 대한 지원을 추가하기로 결정했다. 이는 이전 버전에 대한 호환성을 깨뜨리지 않는 방법으로 이루어진다 – 만일 JUnit 3 단위 테스트를 컴파일하고 실행하는 Surefire 플러그인을 사용하고 있고, Surefire 플러그인의 가장 최신 버전으로 업그레이드하려고 한다면, 테스트는 실패없이 계속 실행하게 된다. 새로운 기능도 사용할 수도 있으며, TestNG에서 단위 테스트를 실행하기 원한다면, Surefire 플러그인의 개발자의 노력 덕분으로 그러한 기능을 이제 사용하게 된다. 또한 어노테이션이 달린 JUnit 4 단위 테스트에 대한 기능도 사용할 수 있다. 이러한 모든 기능을 메이븐 설치에 대한 업그레이드나 새로운 소프트웨어 설치를 할 필요없이 사용한다. 가장 중요한 것은 POM의 플러그인에 대한 버전 번호에 대한 변경을 제외하고 프로젝트에 대해 아무것도 변경할 필요가 없다는 것이다.

Surefire 플러그인 보다 더 많은 것에 영향을 미치는 것이 위와 같은 메커니즘이다. 프로젝트는 Compiler 플러그인을 사용해서 컴파일되며, Jar 플러그인을 사용해서 JAR 파일을 만들어내고, 레포트를 실행하는 플러그인, JRuby와 Groovy 코드를 실행하는 플러그인 뿐만 아니라, 원격 서버로 사이트를 만들어내는 플러그인 등이 있다. 메이븐은 중앙에서 일반적으로 공유되어 관리되는 플러그인으로 공통된 빌드 작업을 추상화시켰다. 만일 기술의 상태가 빌드 영역에서 바뀌거나, 어떤 새로운 단위 테스팅 프레임워크가 개발되거나, 혹은 새로운 도구를 사용하다면, 이를 지원하기 위해 프로젝트에 맞는 빌드 시스템을 망치는 사람이 될 필요가 없다. 플러그인이 원격 레파지토리로부터 다운받고 중앙에서 관리된다는 사실로부터 이점을 얻을 수 있다. 이것이 소위 메이븐 플러그인을 통한 보편적인 재사용이라는 것이다.

1.5 "프로젝트" 에 대한 개념 모델

메이븐은 프로젝트를 모델로 관리한다. 소스 코드를 바이트코드로 컴파일 하는 것 뿐만 아니라, 소프트웨어 프로젝트에 대한 설명을 하고, 프로젝트에 대해 위상에 대한 유일한 업무를 할당한다. 프로젝트의 속성에 대한 기술을 하기도 한다. 프로젝트의 라이센스는 무엇인가? 누가 개발하고 프로젝트에 기여하는가? 이 프로젝트에 의존 관계가 있는 다른 프로젝트가 무엇인가? 메이븐은 단순한 “빌드 도구” 그 이상이다. make와 Ant와 같은 도구에 대한 단지 발전된 모습 그 이상이다. 소프트웨어 프로젝트와 소프트웨어 개발과 관련된 새로운 의미론을 아우르는 플랫폼이다. 모든 프로젝트에대한 모델의 정의는 다음과 같은 기능을 가능하게 한다.

의존성 관리

프로젝트는 그룹 식별자, 산출물 식별자와 버전으로 구성된 유일한 위상으로 정의된다. 프로젝트는 의존성을 선언하는 이러한 위상을 이제 사용할 수 있다.
원격 레파지토리
의존성 관리와 관련되어서 메이븐 산출물에 대한 레파지토리를 생성하는 메이븐 프로젝트 객체 (Maven Project Object, POM)에 정의된 위상을 사용할 수 있다.
빌드 로직에 대한 보편적인 재사용
플러그인은 POM과 같이 동작하기 위해 코딩된다. 드러난 위치에 특정 파일에서 실행되도록 만들어지지 않았다. 모든 것이 모델에 추상화된다 – 플러그인 설정과 변경이 모델에서 이루어진다.
도구 이식성과 통합
Eclipse, NetBeans 와 IntelliJ와 같은 도구는 이제 프로젝트에 대한 정보를 찾는 보편적인 장소가 되었다. 메이븐 등장 이전에 모든 통합 개발 환경(IDE)은 기본적인 자체 POM이라고 했던 것을 저장하는 서로 다른 방법을 가졌었다. 메이븐은 이러한 방법을 표준화했으며, 비록 각 IDE가 계속해서 자체 프로젝트 파일을 관리하고는 있지만, 이러한 파일들은 모델에서 쉽게 생성될 수 있다.
쉬운 검색과 프로젝트 산출물 필터링
Nexus와 같은 도구는 POM에 저장된 정보를 사용해서 레파지토리의 내용을 인덱싱하고 검색을 가능하게 한다.
메이븐은 소프트웨어 프로젝트의 일관된 의미론적인 기술에 대한 시작을 위한 기반을 제공했다.

1.6 Maven은 XYZ의 대안인가?

그렇다면, 분명 메이븐은 앤트의 대안이지만, 아파치 앤트는 대단하고 계속 널리 사용되는 도구이다. 수년간 자바 빌드의 최고봉으로 자리매김을 해왔으며, 앤트 빌드 스크립트를 프로젝트의 메이븐 빌드와 매우 쉽게 통합할 수 있다. 이것은 메이븐 프로젝트에 대한 일반적인 사용 패턴이다. 반면에, 점점 더 많은 오픈 소스 프로젝트가 프로젝트 관리 플랫폼으로 메이븐을 사용함에 따라 작업하는 개발자들은 메이븐이 빌드 관리에 대한 작업을 단순화시킬 뿐만 아니라, 개발자와 소프트웨어 프로젝트간의 일반적인 인터페이스를 조성하는데 도움이 되고 있다고 느끼기 시작했다. 메이븐은 도구 보다는 플랫폼 이상이다. 비록 메이븐을 앤트의 대안으로 생각하고 있더라도 사과를 오렌지에 비유하고 있다. "메이븐"은 단지 빌드 도구 그 이상을 포함한다.

이상이 모든 메이븐과 앤트, 메이븐과 Buildr, 메이븐과 Gradle 인자를 관련없게 만드는 핵심 요점이다. 메이븐은 빌드 시스템의 역학에 의해서 전적으로 정의되지 않는다. 표준들과, 공통 인터페이스, 생명주기, 표준 레파지토리 형태, 표준 디렉토리 구조 등을 만드는 것에 대한 것만큼 빌드의 다양한 작업을 스크립트하는 것이 아니다. 예를 들어, XML과 YAML과 Ruby와 같이 POM이 어떤 형태에서 수행하는지에 대한 것은 분명 아니다. Maven은 그 보다더 훨씬 더 크며, 메이븐은 도구 그 자체보다도 더 많은 것을 참조한다. 이 책이 메이븐에 대해서 언급할 때 소프트웨어, 시스템, 이를 지원하는 표준의 집합체를 가리킨다. Buildr, Ivy, Gradle과 같은 모든 이러한 도구들은 메이븐이 생성하는데 도움을 준 레파지토리 형태와 상호작용하고, Buildr에서 완전하게 작성된 빌드를 지원하는 Nexus와 같은 도구를 쉽게 사용하는 것과 같을 것이다. Nexus는 16장에서 소개한다.

비록 메이븐이 위와 같은 많은 도구에 대한 대안이지만, 커뮤니티는 사용자와 개발자에 대한 각축전에서 친숙하지 않은 경쟁자들 사이에서 제로섬 게임과 같은 기술을 살펴보는 것 이상 진전을 필요로 한다. 이는 얼마나 큰 기업들이 서로 관련되어 있는가 일 수 있지만, 오픈 소스 커뮤니티가 작업하는 방식과는 거의 상관이 없다. “누가 이기는가? 앤트인가 메이븐인가?” 와 같은 제목은 건설적이지 못하다. 이러한 질문에 답변을 강요한다면, 메이븐이 빌드에 대한 기초적인 기술로써 앤트에 대해 우위의 대안이라고 말할 수 밖에 없다. 동시에, 메이븐의 영역은 지속적으로 이동하고 있으며 메이븐 진영은 더 보편적이고, 상호작용하고, 협력적이 되는 새로운 방향을 지속적으로 모색하려고 한다. 메이븐의 핵심 이념은 선언적인 빌드, 의존성 관리, 레파지토리 관리자, 그리고 플러그인을 통한 일반적인 재사용이지만, 특정 시점에서 이러한 개념을 특화시키는 것은 오픈 소스 진영이 “엔터프라이즈 규모의 빌드”의 비효율성을 격감시키기 위해 협업한다는 차원보다 덜 중요하다.

1.7 메이븐과 앤트 비교

이전 절에서 이 책의 저자들은 아파치의 앤트와 메이븐 간의 불화를 읽으키는데 아무런 흥미가 없다는 것을 각인시켰지만, 대부분의 조직들은 앤트와 메이븐 간의 의사결정을 해야하는 사실을 인지하고 있다. 이 절에서 이 도구들에 대해 비교하고 대조할 것이다.

앤트 빌드 프로세스에서 뛰어나다. target과 dependency를 사용한 make 이후 모델링된 빌드 시스템이다. 각각의 target은 XML에 복사된 여러 명령으로 구성된다. <copy> 작업과 <javac> 작업 뿐만 아니라 <jar> 작업이 있다. 앤트를 사용할 때, 결과를 컴파일하고 패키징하는 데에 특정 명령을 사용하여 제공한다. 예제 1-1에 나타난 예제 build.xml 파일을 살펴보자.

예제 1-1. 단순한 앤트 build.xml 파일
<project name="my-project" default="dist" basedir=".">
    <description>
        simple example build file
    </description>
  <!-- set global properties for this build -->
  <property name="src" location="src/main/java"/>
  <property name="build" location="target/classes"/>
  <property name="dist"  location="target"/>

  <target name="init">
    <!-- Create the time stamp -->
    <tstamp/>
    <!-- Create the build directory structure used by compile -->
    <mkdir dir="${build}"/>
  </target>

  <target name="compile" depends="init"
        description="compile the source " >
    <!-- Compile the java code from ${src} into ${build} -->
    <javac srcdir="${src}" destdir="${build}"/>
  </target>

  <target name="dist" depends="compile"
        description="generate the distribution" >
    <!-- Create the distribution directory -->
    <mkdir dir="${dist}/lib"/>

    <!-- Put everything in ${build} into the MyProject-${DSTAMP}.jar file -->
    <jar jarfile="${dist}/lib/MyProject-${DSTAMP}.jar" basedir="${build}"/>
  </target>

  <target name="clean"
        description="clean up" >
    <!-- Delete the ${build} and ${dist} directory trees -->
    <delete dir="${build}"/>
    <delete dir="${dist}"/>
  </target>
</project>

위의 단순한 앤트 예제에서 앤트에게 정확하게 무엇을 수행하는지를 어떻게 전달하는지를 볼 수 있다. javac 작업을 포함하는 compile goal이 있는데, 이는 src/main/java 디렉토리에서 target/classes 디렉토리로 소스를 컴파일한다. 앤트에 소스가 어디에 있는지, 결과 바이트 코드가 어디에 저장되기 원하는지, 그리고 이 모든 것이 JAR 파일에 어떻게 패키지되어야 하는지를 정확히 전달해야 한다. 최근 몇몇 개발을 도와주는 도구는 앤트가 덜 절차적이게 만들지만, 앤트에 대한 개발자 경험은 XML을 사용해서 절차 언어를 코딩하는데 있다.

위의 앤트 예제와 메이븐 예제를 비교해보자. 메이븐에서 자바 소스에서 JAR 파일을 생성하려면, 해야할 것은 단순한 pom.xml을 생성하고, ${basedir}/src/main/java 에 소스 코드를 위치시키고, 그 다음에 명령행에서 mvn install 을 실행하면 된다. 예제 1-1에 나와있는 단순한 앤트 파일과 동일한 결과를 달성하는 예제 메이븐의 pom.xml 이 예제 1-2이 나와있다.

예제 1-2. 단순한 메이븐의 pom.xml
<project>
  <modelVersion>4.0.0</modelVersion>
  <groupId>org.sonatype.mavenbook</groupId>
  <artifactId>my-project</artifactId>
  <version>1.0</version>
</project>

이것이 pom.xml에서 필요한 모든 것이다. 명령행에서 mvn install을 실행하면 리소스를 실행하고, 소스를 컴파일하고, 단위 테스트를 실행하고, JAR를 만들고, 다른 프로젝트에서 재사용하기 위한 로컬 레파지토리에 JAR 파일을 설치한다. 수정없이 mvn site를 실행하면 Javadoc에 대한 링크와 소스 코드에 대한 몇가지 보고서를 포함하는 target/site 에 index.html을 발견할 수 있을 것이다.

분명 위의 예제는 아주 단순한 예제 프로젝트이다. 단지 소스 코드와 JAR를 만드는 프로젝트이다. 메이븐 규칙을 따르고 어떠한 의존관계나 변경이 필요하지 않은 프로젝트이다. 만일 행위를 변경하기를 시작하기 원한다면 pom.xml은 크기가 커지게 되며, 프로젝트들 중에서 가장 큰 pom.xml에서 수많은 plugin 설정과 의존관계 선언이 포함된 매우 복잡한 여러 메이븐 POM들을 볼 수 있을 것이다. 하지만 프로젝트의 POM 파일들이 더 상당하다고 하더라도 앤트를 사용한 유사한 규모의 프로젝트의 빌드 파일로부터 전체적으로 서로 다른 종류의 정보를 포함한다. 메이븐 POM은 "이것은 JAR 프로젝트이다", 혹은 "소스 코드는 src/main/java 에 있다"와 같은 선언들을 포함한다. 앤트 빌드 파일은 "이것은 프로젝트이다", "소스는 src/main/java 에 있다", "이 디렉토리에 대해 javac를 실행하라", "target/classes 에 결과물들을 위치시켜라", "...에서 JAR를 만들어라" 등과 같은 명시적인 명령을 포함한다. 앤트는 절차에 대해서 명시적이어야 하는 반면에, 소스 코드가 어디에 있는지 그리고 어떻게 절차를 진행해야하는지 만을 알고 있는 메이븐에 "내장" 장치가 있다.

위의 예제에서 앤트와 메이븐 간의 차이는 다음과 같다.

아파치 앤트
  • 앤트는 공통 프로젝트 디렉토리 구조와 같은 공식적인 규약을 가지지 않는다. 앤트에 소스코드를 찾는 위치와 결과물을 넣는 위치를 정확하게 알려주어야 한다. 비공식적인 규약이 시간이 지남에 따라 나타났지만, 이러한 규약들은 프로젝트로 코딩되지 않았다.
  • 앤트는 절차적이다. 앤트에게 무엇을 하고 언제 할지를 정확하게 전달해주어야 한다. 컴파일하고, 그 다음에 복사하고, 그 다음에 압축하라고 전달해주어야 한다.
  • 앤트는 생명주기를 가지지 않는다. goal과 goal 의존관계를 정의해야 한다. 수동으로 각 goal에 대한 일련의 작업을 추가해야 한다.
아파치 메이븐
  • 메이븐은 규약을 갖는다. 예제에서 규약에 따랐기 때문에 소스 코드가 어디에 있는지를 이미 안다. target/classes 에 바이트코드를 위치시키고, target에 JAR 파일을 만들었다.
  • 메이븐은 선언적이다. 단지 할 것은 pom.xml 파일을 만들었고 기본 디렉토리에 소스를 위치시켰다. 메이븐이 나머지를 수행했다.
  • 메이븐은 생명주기를 갖는데, mvn install을 실행했을 때 호출했다. 이 명령은 메이븐에게 생명주기에 도달할 때까지 일련의 절차를 실행하라고 말하는 것이다. 생명주기를 통한 이러한 과정의 부수 효과로써 메이븐은 컴파일과 JAR 생성과 같은 일을 수행하는 수많은 기본 플러그인 goal을 실행했다.
메이븐은 메이븐 플러그인의 형태에 공통 프로젝트 작업에 대한 내장 기능을 가진다. 단위 테스트를 작성하고 실행하기 원한다면 단지 테스트를 작성하고, ${basedir}/src/test/java 에 위치시키고, TestNG나 JUnit 중에 하나에 대한 test 영역 의존관계를 추가하고, mvn test를 실행하면 된다. JAR가 아닌 웹 어플리케이션을 배포하기 원한다면, 단지 프로젝트 유형을 WAR로 변경하고 ${basedir}/src/main/webapp 에 docroot를 위치시키면 된다. 분명 이러한 모든 것을 앤트를 사용해서 수행할 수도 있지만, 해당 내용에 대한 지시 명령을 작성해야 할 것이다. 앤트에서 먼저 JUnit JAR 파일이 어디에 위치하고 있는지 알아야 하며, 그 다음에 JUnit JAR 파일을 포함하는 클래스패스를 생성해야 할 것이고, 그 다음에 앤트에게 테스트 소스 코드를 어디서 찾아야하는지를 알려주고, 테스트 소스를 바이트코드로 컴파일하는 goal을 작성하고, JUnit을 사용해서 단위 테스트를 실행할 것이다.

antlib와 Ivy 같은 기술 지원없이 (이러한 기술을 지원된다고 하더라도) 앤트는 사용자가 작성하는 절차적인 빌드에 대한 느낌을 갖는다. 메이븐이 고려하고 있는 규약에 의존하는 프로젝트에서 효율적인 메이븐 POM들은 앤트에 비해서 상당히 적은 양의 XML을 가진다. 모든 사람은 단위 테스팅을 위해 메이븐의 Surefire 플러그인을 사용하며, 새로운 단위 테스팅 프레임워크에 대한 지원을 누군가가 추가한다면 단지 프로젝트의 POM에 있는 특정 메이븐 플러그인의 버전을 높임으로써 빌드에 새로운 기능을 추가할 수 있다.

메이븐이나 앤트를 사용하는 결정은 이분법적인 것이 아니며, 앤트는 여전히 복잡한 빌드에서 사용될 수 있다. 만일 현재 빌드가 변경이 많은 절차를 포함한다거나, 메이븐 표준에 적합하지 않은 특정 방식으로 특정 프로세스를 완료하기 위해 앤트 스크립트를 작성했다면, 메이븐에서 이러한 스크립트를 여전히 사용할 수 있다. 앤트는 핵심 메이븐 플러그인처럼 사용이 가능하며, 수정된 메이븐 플러그인들이 앤트에 구현될 수 있으며, 메이븐 프로젝트는 메이븐 프로젝트의 생명주기 내에서 앤트 스크립트를 실행하도록 설정이 가능하다.

1.8 요약

지금까지 개요는 의도적으로 짧게 작성했다. 메이븐이 무엇이고 그동안의 다른 빌드 도구하고 비교와 향상이 어떻게 되었는지에 대한 기본적인 개요를 설명했다. 다음 장에서는 메이븐을 어떻게 설치하고 실행하는지를 설명하고, 3장에서는 간단한 프로젝트를 만들고 메이븐이 적은 양의 설정을 통해 경이로운 작업을 어떻게 수행하는지를 보여줄 것이다.

<<Pre Next>>

Creative Commons License
Elvis Lee에 의해 창작된 메이븐 가이드 은(는) 크리에이티브 커먼즈 저작자표시-비영리-동일조건변경허락 2.0 대한민국 라이선스에 따라 이용할 수 있습니다.
www.sonatype.com의 저작물에 기초

반응형

'Homo Faber > Maven Definitive Guide' 카테고리의 다른 글

I부. 메이븐 예제  (0) 2008.10.29
2장. 메이븐 설치와 실행  (0) 2008.10.29
서문  (0) 2008.10.28
Maven : Build Success for your Enterprise  (0) 2008.10.28
Copyright  (0) 2008.10.28