IBM®
메인 컨텐츠로 가기
    Korea [국가변경]    이용약관
 
 
   
        제품    서비스 & 솔루션    고객지원 & 다운로드    회원 서비스    
메인 컨텐츠로 가기

한국 developerWorks  >  자바 | 오픈 소스  >

사람을 위한 자동화: Ivy로 의존성 관리하기

아파치 Ant로 공공(common) 저장소를 사용하여 다른 프로젝트 소스 코드 공유하기

developerWorks
문서 옵션

JavaScript가 필요한 문서 옵션은 디스플레이되지 않습니다.

영어원문

영어원문


제안 및 의견
피드백

난이도 : 초급

Paul Duvall, CTO, Stelligent Incorporated

옮긴이: 백기선 dwkorea@kr.ibm.com

2008 년 7 월 15 일

여러 프로젝트와 도구 사이의 소스 코드 의존성들을 관리하는 것이 보통 큰 짐이 되기 마련인데, 더 이상 그럴 필요가 없습니다. 이번 사람을 위한 자동화 연재에서 자동화 전문가 Paul Duvall은 아파치 (Ant) 프로젝트의 아이비(Ivy) 의존성 관리자를 사용하여 보통의 자바(Java™) 프로젝트가 관리해야만 하는 무수히 많은 의존성을 어떻게 다룰 수 있는지 살펴볼 것입니다.

사실 모든 소프트웨어 개발 프로젝트는 항상 다른 프로젝트의 소스 코드에 의존해야만 한다. 예를 들어, 여러분의 프로젝트가 로깅 기능에는 log4j를, 웹 프레임워크로 스트럿츠를 사용했다고 하자. 여러분의 개발 팀이 이런 프로젝트의 소스 코드를 관리하지는 않는다. 하지만, 여러분은 프로젝트의 커스텀 소프트웨어를 구현할 때 그 API에 의존하한다. 여러분의 소프트웨어가 의존하는 다른 프로젝트와 그 프로젝트 자체가 가지는 의존성까지 포함한 개수가 증가할수록, 여러분의 소프트웨어를 빌드하는 것이 점차 더 복잡해진다.

본 연재에 대해

개발자로서 우리는 고객의 프로세스를 자동화하기 위해 일한다. 하지만, 우리 중 대부분은 스스로의 개발 프로세스를 자동화할 수 있는 기회를 간과하곤 한다. 더 이상 그러지 않기 위해, 사람을 위한 자동화 연재를 기획하여 소프트웨어 개발 프로세스를 자동화하는 실용적인 사용법들과 성공적으로 자동화를 언제 어떻게 적용하는지 설명하겠다.

나는 이런 딜레마를 해결하기 위해 팀들이 사용하는 여러 불완전한 방법을 발견했다.

  • 의존하는 모든 프로젝트(JAR 파일)를 프로젝트 버전 관리 저장소 안에 있는 디렉터리에 넣어둔다. 이 방법은 저장소를 필요 이상으로 부풀리고, 다른 버전을 관리하기가 어렵다.

  • 의존하는 JAR 파일을 전부 파일 서버에 둔다. 이렇게 하면 팀이 버전 변경을 제어할 수가 없다.

  • JAR 파일들을 직접 복사해 각각의 개발자 작업 환경에 가지고 있는다. 이 접근 방법은 빠진 파일 또는 올바른 버전을 찾기가 힘들다.

  • HTTP Get을 사용해 수동 또는 자동화된 빌드를 통해 개발자의 작업 환경에 파일들을 다운로드한다. 이 기술은 중복 스크립틀릿을 필요로 하고 종종 관리 대상이 아닌 JAR 파일까지 가져오게 된다.

나는 1000개의 자바 클래스와 100개가 넘는 JAR 파일을 가지고 있는 중간 규모 프로젝트에서 일한 적이 있다. (이 때 첫 번째 불완전한 방법을 선택했다. 모든 JAR 파일을 버전 관리 저장소에 같이 올렸다.) 그림 1은 그런 프로젝트에서 볼 수 있는 의존성 타입의 일부를 보여준다.


그림 1. 웹 개발 프로젝트에서 JAR 의존성 예제
웹 개발 프로젝트에서 JAR 의존성 예제
고정된 추이 의존성

추이적인 의존성(Transitive dependencies)은 아이비가 제공하는 간단하지만 강력한 기능 중 하나다. 몇몇 JAR 파일은 기능이 올바로 동작하기 위해 다른 JAR 파일들에 의존한다. 아이비를 사용할 때, 컴포넌트의 의존성들을 한 번만 선언해 두면 된다. 그러면 그 후부터는, 오직 목표로 하는 JAR 파일만 알면 되고 그 JAR 파일이 의존하는 다른 JAR 파일들은 신경 쓰지 않아도 된다. 만약 손수 문서를 뒤지고 소스 코드를 조사해 가면서 의존성을 따라가며 조사하는 고통을 경험한 적이 있다면, 이 기능 하나만으로도 아이비로 프로젝트를 설정하는 것이 가치 있는 일이 될 것이다. 본 기사의 의존하는 라이브러리에 의존하기를 참조하라.

그림 1은 Brewery 프로젝트의 소스 코드가 하이버네이트(Hibernate), 스트럿츠 2, MySQL 커넥터 그리고 Cobertura에 의존하는 것을 보여준다. 또, Cobertura는 또 다른 JAR 파일인 asm-2.2.1.jar, jakarta-oro-2.0.8.jar, log4j-1.2.9.jar 등에 의존한다. 더 들어가서 asm-2.2.1.jar는 asm-tree-2.2.1.jar에 의존하고 있다. 이것은 내부 의존성에 대한 매우 간단한 예제에 불과하다. 만약 이 중 JAR 버전이 하나라도 일치하지 않으면, 컴파일 에러 또는 예상치 못한 동작 같은 처리하기 힘든 문제를 경험하게 될 것이다.

아파치 메이븐 빌드와 프로젝트 관리 도구는 최근 자바 개발자들 사이에서 인기를 얻고 있다. 메이븐은 어디서나 접속 가능한 웹 서버(ibiblio)를 통해 JAR 파일에 접근할 수 있는 공공 저장소 개념을 도입했다. 메이븐 접근 방식은 대부분의 버전 관리 저장소가 소비해야만 했던 JAR 파일 비대화를 줄여주었다. 하지만 메이븐을 사용하는 것은 그것이 제공하는 "설정보다는 관례(convention over configuration)"를 따라야 한다는 의미가 되고 이는 여러분의 빌드 스크립트의 유연함을 제한할 수 있다.

아파치 앤트를 수년간 사용해 왔고 공공 저장소의 장점도 얻기 원한다면 어떻게 할 것인가? 이런 장점들을 얻기 위해 메이븐의 빌드 접근 방식을 받아들이도록 강요할 것인가? 운좋게도 대답은 "아니"다. 앤트 서브 프로젝트인 아파치 아이비라는 도구 때문이다. 아이비는 좀 더 일관적이며, 반복가능하고, 유지보수하기 쉬운 방법을 통해 프로젝트의 빌드 의존성들을 관리할 수 있게 해준다(메이븐과 아이비의 차이 비교는 참고자료를 참조하라). 본 기사는 의존성과 좀 더 자세하게 실험해볼 수 있는 지점을 관리할 때 필요한 아이비 설치와 설정에 대해 다룬다.

시작하기

아이비를 시작하는 것은 두 개의 아이비용 파일을 만들고 새로운 앤트 태스크를 추가하는 것만큼이나 간단하다. 아이비용 파일은 ivy.xml과 아이비 설정 파일이다. ivy.xml 파일에는 프로젝트의 모든 의존성 목록을 설정한다. ivysettings.xml 파일(이 파일 이름은 원하는 것으로 바꿔도 괜찮다)에는 의존하는 JAR 파일들을 다운로드할 저장소를 설정한다.

Listing 1은 두 개의 아이비 태스크 ivy:settingsivy:retrieve를 호출하는 앤트 스크립트를 보여준다.


Listing 1. 아이비를 사용하는 간단한 앤트 스크립트
<target name="init-ivy" depends="download-ivy">
  <ivy:settings file="${basedir}/ivysettings.xml" />
  <ivy:retrieve />
</target>

Listing 1에서 ivy:settings는 아이비 설정 파일을 정의한다. ivy:retrieve를 호출하여 ivy.xml에 선언한 저장소 중 한 곳에서 JAR 파일들을 가져오도록 한다.

아이비 설치하기

아이비를 다운로드하고 설정하는 방법은 여러 가지가 있다. 먼저 아이비 JAR 파일을 손수 다운로드하고 앤트의 lib 디렉터리로 복사하거나 앤트 스크립트의 클래스패스로 설정한 별도 디렉터리에 복사해 넣는 방법이 있다. 나는 자동화 팬이기 때문에 이런 과정을 자동화하는 방법을 더 선호한다. 아이비 JAR 파일을 다운로드하고 그것을 클래스패스로 설정하는 앤트 타깃을 사용한다. Listing 2는 이 기술에 대한 예제다.


Listing 2. 앤트를 사용하여 자동으로 아이비 설치하기
<?xml version="1.0" encoding="iso-8859-1"?>
<project name="test-ivy" default="init-ivy" basedir="." 
   xmlns:ivy="antlib:org.apache.ivy.ant" xmlns="antlib:org.apache.tools.ant">
  <property name="ivy.install.version" value="2.0.0-beta2" />
  <property name="ivy.home" value="${user.home}/.ant" />
  <property name="ivy.jar.dir" value="${ivy.home}/lib" />
  <property name="ivy.jar.file" value="${ivy.jar.dir}/ivy.jar" />
  
  <taskdef resource="org/apache/ivy/ant/antlib.xml" 
     uri="antlib:org.apache.ivy.ant" classpath="${ivy.jar.dir}/ivy.jar"/>
 
  <target name="download-ivy">
    <mkdir dir="${ivy.jar.dir}"/>
    <get src="http://www.integratebutton.com/repo/
       ${ivy.install.version}/ivy-2.0.0-beta2.jar"
      dest="${ivy.jar.file}" usetimestamp="true"/>
  </target>

</project>

Listing 2의 두 번째 줄은 XML 네임스페이스를 정의한다. antlib은 inv.jar 파일에 들어있는 antlib.xml을 참조한다. xmlns의 나머지 부분은 ivy 앤트 태스크의 전체 정로를 설정한다. ${user.home}/.antivy.home 값은 다운로드한 ivy.jar 파일이 위치할 곳이다. taskdefivy 앤트 태스크를 정의하고 그것을 클래스패스로 참조한다. download-ivy 타깃은 ivy-2.0.0-beta2.jar를 다운로드하고 그것을 dest 속성을 사용하여 이름을 변경한다.

아이비를 다운로드하고 설정을 마쳤다면, 이제 모든 아이비 앤트 태스크(Listing1에서 봤던 두 개의 태스크처럼)를 사용할 수 있다.

설정 스크립트 작성하기

프로젝트의 모든 의존성 JAR 파일을 정의한 ivy.xml 파일이 필요하다. Listing 3은 그 예에 해당한다.


Listing 3. ivy.xml 파일에 의존성 정의하기
<?xml version="1.0" encoding="ISO-8859-1"?>
<?xml-stylesheet type="text/xsl" href="./config/ivy/ivy-doc.xsl"?>
<ivy-module version="1.0">
  <info organisation="com" module="integratebutton" />
  <dependencies>
    <dependency name="hsqldb" rev="1.8.0.7" />
    <dependency name="pmd" rev="2.0" />
    <dependency name="cobertura" rev="1.9"/>
    <dependency name="checkstyle" rev="4.1" />
    <dependency name="junitperf" rev="1.9.1" />
    <dependency name="junit" rev="3.8.1" />
  </dependencies>
</ivy-module>

Listing 3에는 어떠한 파일 위치나 URL이 없다는 것에 주목하라. 따라서 이 목록에 있는 의존성들을 다운로드할 저장소가 바뀌더라도 이 목록은 수정하지 않아도 된다. info 엘리먼트에 있는 organisation 속성은 (.net, .org 또는 .com 같은)조직의 유형을 알려준다. 그 뒤에는 module 이름을 설정한다. 해당 모듈의 의존성 목록은 작명 규약을 따르는데, 이 작명 규약은 다음 코드에서 볼 수 있다. 지금은, dependency name="cobertura" rev="1.9" 이것이 cobertura-1.9.jar로 변경된다는 것만 알아두자.

Listing 4는 아이비 설정 파일 예제다. 여기서는 Listing 3에 있는 ivy.xml 파일이 사용할 작명 규약과 저장소 위치를 정의한다.


Listing 4. 아이비 설정 파일
<ivysettings>
  <settings defaultResolver="chained"/>
  <resolvers>
    <chain name="chained" returnFirst="true">
      <filesystem name="libraries">
        <artifact pattern="${ivy.conf.dir}/repository/[artifact]-[revision].[type]" />
      </filesystem>
      <url name="integratebutton">
        <artifact pattern="http://www.integratebutton.com/repo/[organisation]/[module]/
           [revision]/[artifact]-[revision].[ext]" />
      </url>
      <ibiblio name="ibiblio" />
      <url name="ibiblio-mirror">
        <artifact pattern="http://mirrors.ibiblio.org/pub/mirrors/maven2/[organisation]/
           [module]/[branch]/[revision]/[branch]-[revision].[ext]" />
      </url>
    </chain>
  </resolvers>
</ivysettings>

Listing 4에 있는 filesystem 엘리먼트는 로컬 워크스테이션의 위치 패턴을 정의한다. 두 개의 url 엘리먼트는 JAR 파일을 다운로드할 수 있는 여러 개의 위치를 정의한다. 첫 번째 것은 내가 관리하는 integrationbutton.com에 있는 커스텀 저장소를 정의했고, 다음에는 상당히 많은 양의 오픈 소스 JAR 파일을 가지고 있는 외부 메이븐 저장소(내가 관리할 수 없는)를 설정했다. 아이비가 첫 번째 저장소에서 JAR 파일을 (서버가 다운됐거나 해당 파일이 기술한 위치에 없어서) 다운로드하지 못 한다면, 다음 위치에서 시도할 것이다. 정말 멋진 것은 아이비가 다운로드한 JAR 파일을 로컬 파일 시스템에 저장하고 그 파일을 모든 빌드를 할 때 사용하기 때문에 또 다시 다운로드할 필요가 없다는 것이다.




위로


의존하는 라이브러리에 의존하기

모듈이 다른 모듈에 의존성을 갖는 것은 일반적인 일이다. 예를 들어, 그림 1에서 cobertura-1.9.jar 파일이 asm-2.2.1.jar를 포함한 여러 개의 라이브러리에 의존하고 있으며 동시에 asm-2.2.1.jar는 다시 asm-tree-2.2.1.jar에 의존하는 것을 보았을 것이다. 아이비와 같은 도구가 없다면, 올바른 버전의 JAR 파일들이 클래스패스에 설정되었는지 확인해야 하고 JAR 버전 사이에 충돌이 없는지 확인해야 할 것이다. 아이비를 사용하면, 간단하게 Listing 5에 있는 예제 ivy.xml 파일 안에 cobertura 모듈과 그 의존성을 정의하기만 하면 된다. 이 ivy.xml 파일이 cobertura-1.9.jar 파일과 같은 디렉터리에 위치해야 한다는 것을 알아두기 바란다.


Listing 5. 의존성을 ivy.xml에 정의하기
<?xml version="1.0" encoding="UTF-8"?>
<ivy-module version="2.0"
  xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
  xsi:noNamespaceSchemaLocation="http://ant.apache.org/ivy/schemas/ivy.xsd">
  <info organisation="cobertura" module="cobertura" revision="1.9"/>
  <configurations>
    <conf name="master"/>
  </configurations>
  
  <publications>
    <artifact name="cobertura" type="jar" conf="master" />
  </publications>
  
  <dependencies>
    <dependency org="objectweb" name="asm" rev="2.2.1" conf="master"/>
    <dependency org="jakarta" name="oro" rev="2.0.8" conf="master"/>
    <dependency org="apache" name="log4j" rev="1.2.9" conf="master"/>		
  </dependencies>
</ivy-module>

Listing 5에 굵은 글씨로 표시된 의존성은 objectweb이라는 orgasm이라는 name 속성 그리고 사용할 버전을 명시하한다. 아이비는 이 정보와 (Listing 4에 있는) ivysettings.xml 파일에 있는 저장소 정의에 대한 정보를 사용하여 의존하는 JAR 파일을 다운로드할 것이다.

그림 2는 Listing 4에 있는 invsettings.xml 파일에 있는 설정이 동작하는 저장소의 디렉터리 구조를 보여준다.


그림 2. asm 모듈 디렉터리 구조
asm 모듈 디렉터리 구조

그림 2에 보이는 inv.xml 파일(Listing 6 참조)은 asm이 의존하는 라이브러리를 정의해둔 파일이라는 것을 알아두자. Listing 6에는 asm 모듈용 ivy.xml 중 일부로 asm-tree-2.2.1.jar에 대한 단일 의존성을 보여준다.


Listing 6. asm의 의존성을 정의한 ivy.xml
...
<dependencies>
  <dependency org="objectweb" name="asm-tree" rev="2.2.1" conf="master"/>
</dependencies>
...

다시 보면, cobertura 모듈은 Listing 5에 명시한 것처럼 세 개의 모듈 asm, jakarta-oro, log4j에 의존하고 있다. 이번에는 asm 모듈은 Listing 6에 명시한 것처럼 하나의 의존성 모듈인 asm-tree를 가지고 있다.

그림 2에서 봤던 asm 모듈과 그림 3에 보이는 asm-tree의 디렉터리 구조가 얼마나 비슷한지 살펴보자.


그림 3. asm-tree 모듈 디렉터리 구조
asm-tree 모듈 디렉터리 구조

물론 그 둘의 차이는, JAR 파일들이 서로 다른 클래스를 담고 있으며, 그림 2에서 보았던 ivy,xml과는 달리 asm-tree 모듈을 기술하고 있다는 것이다(같은 파일이라면 asm-tree 모듈은 자신의 ivy.xml에 어떠한 의존성도 정의하지 않은 것이다).




위로


아이비로 성장하기

이제 아이비 기본 사용법을 익혔으니 더 유용한 앤트 태스크들을 소개하겠다.

보고서 만들기

아이비는 프로젝트의 의존성 파일들에 대한 보고서를 작성하는 태스크를 제공한다. Listing 7은 아이비의 report라는 앤트 태스크를 호출하여 의존성 목록을 생성해준다.


Listing 7. 앤트에서 아이비 의존성 보고서 생성하기
<target name="ivy-report" depends="init-ivy">
  <ivy:report todir="${target.dir}/reports/ivy"/>
</target>

Listing 7에 있는 스크립트에 의해 생성된 HTML 보고서는 프로젝트의 의존성 파일들을 보여준다. 그림 4가 그 보고서다.


그림 4. 프로젝트 의존성을 보여주는 HTML 보고서
프로젝트 의존성을 보여주는 HTML 보고서

부가적인 태스크들

이 밖에도 여러 앤트 태스크를 사용하여 메이븐에서 사용할 POM 파일 생성하기부터 파일 시스템 캐시 정리하기 등을 할 수 있다. 표 1은 몇몇 아이비 앤트 태스크와 그 용도를 보여준다.


표 1. 기타 아이비 앤트 태스크
태스크용도
settings 저장소를 가지고 있는 호스트로 접속할 때 매우 유용하다.
cachepath 파일을 다운로드해 로컬 파일 시스템에서 호스팅할 기본 캐시 경로를 재정의한다.
repreport 저장소에 있는 몇 개의 모듈에 대한 보고서를 생성한다.
install install 모듈과 그 모듈의 의존성들을 설치한다.
makepom ivy.xml을 기준으로 메이븐에서 사용할 수 있는 pom.xml 파일을 생성한다.
cleancache makepom cleancache 로컬 파일 시스템 캐시를 제거하고 다음에 빌드할 때는 모든 JAR 파일을 저장소에서 다운로드한다.

참고자료를 참조하여 아이비에서 사용할 수 있는 다른 앤트 태스크들을 확인하라.




위로


그때 그때 다르다

바이너리 버전 관리

아이비는 JAR 파일들을 버전 관리해야 하는 상황을 미연에 방지한다. 나는 종종 버전 관리 시스템에 파일들을 넣지 않고 HTTP로 접속 가능한 저장소를 사용하는 팀들을 봐왔다. 1년 후에 소프트웨어와 HTTP 저장소를 다시 만들어야 한다고 생각해보자. 아마도 매우 힘들지도 모른다. 서브버전(Subversion)과 같은 HTTP로 접근 가능한 버전 관리 저장소를 사용하면 저장소를 중앙화하여 관리할 수도 있고 HTTP 접근을 제어할 수도 있기 때문에 그런 수고가 줄어든다.

아이비는 의존성 파일들을 한군데로 모으고 개발 팀이 JAR 파일들을 어떤 버전 관리 저장소에서 다른 곳으로 복사할 때 일어날 수 있는 문제들을 줄여준다. 간단한 프로젝트에 종사하고 있다면, 버전 관리 시스템에 올릴 JAR 파일들의 버전을 확인하거나 본 기사의 처음에 언급했던 방법들을 사용할 필요가 없을지도 모른다. 하지만, 프로젝트가 점차 커지거나 엔터프라이즈 환경에서 일한다면, 일관적인 접근 방법이 필요해진다. 그런 경우, 아이비가 프로젝트의 의존성을 더 일관성 있고 접근이 쉬운 형태로 유지해줄 것이다. 따라서 프로젝트에서 아이비를 사용하기 위해 노력하는 데 시간을 투자하는 것은 가치 있는 일이다.



참고자료

교육
  • 아파치 아이비: 아이비 프로젝트 사이트에 접속하여 문서, 튜토리얼 그리고 커뮤니티 참고자료를 확인하라.

  • "Ivy in 4.2 steps" (Andrew Glover, testearly.com, 2007년 6월): 몇 단계에 걸쳐 아이비를 다운로드하고 실행하라.

  • Ivy / Maven2 Comparison(아파치 앤트 아이비 프로젝트): 아이비와 메이븐 2 의존성 관리 차이점에 대한 논의

  • Ant in Action (Steven Loughran and Erik Hatcher, Manning, 2007): 이 멋진 책의 11장에서 아이비를 사용하여 의존성을 관리하는 방법을 설명하고 있다.

  • Automation for the people (Paul Duvall, developerWorks): 전체 연재를 확인하라.

  • 기술 서점을 참조하여 이번 주제 또는 다른 주제에 관한 책을 참조하라.

  • 한국 developerWorks 자바 영역: 자바 프로그래밍에 관련한 수백 개의 기사를 참조할 수 있다.


제품 및 기술 얻기
  • 앤트: 앤트를 다운로드하고 예측 가능하고 반복 가능한 형태로 소프트웨어를 빌드하라.

  • 아이비: 아이비를 다운로드하라.


토론


필자소개

Paul Duvall

Paul Duvall은 컨설팅 회사이자 개발 팀을 애자일 소프트웨어 제작에 최적화하는 데 있어 선구자적인 역할을 하는 Stelligent Incorporated의 CTO다. Paul Duvall은 Addison-Wesley Signature Series Book인 Continuous Integration: Improving Software Quality and Reducing Risk (Addison-Wesley, 2007)의 공동 저자다. 또 UML 2 Toolkit (Wiley, 2003)과 No Fluff Just Stuff Anthology (Pragmatic Programmers, 2007)에도 기여하였다.




기사에 대한 평가


보다 나은 서비스를 제공하기 위함이오니 잠시 짬을 내어 이 양식을 제출하여 주십시오.



 


 


 


이 문서 북마킹 하기

mar.gar.in mar.gar.in naver naver eolin eolin del.icio.us del.icio.us





위로


developerWorks 콘텐트를 다른 사이트에 전재하기:
developerWorks 콘텐트에 대한 저작권은 IBM에 있습니다. IBM의 서면 허가나 원본 저자의 허락이 없이는 전재를 금합니다. 저희 콘텐트를 전재하시려면 IBM developerWorks 담당자 에게 문의하십시오.
    IBM 소개 개인정보 보호정책 문의