1. Ease of installation & use
2. Fairly extensive ecosystem of plugins
3. Distributed build support
4. Inter team support
5. Open source
6. Maturity
7. Extensive tools outside Hudson
8. Permalink support
9. Localization
10.Building blocks
Name : petstore20 Next build version : petstore20-0 Trigger type : manual Build necessary condition : always Associated builders : ant 1.6.2
Next build version을 perstore20-0으로 놓게 되면 빌드가 될때마다 -1, -2 로 증가하게 됩니다. Build necessary condition은 원래 형상서버에 변경이 생겼을때만 빌드 하도록 놓는게 기본값(vcsModified or dependencyNewer)입니다만 여기서는 테스트를 위해 항상 빌드하도록 설정합니다.
저장을 하고나면 다음과 같은 결과를 볼 수 있습니다. 저는 테스트를 위해 이미 빌드를 실행했기 때문에 빌드가 성공했다는 파란 동그라미가 나타납니다. 오른쪽 상단의 build manualy를 누르고 [Save]를 누르면 빌드가 실행됩니다. build history 아이콘을 누르면 빌드 결과를 볼 수 있습니다.
전체 4번 빌드가 실행되었고 그중에서 세번 실패하고 1번 성공했군요. Version을 누르면 상세 화면으로 이동합니다.
상세화면에서는 빌드 시작일, 종료일, 빌드에 걸린시간, 빌드 로고, 리비전 로고를 볼 수 있습니다.
간단하게 나마 Luntbuild와 Subversion을 연동해봤습니다.
내용이 간단해서 더 상세하게 다룰 내용이 많이 남은거 같습니다. CVS, Visual Source Safe와 연동한다거나 Maven과 같은 빌더를 이용하는것, 구체적으로 사용되는 시나리오등도 필요할 거 같네요. 틈나는 대로 위와 같은 내용으로 이 포스트를 확장해 가려고 합니다.
이번에는 Luntbuild에 Version Control System을 등록하는것에 대해 알아보겠습니다. Luntbuild가 지원하는 Version Control System에는 어떤것들이 있을까요 ?
AccuRev
Base Clearcase
Dynamic Clearcase
CVS
File System
MKS
Perforce
Star Team
Subversion
SubversionExe
ClearcaseUCM
Visual Source Safe
많이 사용하는 형상관리 시스템을 대부분 지원하기 때문에 따로 커스터마이징이 필요없을 정도입니다. (물론 저희회사에서 사용하는 Dimensions은 없습니다. 슬픈 현실이죠. --;) 여기서는 Subversion을 사용하겠습니다.
1.Project 탭에서 해당 프로젝트 이름을 클릭하여 프로젝트를 선택합니다.
2.오른쪽 상단의 Edit 아이콘을 클릭하여 프로젝트 수정화면으로 들어갑니다.
3.Builders탭으로 이동하여 new builder 아이콘을 클릭하여 빌더를 추가합니다. Luntbuild가 지원하는 builder는 다음과 같습니다. 여기서는 Ant를 사용하겠습니다.
Ant
Maven
Maven2
Command
Rake
builder type : Ant builder Name : ant 1.6.2 Command to run Ant : E:\j2ee\devlib\apache-ant-1.6.5\bin\ant.bat Build script path : /Petstore20/build/build.xml Build targets : all
Ant는 1.6.2 버전을 사용했습니다. 미리 Ant를 받아서 압축을 풀어놓으셔 하며 그 위치를 명시하면 됩니다. 빌드 스크립트는 테스트용으로 빈 파일을 하나 만들어서 사용했으며 스크립트 위치는 /build 폴더 입니다.
Luntbuild의 실행결과는 데이터베이스에 저장하는것이 가능합니다. 굳히 무겁게 DB까지 연동할 필요가 있냐고 이야기 하는 분도 계실듯 합니다. 하지만 빌드결과는 개발관리 측면에서 본다면 유용한 정보가 될 수 있습니다. Luntbuild가 지원하는 DB는 다음과 같습니다.
HSQL
MySQL
PostgreSQL
SqlServer
Oracle
Derby
H2
이 정도면 왠만한 데이터베이스는 다 지원한다고 말할 수 있을거 같네요. 이중에서 MySQL만 한번 연동해 보겠습니다.
1.MySQL을 설치합니다. 설치가 어렵지 않으니 그냥 하시면 될거 같구요. 설치하면서 사용자계정,암호,포트번호 등을 기억해 두셔야 합니다. 클라이언트 툴을 하나쯤 사용하시는게 편합니다. 제가 주로 사용하는 툴을 SQLyog 입니다.
2.Luntbuild에서 MySQL 관련 프로퍼티를 수정합니다. 이 설정파일은 \luntbuild-1.5.4.1\web\WEB-INF\jdbc.mysql.properties입니다. 이 파일을 열어서 아래와 같이 수정합니다. 포트나 서버이름은 자신의 MySQL에 따라 다를수 있습니다.
Luntbuild는 가장 많이 사용되는 빌드서버라고 할수 있습니다. 이번에는 이 Luntbuild를 이용해서 서브버전의 형상을 빌드하는것에 대해 알아보겠습니다. 그럴려면 먼저 서브버전이 설치되어 있고 Luntbuild에서 읽어올 레파지터리가 만들어져 있어야 합니다. 이 부분은 제가 이전에 포스팅한 Collabnet Subversion으로 형상서버 꾸미기를 참고하세요.
Luntbuild를 설치하겠습니다. 설치는 단순합니다. http://luntbuild.javaforge.com에 가셔서 Luntbuild를 다운로드 해서 적당한 위치에 압축을 풀면 됩니다. 저는 Luntbuild 1.5.4 버전을 사용하였습니다. Luntbuild는 웹기반의 애플리케이션이며 두가지 방식으로 사용하는게 가능합니다.:Standalone 방식과 서블릿 컨테이너에 배포하여 사용하는 방식
Standalone방식으로 실행하기 위해서는 \bin 폴더에 있는 luntbuild.bat 파일의 $INSTALL_PATH를 실제로 Luntbuild가 설치된 곳으로 바꿔줘야 합니다.
@echo off
cd /D "$INSTALL_PATH" if "%1" == "" ( set host="localhost" ) else ( set host="%1" ) if "%2" == "" ( set port="8080" ) else ( set port="%2" )
빌드루프(Build Loop) 빌드루프는 일종의 데몬입니다. 주기적으로 형상관리 서버를 검사하면서 빌드가 필요한 경우에는 실제로 빌드를 실행하고, 빌드 상태를 알려줍니다. 크루즈컨트롤에는 빌드 주기를 정의할수 있습니다. 이 빌드주기에 맞춰서 빌드가 실행되고 빌드로그를 생성한다음 이를 알려줍니다. 데몬 프로세스는 사용자가 사전에 정의해 놓은 빌드 사이클에 따라 동작합니다. 설정파일이 변경되면 데몬을 재 시작해야 새로운 설정이 반영됩니다. 빌드가 끝나면 Build Results JSP를 이용해서 로그 파일을 작성합니다.
결과 JSP(Results JSP)
Build Results JSP는 빌드 루프의 결과를 보여줍니다. 왼쪽 부분은 현재 빌드되고 있는 프로젝트를 나타내는데 이전 빌드의 상세내역에 대한 링크를 제공합니다.
오른족 창은 빌드중에 발생한 에러, 테스트 결과, 최종 빌드후에 일어난 변경 내역을 보여줍니다.
대쉬 보드(Dashboard) 크루즈컨트롤 대쉬보드는 프로젝트 상태를 보여주는 강력한 도구로서 프로젝트의 빌드 상태를 다양한 색상으로 나타내며 각 색상별로 프로젝트의 스냅샷을 보여줍니다.
얼마전 실용주의 개발환경을 구성하기 위한 도구를 정리하고 나서 어떤 툴부터 스터디를 시작할까 고민하던중에 마침 업무적으로도 필요하고 해서 크루즈컨트롤에 대해 자세히 살펴보기로 했습니다.
크루즈컨트롤의 원래 의미는 장거리 운전을 할때 운전자가 엑셀을 밟지 않아도 일정한 속도를 유지시켜주는 정속주행 장치입니다. 외국 개발자들은 참 이름도 잘 짓네요. ^^;
크루즈컨트롤(Cruise Control)
과 같은 애플리케이션을 CI Server 나 CI System 이라고 부릅니다. 빌드 서버라고 부르기도 하는데 요즘 나온
애플리케이션들이 대쉬보드나 모니터링을 같이 지원하는 경우가 많기 때문에 이 보다는 CI 서버라고 부르는게 맞다고 봅니다.
크루즈컨트롤을 처음 시작한건 마틴 파울러(Martin Fowler)로 유명한 Thought Works사 입니다. 처음 크루즈 컨트롤을 만들기 시작했고 지금도 많은 사람들이 커미터로 활동하고 있습니다.
크루즈컨트롤의 라이센스는 BSD-style을 따르며 OSI Certified 오픈 소스 소프트웨어라고 명시하고 있습니다.
크루즈 컨트롤의 내부구성은 크게 3가지 모듈로 이루어져 있습니다.
빌드 루프(build loop) : 코어 모듈, 빌드를 주기적으로 실행하고 실행결과를 사용자에게 통보한다.
레거시 리포팅(legacy reporting) : 사용자가 빌드 결과를 볼 수 있게 제공한다.
대쉬보드(dashboard) : 모든 프로젝트 빌드 상태상태를 비쥬얼하게 나타낸다.
이렇게 모듈로 구성되어 있기 때문에 원하는 형태에 맞게 크루즈컨트롤을 사용하는게 가능합니다. 예를 들어 빌드 루프에서 모니터링에 사용되는 HTTP, RMI 같은 기술을 보안상의 이유로 사용하지 않는게 가능합니다.
CI Server는 Continous Integration 환경을 구축하는데 핵심이 되는 애플리케이션입니다. Ant나 Maven과 같은 빌드 스크립트 도구를 기반으로 빌드를 실행하고 그 결과를 사용자에게 알려주는 역할을 합니다.
(CI에 대해 잘 모르시는 분은 제가 일전에 번역해 놓은 Continous Integration을 읽어 보시고, 영어가 좀 되시는 분들은 원문을 보시길 강추합니다.)
이 CI Server의 기능을 리스트로 잘 정리해 놓은 사이트가 있어서 공유합니다. 한가지 아쉬운건 그래서 뭐가 제일 좋다는 순위나, 각 서버간의 비교가 없는 점 이네요. (하긴 상대적이어서 의미가 없을수도 있을거 같습니다.)
한달여를 끌어온 Continous Integration (by Martin Fowler)에 대한 번역을 완료했다. 내가 너무 좋아하는 글이라 꼭 한번 다시 숙독을 해야겠다고 마음먹은게 한달전이다. 기왕 읽는거 아예 번역을 해서 여러사람이 볼 수 있게 공개를 해야겠다고 맘을 고쳐먹고 "한 일주일이면 끝나겠지~" 했는데 이렇게 오래 거릴줄이야 ^^ 개발을 좋아하시면 꼭 읽어보기를 권한다. 가능하면 영어로들 보시고 한글로 보고 싶으신 분은 여기를 참고하시길..
맷(Matt)과 내가 이 사이트에 CI의 원본 문서를 작성하고 나서 지속적 통합은 소프트웨어 개발의 주요 기법이 되었다. CI를 사용하지 않는 ThoughtWorks의 프로젝트는 찾아보기 힘들게 되었으며 전 세계적으로 다른 사람들도 CI를 이용하는것을 볼수가 있다. 논란의 여지가 있는 다른 XP 프랙티스와는 달리 이 접근방법에 대한 안좋은 이야기는 거의 들은바가 없다.
만일 CI를 사용하고 있지 않다면 바로 시도해 보길 강력하게 권한다. 만약 적용하고 있다면 이 기사에 담겨있는 아아이디어들이 이를 더 효율적으로 만드는데 도움이 될것이다. 우리는 지난 몇년간 CI에 대해 많은것을 배웠으며 여전이 더 많이 배우고 향상시킬 여지가 있길 바란다.
그러면 지속적인 통합을 적용하고 싶다면 어디서 부터 시작해야 할까 ? 위에서 언급한 프랙티스 전체 셋트를 구성하게 되면 모든 이점을 얻을수 있다. 하지만 그렇다고 이 모든것을 한꺼번에 시작할 필요는 없다.
여기에 어떤 고정된 해결책이 존재하는것은 아니다. 많은 부분이 여러분들의 팀과 환경에 달려있다. 그러나 이를 적용하는데 배워야 할 것들이 몇가지 있다.
첫번째 단계중 하나는 빌드를 자동화 하는 것이다. 명령어 하나로 전체 시스템을 빌드 할수 있도록 필요한 모든것은 소스 컨트롤로부터 얻을수 있어야 한다. 많은 프로젝트에서 이것을 사소한 것으로 생각하는데 이것이 다른 어떤 작업보다 중요하다. 처음에 필요에 따라 빌드를 할수도 있고 자동으로 밤에 빌드를 할수도 있다. 이런 일들이 지속적인 통합은 아니지만 자동으로 밤마다 빌드하는것 그중 한 단계로 볼 수 있다.
자동화된 테스트를 빌드에 추가하라. 잘못될수 있는 중요한 부분을 확인해서 자동화 테스트에 이 결함이 드러날수 있도록 하라. 기존 프로젝트에서는 특히 정말 잘된 테스트를 빨리 만든다는게 어렵다. 빌드에 테스트를 추가하는것은 시간이 걸린다. 언젠가는 이 모든 진부한 작업들을 시작해야만 한다. 큰일은 하루 아침에 이루어 지는건 아니다.
커밋 빌드의 속도를 높이도록 노력하라. 지속적인 통합을 위한 빌드가 몇시간이 걸리더라도 아예 안하는것보다는 낫다. 그러나 10분이라는 빌드 시간에 대한 가이드를 지키는게 더 좋다. 보통 시스템의 느린 부분에 대한 종속성을 없애기 위해 코드 기반의 많은 수정작업이 필요하기도 한다.
새로운 프로젝트를 시작한다면 지속적인 통합을 같이 시작하라. 빌드 시간을 살펴보고 10분 규칙보다 더 느리면 가능한 조치를 취해야 한다. 코드가 커지기 전에 가능한 빨리 필요한 구조개선을 취하는게 노력을 줄일 수 있다.
도움을 청하라. 지속적인 통합을 적용해본 사람을 찾아라. 다른 새로운 기법처럼 어떤 결과가 나와야 하는지 모르는 사람에게는 CI를 적용하는게 어렵다. 멘토를 찾는데는 돈이 들수도 있다. 하지만 시간이나 생산성을 높여줄 것이다.(ThoughtWorks는 이 영역에 대해 컨설팅을 해왔다. 결국 우리가 했던 많은 실수를 다른 사람들도 할 것이다.)
전반적으로 내가 생각하는 지속적인 통합의 가장 크고 넓은 범위의 장점은 위험을 줄여준다는 것이다. 내가 첫번째 단락에서 언급했던것 처럼 소프트웨어 프로젝트 초기로 돌아가 보자. 장기 프로젝트에는 끝이 정해져 있지만 실제로 끝나기 전에는 얼마나 오래걸릴지 사실은 알수가 없다.
통합이 지연되는 문제는 이 작업이 얼마나 오래 걸릴지 예측하기가 아주 힘들다는 것이고 더욱 안좋은건 이 과정이 얼마나 진행되었는지 아는것이 어렵다는 것이다. 이런 알수없는 부분은 프로젝트에서 가장 긴장되는 부분이다. 이런 경우가 아주 드물긴 하지만 이미 늦은건 아니다.
지속적인 통합은 이런 문제에 대해 완벽한 해결책이다. 통합은 오래 걸리지 않으며 알수 없는 부분을 완전히 제거할 수 있다. 시스템에서 어느 위치에 있는지, 뭐가 동작하는지, 뭐가 동작하지 않는지, 시스템에 버그가 무엇인지 항상 알수 있다.
버그는 자신감을 없애는 심술맞은 것이고 일정과 명성을 망친다. 소프트웨어를 배포할때의 버그는 사용자를 화나게 만든다. 작업중에 발생하는 버그는 소프트웨어의 남은 부분을 제대로 동작하도록 만드는걸 더 어렵게 만든다.
지속적인 통합이 버그를 없애주는건 아니지만 이를 발견하고 제거하는걸 쉽게 만들어 준다. 이렇게 해주는건 셀프 테스트 코드 덕분이다. 버그를 빨리 발견하게되면 이를 없애는것도 더 쉬어진다. 시스템에서 수정한 부분이 작기 때문에 살펴볼 필요가 없다. 시스템에서 작업한지 얼마 안됐기 때문에 작업한것을 생생이 기억하고 있다. 다시 만들게 되면 버그를 발견하는걸 더 쉽게 해준다. 시스템의 현재 버전과 버그가 없는 초기 버전과 비교하는 diff debugingg에 대해 살펴보라.
버그 역시 축척된다. 버그가 많아지면 이를 하나씩 없애는것은 더 어려워진다. 이는 버그와 상호작용 때문에 부분적으로 나타나는것이며 여러 결함은 실패로 나타나는데 각 결함을 발견하는건 더 어려워진다. 심리적인 부분도 있는데 버그가 많아지면 사람들은 버그를 발견하고 제거하는데 더 적은 에너지를 사용하게 된다. 실용주의 프로그래머에서는 이 현상을 Broken Windows syndrome 이라고 부른다.
지속적인 통합은 프로젝트에서 제품과 프로세스에서 극적으로 버그를 줄여준다. 그러나 이런 장점은 얼마나 테스트를 잘 하느냐에 직접적으로 관련이 있다는걸 강조하고 싶다. 차이를 알수 있도록 테스트를 빌드하는게 어렵지 않다는 사실을 알게 될 것이다. 그러나 보통은 팀이 정말로 낮은 수준의 잠재 버그를 발견하는데는 약간의 시간이 걸린다. 이 말은 계속해서 테스트를 만들고 향상시켜 나가야 한다는 의미이다.
만일 지속적인 통합을 사용한다면 잦은 배포를 위한 가장 큰 벽을 하나 제거한 셈이다. 잦은 배포는 사용자게 새로운 기능을 빨리 제공할수 있게 해주며 개발 주기를 더욱 공동의 작업으로 만들어주기 때문에 중요하다. 고객과 개발사이의 벽을 허무는데 도움이 되는데, 이 벽은 성공적인 개발에 있어 가장 큰 벽이라고 나는 생각한다.
지속적 통합을 위해서 여러 환경이 필요한데, 커밋 테스트를 실행하기 위한 환경과, 2차 테스트를 실행하기 위한 여러 환경을 말한다. 이 환경에 하루에 여러번 실행본을 옮겨야 한다면, 이를 자동화 하길 원할것이다. 그래서 어떤 환경이든지 쉽게 애플리케이션을 배포할 수 있는 스크립트를 갖는건 중요하다.
이는 자연스러운 결과로 이와 유사하게 제품을 배포할수 있는 스크립트도 가지고 있어야만 한다. 제품을 매일 배포하지는 않지만 (그렇지만 나는 프로젝트가 그렇게 하도록 한다.) 자동화된 배포는 프로세스 진행 속도를 높여주며 에러를 줄이는데 도움이 된다. 이는 테스트 환경에 이용하는 배포와 같은 정도의 능력이면 되기 때문에 값싼 선택이다.
만일 제품이 별도의 자동화된 기능에 의해 배포된다면, 자동화된 롤백도 고려해야 한다. 때때로 잘못된일이 발생하는데 가능한 빨리 좋은 상태로 되돌려야 한다. 자동으로 복구를 하는기능은 배포에 대한 많은 부담을 줄여주며 사람들이 더 자주 배포를 할수있게 해주고 사용자가 더 빨리 새로운 기능을 사용할 수 있게 해준다.(루비 온 레일즈 커뮤니티는 Capistrano 라는 툴을 개발했는데 이런 작업을 해주는 툴의 좋은 예라고 할 수 있다.)
클러스터된 환경에서 한번에 한개 노드에 새로운 소프트웨어를 배포하도록 하면 점차적으로 몇 시간 내로 애플리케이션을 변경할수가 있다.
많은 사람들이 자주 릴리즈 할때 공통으로 사용하는것은 데이터베이스 마이그레이션이다. 데이터베이스의 변경은 다루기 어려운데 데이터베이스 스키마는 변경할수 없으면서 데이터를 제대로 마이그레이션 해야하기 때문이다. 이 기사는 내 동료 프라모드 사달라즈(Pramod Sadalage)가 리팩토링과 데이터베이스 마이그레이션을 자동화 하기 위해 사용한 기법에 대해 설명하고 있다. [앰블러-사달라즈]
내가 일반적인 웹 애플리케이션을 배포하다가 알게된 부분적으로 재밌는 시도는 사용자 일부에 대해 시험적인 빌드를 배포해 보는 것이다. 그러면 팀은 시험 빌드가 어떤지 살펴볼수 있으며 이를 전체 사용자에게 배포할지 여부를 결정할때 사용할수 있다. 이 방법은 최종 선택을 확정하기전에 새로운 기능과 UI를 테스트 할수 있다. 자동화된 배포는 좋은 CI 규칙과 밀접하게 관련이 있으며 이를 가능하게 하는것은 중요하다.
지속적 통합은 모든게 커뮤니케이션을 위한 것이다. 그렇기 때문에 모든 사람이 쉽게 시스템의 상태를 볼수있으며 이를 바꿀수 있게 해줘야 한다.
커뮤니케이션에서 가장 중요한 것중의 하나가 메인라인 빌드의 상태이다. 만일 크루즈 컨트롤을 사용하고 있다면 거기에는 빌드가 어떻게 진행되고 있는지 보여주고 마지막 메인라인 빌드 상태를 보여주는 웹사이트가 들어있다.
많은 팀은 빌드 시스템의 상태를 좀 더 보기 쉽게 하기 위해서 녹색이면 빌드가 잘 되고 있는거고 빨간색이면 빌드가 안되고 있다고 빌드시스템 상태 표시하는 화면을 계속 켜놓기도 한다. 특히 좋은 것은 빨간색과 녹색의 lava lamps 인데 단순히 빌드 상태만을 나타내는게 아니라 얼마나 오래 지속되고 있는가도 나타낸다. 빨간색 램프의 거품은 빌드가 깨진 상태로 오랫도안 지속되고 있다는걸 나타낸다. 각 팀은 이러한 빌드 센서를 선택해야 하는데 재밌는걸 선택하는게 좋다.(최근에 어떤 팀은 춤추는 토기를 이용하는것도 본적이 있다.)
만일 수동으로 CI 프로세스를 처리한다 하더라도, 빌드 상태를 보여주는건 여전히 중요하다. 물리적 빌드 서버 모니터는 메인라인 빌드 상태를 보여준다. 때로는 누구든지 현재 빌드를 할수 있도록 책상위에 빌드 토큰을 놔둘수도 있다.(좀 어리석을지 몰라도 고무로 된 닭도 훌룡한 선택이다.) 가끔 사람들은 빌드가 성공했음을 벨소리같은 간단한 소리로 알리기도 한다.
CI 서버의 웹 페이지는 사실 이보다 더 많은정보를 전해준다. 크루즈 컨트롤은 누가 빌드를 했는지 무엇이 변경됐는지 알수있는 정보를 제공한다. 또한 변경 이력을 제공하여 팀 구성원들이 최근에 프로젝트 변경사항에 대해 알수 있게 해준다. 이를 이용하는 팀은 누가 무엇을 했는지 시스템이 변경되었는지를 알수 있다.
웹 사이트를 이용하는 또 다른 이점은 프로젝트의 상태를 알기 위해 같은 장소에 있지 않아도 된다는 것이다. 일반적으로 모든사람들은 같이 앉아서 활발하게 프로젝트를 진행하는게 좋지만 가끔은 떨어져 일하는 사람들을 지켜봐야 하기도 하다. 여러 프로젝트의 빌드 정보를 그룹으로 묶는것도 유용할때가 있는데 다른 프로젝트의 자동화 상태를 제공한다.
좋은 정보를 컴퓨터 화면에만 나타내지 않는다. 내가 즐겨 나타내는것은 프로젝트에서 CI에 관한것 들이다. 안정화된 빌드가 되기까지는 오랜 시간이 필요하다. 벽에 하루가 사각형으로 되어있는 일년이 모두 표시되는 큰 달력을 걸어놓는다. 매일 QA 그룹은 커밋 테스트가 통과한 안정화된 빌드가 있는날에는 녹색 스티커를 붙이고 그렇지 않으면 빨간 스티커를 붙인다. 시간이 흐를수록 달력에는 빌드 상태가 어떻게 진행되는지 나타나는데 점점 녹색이 늘어나게 되면 달력을 치워도 된다. 목표가 달성된 것이다.
소프트웨어를 개발하는데 가장 어려운 부분중 하나는 제대로된 소프트웨어를 빌드할수 있다고 확신하는 것이다. 미리 우리가 원하는것을 명시하고 이렇게 바로잡는것이 아주 어렵다는 것을 알게되었다. 사람들은 어떤것을 보는것이 쉽다고 여기는데 사실은 그렇지 않기 때문에 변화시킬 방법이 필요하다. 애자일 개발 프로세스는 사실 사람의 행위에 의해 이점을 얻길 기대한다.
이를 돕기 위해 소프트웨어 프로젝트에서 일하는 사람은 누구든 최신 실행본에 접근할수 있어야 하고, 데모나 테스트나 이번주 변경사항을 보기위해 이를 실행할수 있어야 한다.
이렇게 하는것은 아주 수월하다. 사람들이 최신 실행본을 어디서 찾을수 있는지 잘 알수 있도록 확실히 해야한다. 몇가지 실행본을 저장해 두는것도 유용하다. 아주 최신본을 위해서는 커밋 테스트를 통과한 최신 실행본을 저장해 두어야 하며 그런 실행본은 커밋 테스트에 의해 아주 안정적이여야 한다.
만일 잘 정의된 이터레이션을 가진 프로세스를 따른다면, 마지막 이터레이션에도 따로 빌드를 두는것이 현명한 일이다. 특히 데모는 기능에 익숙해 지기 위해 필요하다. 그래서 보통 데모를 하는 사람은 오퍼레이션을 위해 최신 기능을 빼는게 더 나은 선택이기도 하다.
테스팅 포인트란 시스템이 제품으로서 갖는 문제를 해결하기 위한 제어 가능한 조건이다. 여기서 중요한 부분은 시스템이 실행되는 환경에 있다. 만일 다른 환경에서 테스트 한다면, 모든 차이는 테스트가 실행되지 않았어야 하는 상황에서 실행되면서 발생하는 위험에 따른 결과를 만들게 된다.
그렇기 때문에 테스트 환경을 실제 제품이 운영되는 환경과 가능한 일치시켜야만 한다. 같은 버전의 같은 데이터베이스 소프트웨어, 같은 버전의 운영체제를 이용하라. 시스템이 실제로 라이브러리를 이용하지 않는다 하더라도 테스트 환경에서도 운영 환경과 같이 똑같은 라이브러리를 배치하라. 같은 IP 주소와 포트를 이용하고 같은 하드웨어에서 실행되도록 하라.
물론 현실에는 한계가 있다. 만일 데스크 탑 소프트웨어를 개발한다면, 다른 사람들이 실행하는 외부 업체 소프트웨어가 설치된 모든 가능한 데스크탑 사본에서 테스트 한다는건 비현실적이다. 유사하게 어떤 운영환경은 이중화 하는데 비용이 너무 비싸서 불가능할 수도 있다.(내가 가끔은 적당히 비싼 환경을 이중화 하지 않는것이 경제적으로 잘못되었다는 현실에 부딪힐지라도)
이런 한계에도 불구하고 목표는 가능한 운영환경을 이중화하는 것이고 테스트 환경과 운영환경간의 모든 차이를 받아들이고 이에 따른 위험을 이해해야 한다.
만약 다루기 힘든 많은 커뮤니케이션을 제외하면 매우 간단한 설정만 남는다면, 최소한의 차이만 있는 환경에서 커밋빌드를 실행할 수 있다. 그러나 때로는 시스템 응답속도가 느리거나 중단되기 때문에 test doubles를 이용할 필요가 있다. 커밋 테스트의 속도를 높이기 위해 인위적인 환경을 구성하는것은 일반적이며 두번째 테스트를 위해서는 운영환경과 동일한 환경을 이용해야 한다.
나는 테스트 환경을 구성하는것을 용이하게 하기 위해 가상화를 이용하는데 관심이 증가하는데 주목하고 있다. 가상화 서버는 모든 필요한 요소를 가상화 함으로써 비용을 줄여준다.
최신 빌드를 설치하고 테스트를 실행하는것은 어느정도 수월한 작업이다. 더우기 이는 한 서버에서 여러 테스트를 가능하게 해주면서 네트워크 상의 여러 서버를 하나의 서버처럼 테스트 할수 있게 해주기도 한다. 가상화가 성능상에 불이익을 가져다 주지만, 의미있는 선택이다.
지속적 통합의 정수는 빠른 피드백에 있다. 여기서 나는 CI 할동에서 빌드가 오래 걸리는것 만큼 치명적인 것은 없다는 사실에 동의한다. 내 동료 대부분은 빌드가 한시간 정도 걸려야 완전히 합당하다고 여긴다. 나는 팀이 가능한 빌드가 빨리 끝나길 원한다는걸 기억한다. 그러나 때로는 빨리 빌드하는게 어려울때도 여전히 빌드를 해야 하는 경우가 있다.
그러나 대부분 프로젝트에 대해 XP에서는 10분 빌드가 최적이라고 가이드 한다. 현대 프로젝트의 대부분은 이것이 가능하다. 가능한 여기에 노력을 기울이는건 의미있는 일이다. 왜냐면 빌드 시간을 매분 줄일때마다 모든 개발자가 커밋할때마다 이시간을 절약할 수 있기 때문이다. CI는 잦은 커밋을 요구하기 때문에, 이 때문에 많은 시간이 들어간다.
만일 빌드 타임 한시간으로 시작한다면, 더 빨리 빌드되도록 할수 있을것이다. 새로운 프로젝트에 작업을 시작했다 하더라도 어떻게 하면 더 빨리 빌드 할수있는지를 고민해야 한다. 엔터프라이즈 애플리케이션에서는 적어도 일반적인 병목점을 찾을수 있는데 바로 테스팅이다. 특히 데이터베이스와 같은 외부 서비스와 연관된 테스트가 그렇다.
아마도 가장 중요한 단계는 안정된 빌드(staged build)가 되도록 설정하는 것에서 시작하는 것이다. (빌드 파이프라인이라고 부르는) 안정된 빌드에 깔려있는 개념은 순서대로 여러 빌드가 이루어지는 것이다. 메인라인에 커밋되면 첫번째 빌드가 실행되는데 이를 커밋 빌드(commit build)라고 부른다. 커밋 빌드는 누군가 메인라인에 커밋할때 필요한 빌드이다. 커밋 빌드는 빨리 이루어져야 하며 그 결과는 버그를 발견하는데 드는 시간을 줄여준다. 재밌은 사실은 다른 사람들이 작업할수 있게 커밋 빌드가 안정적이 되도록 버그를 발견하는데 필요한것과 스피드에 대한 균형이 필요하다는 것이다.
일단 커밋 빌드가 이루어 지면 다른 사람들도 자신감을 갖고 코딩을 할수 있다. 그러나 아직 테스트가 남아있다. 여기서 시작해야 한다. 또 다른 서버에서 시간이 오래 걸리는 테스트가 실행되도록 할수 있다.
이 간단한 예는 2단계 빌드에 있다. 첫번째는 컴파일하고 데이터베이스와는 완전히 분리된 로컬상의 테스트를 실행한다. 이런 테스트는 아주 빨리 실행되기 때문에 10분이내 빌드라는 가이드라인을 준수할수 가 있다. 그러나 실제 데이터베이스와 연관있는 경우처럼 더 많은 범위의 상호작용과 연관된 버그는 발견되지 않을 것이다. 두번째 빌드는 실제 데이터베이스를 사용하며 엔드 투 엔드로 동작하는 등의 다른 형태의 테스트를 실행한다. 이런 테스트는 몇시간이 걸릴수도 있다.
이 시나리오는 사람들이 커밋 빌드에서 첫번째 빌드를 사용하게 하고 이를 주 CI 사이클에서도 이용한다. 두번째 단계 빌드는 실행되는 순서로는 두번째 빌드이며, 테스트를 위해 가장 최근에 성공한 커밋 빌드를 이용한다. 만약 두번째 빌드가 실패한다고 해서 모든 작업을 멈춰야 한다는걸 의미하지 않지만, 커밋 빌드가 실행되는 동안에 팀은 가능한 빨리 그런 버그를 제거하기 위해 노력해야 한다. 사실 이 두번째 빌드가 유지되지 않으면, 매번 버그가 발견될것이기 때문에 몇일내로 이를 처리해야한다.
두번째 빌드에 버그가 발견됐다는건 커밋빌드도 또 다른 테스트를 해야 한다는걸 나타낸다. 두번째 빌드가 실패했다는 사실은 커밋빌드가 버그를 잡을수 있도록 새로운 테스트를 추가해야 한다는걸 의미하며, 그렇게 하면 커밋빌드는 이 버그를 수정하게 된다.
이런 방식은 이런일이 발생할때 마다 커밋 테스트를 더 강하게 해준다. 버그가 드러나도록 해주는 테스트를 빨리 실행되게 할수 없는 경우가 있는데, 그래서 두번째 빌드에 들어갈 테스트 조건을 결정해야 한다. 다행스러운건 대부분은 커밋 빌드에 적당한 테스트를 추가할수 있다는 것이다.
이 예제는 2단계 빌드이지만, 기본 원칙은 이후에 실행되는 어떤 빌드에서도 확장될수 있다. 커밋 빌드 이후의 빌드 역시 병렬로 수행할수 있는데, 그래서 만약 두시간이 걸리는 두번째 테스트가 있다면 각 테스트를 반씩 두개 서버에서 실행되도록 해서 반응속도를 높일수 있다. 병렬의 두번째 빌드를 이렇게 이용하면 성능테스트와 같은 모든 종류의 자동화된 테스트를 기존의 정규 빌드 프로세스에 추가할수가 있다.(나는 지난 몇년간 ThoughtWorks사가 수행했던 다양한 프로젝트에서 많은 재밌는 기법들을 실행해왔다. 나는 개발자들이 이를 작성하도록 설득하길 바란다.)
매일 커밋하게 되면, 팀은 자주 빌드를 테스트 해야 한다. 그래야 메인라인을 건강한 상태로 유지할수가 있다. 그러나 사실 잘못될 여지는 여전히 남아있다. 그 이유중 하나는 커밋하기 전에 빌드하고 업데이트 해야 한다는 원칙을 지키지 않기 때문이다. 또 다른 이유는 개발자 PC 환경의 차이에서 발생한다.
그 결과 정기적 빌드는 통합 서버에서 확인해야만 하는데 빌드가 성공적으로 된 경우만 커밋해야 한다. 커밋하는 개발자는 누구라도 이에 대한 책임을 져야하며, 개발자는 메인라인을 모니터링 해서 에러가 발생하면 이를 수정해야 한다. 이런일이 발생하게 되면 그 날 추가된 모든 커밋이 빌드될 때까지 아무도 집에 가지 못한다.
이를 확실하게 하기 위해서는 두가지 방법이 있다. : 수동 빌드를 이용하는 방버과 CI 서버를 이용하는 방법이다.
수동 빌드는 가장 단순한 방법이다. 중요한건 개발자가 레파지터리에 커밋하기 전에 로컬빌드를 유사하게 진행해야 한다는 것이다. 개발자는 통합서버에서 메인라인을 체크아웃하고 통합 빌드를 실행한다. 커밋된 사항에 대해 빌드가 성공하는지 모든 과정을 지켜본다.(짐 쇼어(Jim Shore)의 설명을 참고하라.)
CI 서버는 레파지터리를 모니터링 한다. 레파지터리에 커밋할때마다 서버는 자동으로 소스를 통합 서버로 체크아웃 하여 빌드를 초기화 하고 커밋한 사람에게 빌드 결과를 알려준다. 커밋한 사람은 이메일 같은걸로 통보가 올때까지 완료된게 아니다.
ThoughtWorks사는 CI 서버를 정말 좋아한다. 사실 우리회사가 CruiseControl 과 CruiseControl.NET 개발을 이끌고 있는데 오픈소스 CI 서버로 널리 사용되고 있다. ThoughtWorkers는 이 오픈소스 프로젝트에서 여전히 활발하게 커미터로 활동하고 있는 폴 줄리어서(Paul Julius), 제이슨 입(Jason Yip), 오웬 로저스(Owen Rodgers)를 좋아한다. 우리는 크루즈 컨트롤을 거의 모든 프로젝트에서 사용하고 있으며 그 결과에 만족하고 있다.
모든 사람이 CI 서버를 사용하는것을 좋아하는건 아니다. 짐 쇼어(Jim Shore)는 왜 수동빌드가 자동빌드보다 좋은지를 설명하고 있다. 나 역시 CI가 단지 크루즈 컨트롤을 설치하는것 이상의 작업이라는데 동의한다. 여기 나와있는 모든 프랙티스는 지속적 통합을 효과적으로 적용하는데 필요한 사항들이다. 그러나 CI를 적용하는 많은 팀들에게 있어 크루즈 컨트롤은 도움이 되는 툴이다.
많은 조직들은 매일 밤과 같은 일정에 따라 정기적으로 빌드를 한다. 이는 지속적 빌드와는 약간 다른데 지속적 통합이라고 하기에는 부족하다. 지속적 통합에서는 가능한 빨리 문제를 발견할수 있어야 한다. 매일밤 빌드하는것은 버그가 하루종일 발견되지않고 숨어있다는것을 의미한다. 버그가 시스템이 오래 머물러 있게 되면 이를 발견해서 제거하는데 오랜 시간이 필요하다.
지속적 통합의 중요한 부분은 메인라인 빌드가 실패했을때 즉시 이를 수정해야 한다는 것이다. CI를 기반으로 작업할때는 항상 안정적인 소스를 기준으로 개발을 진행해야 한다. 메인라인 빌드가 깨지는게 나쁜건 아니다. 커밋하기 전에 로컬에서 빌드하고 수정하는등의 작업에 충분한 주의를 기울이지 않으면 이런상황은 언제든지 발생할수가 있다. 그러나 메인라인 빌드가 깨졌을때 가능한 빨리 이를 수정하는게 중요하다. 메인라인 빌드가 깨지는 것을 막기 위해서는 pending head를 이용하는것을 고려해 보라.
팀에 CI를 소개할때 가장 어려운 부분중 하나가 이를 가려내는것이다. 초기의 팀은 메인라인 빌드를 갖고 일하려는 습관을 고수하려고 하는데, 특히 기존 코드를 기반으로 일하려든다. 애플리케이션이 정기적으로 잘못되더라도 참을성을 가지고 진행해야 한다. 낙심하지 마라.
통합은 커뮤니케이션이 주가 된다. 통합은 개발자가 다른 개발자에게 변경사항에 대해 이야기 하도록 해준다. 잦은 커뮤니케이션은 사람들에게 개발에 따른 변경을 빨리 알려주게 된다.
개발자가 메인라인에 커밋을 하는데 있어 단 하나의 사전조건은 코드가 빌드되어야 한다는 것이다. 물론 이 조건은 빌드 테스트도 성공해야 함을 내포한다. 커밋의 주기가 어떻든지간에 개발자는 작업한 것을 메인라인에 맞춰서 반영해야 하는데, 메인라인과 충돌이 발생하면 이를 해결해서 자기 PC에서 빌드가 되도록 해야 한다. 빌드가 되면 메인라인에 커밋해도 된다.
이렇게 자주 하면 할수록, 개발자는 두 개발자간에 충돌이 있음을 빨리 발견할 수가 있다. 문제를 빨리 해결하는데 있어 중요한건 빨리 발견하는 것이다. 개발자가 몇시간 마다 커밋하다 발생하는 충돌은 발생한지 몇시간내에 발견되기 때문에 이를 해결하는건 그리 어렵지 않다. 몇주동안 남아있던 충돌을 해결하는게 어렵다.
작업한게 빌드된다는 사실은 문자그대로 컴파일 단계에서의 충돌을 발견했다는 의미이다. 빌드 단계중에 셀프 테스팅이 있다면 코드가 실행되는 중에 충돌 역시 발견할수가 있다. 후자의 충돌이 오랫동안 코드에 숨겨져 있던 버그를 발견하는 셈이다. 커밋간에 단지 몇시간의 차이만 있다 하더라도 문제는 여러 부분에 숨어있게 된다. 더우기 변경이 많이 이루어진 경우에는 diff-debugiing을 사용하는게 버그를 찾는데 도움이 된다.
내가 가진 일반적인 규칙은 모든 개발자는 매일 레파지터리에 커밋해야만 한다는 것이다. 사실 개발자가 더 자주 커밋하는게 유용할때도 있다. 더 자주 커밋하면 충돌 에러때문에 살펴봐야 하는곳이 더 적어지고, 그래서 더 빨리 충돌을 수정할 수 있다.
잦은 커밋은 개발자가 자기가 작업할 분량을 몇시간내로 마칠수 있는 작은 단위로 세분화 하도록 만든다. 이는 진척도를 추적하고 진척도를 이해하는데 도움이 된다. 사람들은 처음에는 몇 시간내에 의미있는 작업을 할수 있다고 생각하지 않는다. 하지만 멘토링과 실습을 통해서 가능하다는것을 알게된다.
보통 빌드는 컴파일, 링킹외에 프로그램을 실행하는데 필요한 모든 자질 구레한 일을 의미한다. 프로그램이 실행된다고 해서 아무런 문제가 없다고 할수는 없다. 요즘 언어들은 많은 버그를 잡을수 있지만 놓칠수도 있다.
버그를 더 빨리 효율적으로 잡는 좋은 방법은 빌드 프로세스에 자동화된 테스트를 추가하는 것이다. 물론 완벽한 테스트는 없다. 하지만 사용하기 충분할 정도의 많은 버그를 잡을수 있다. 특히 XP와 TDD가 등장 하면서 셀프 테스트 코드가 인기를 끌게 되었고 그 결과 많은 사람들이 이 기법의 가치를 알게 되었다.
내 글을 읽는 독자들은 내가 XP와 TDD를 광적으로 좋아한다는걸 알고 있을것이다. 그러나 나는 이런 접근이 셀프 테스트 코드의 이점을 얻는데 꼭 필요한건 아니라는 점을 강조하고 싶다. 이 접근방법 둘다는 코드를 작성하기 전에 작성한 테스트 코드가 패스하는것을 중요하게 여긴다. 이런 테스트는 버그를 잡을수 있는 시스템을 설계하게 해준다. 이는 좋은일이지만 CI에서 반드시 필요한건 아니다. 셀프 테스트 코드에 대한 요구는 약한 편이다.(TDD는 셀프 테스트 코드를 만드는걸 선호하는 편이다.)
셀프 테스트 코드에서 자동화된 테스트는 버그를 담고 있는 코드의 많은 부분을 검사할수 있어야 한다. 테스트는 간단한 명령어를 실행하는일을 없애주고 스스로를 체크할수 있어야 한다. 테스트를 실행한 결과는 어떤 테스트든지 실패하게 되면 이를 알아 차릴수 있게 해주어야 한다. 빌드 하는 동안에 셀프 테스팅이 실패하면 빌드는 실패하게 된다.
최근 몇년간에 걸쳐 TDD의 증가는 이런 종류의 테스트에 적합한 XUnit 계열의 오픈소스툴을 인기 상승을 가져왔다. XUnit 툴은 우리 ThoughtWorks사에게 매우 가치가 있다는것이 증명되었고 나는 항상 사람들에게 이를 사용하라고 제안하고 있다. 이 툴은 켄트벡(Kent Beck)에 의해 시작되었으며 셀프 테스팅 환경을 구성하는것을 도와준다.
XUnit 툴이 셀프 테스팅 코드를 만들기 위한 시작점이라는 것은 확실하다. 엔드 투 엔드(end-to-end) 테스팅을 위한 다른 툴을 찾을수 있는데 FIT,
Selenium, Sahi, Watir, FITnesse가 바로 이런 툴로서 아주 넓은 범위의 테스트를 위한 툴인데 여기서이 툴에 대해 상세하게다루지는 않겠다.
물론 버그을 찾기위해 테스트에만 의지할 수는 없다. 테스트는 버그가 없다는 사실을 증명해주지 못한다. 그러나 셀프 테스팅 빌드가 도움이 된다는것은 확실하다. 완벽하지 못한 테스트라도 자주 실행하는게 완벽한 테스트를 전혀 작성하지 않은 것보다는 낫다고 할수 있다.
소스를 가지고 실행중인 시스템을 만드는 작업은 컴파일하고 파일을 옮기고 스키마를 데이터베이스에 로딩하는것과 같은 복잡한 프로세스로 이루어진다. 그러나 소프트웨어를 개발하는 이 부분의 대부분은 자동화 되어야 한다. 그리고 그 결과 자동화가 되는것이다. 사람들에게 낮선 명령어를 입력하고 대화상자 누르는 일을 시키는것은 시간 낭비이고 실수를 만들게 된다.
빌드를 위한 자동화된 환경은 시스템의 공통된 특징이다. 유닉스는 수십년에 걸쳐 만들어 졌다, 자바 커뮤니티는 앤트(Ant)를 개발했고, .NET 커뮤니티는 Nant를 개발했고 지금은 MSBuild를 쓰고 있다. 명령어를 이용하는 이 스크립트를 이용해서 시스템을 빌드하고 실행할수 있다.
자동화된 빌드에 모든것을 포함시키지 않는것은 흔히 저지르는 실수이다. 빌드는 레파지터리에서 데이터베이스 스키마를 가져올수 있어야하며 실행환경을 찾을수 있어야 한다. 이전에 언급했던 규칙을 기억해 보면 누구든간에 새로운 PC를 받아서 레파지터리에서 소스를 체크아웃해서 명령어를 실행하면 자기 PC에서 시스템을 실행할 수 있어야 한다.
빌드 스크립트는 종종 특정 플랫폼이나 커뮤니티에 따라 다양한 특징을 갖는데 그럴 필요가 없다. 대부분의 자바 프로젝트는 앤트를 사용하지만 일부는 루비(Ruby)를 사용한다.(Ruby Rake 시스템은 아주 뛰어난 빌드 스크립트 툴이다.) 초기 마이크로소프트 COM 프로젝트를 앤트로 자동화 하는건 아주 중요했다.
커다란 빌드는 시간이 걸리곤 하는데 작은 변화에 이 모든 과정을 반복할 필요는 없다. 그래서 좋은 빌드 툴은 프로세스의 일부를 변경해야 하는지 분석한다. 이렇게 하는 일반적인 방법은 소스와 오브젝트 파일의 날짜를 검사해서 소스 날짜가 더 나중인것만 컴파일하면 된다. 그러나 종속성은 다루기 어렵다. 만일 객체 파일 하나가 변경되면 종속된 파일들은 다시 빌드되어야 한다. 컴파일러는 이를 처리할수도 있고 그러지 못할수 도 있다.
필요에 따라 빌드를 하기 위애 다른 것들이 필요할때도 있다. 시스템을 빌드할때 테스트코드가 있을수도 있고 없을수도 있으며 다른 테스트 집합이 있을수도 있다. 어떤 컴포넌트는 단독으로 빌드할수 있다. 빌드 스크립트는 다른 경우에 또 다른 타겟으로 빌드 할수 있게 해준다.
많은 사람들이 IDE를 사용하며 대부분의 IDE는 내부에 일종의 빌드 관리 프로세스를 갖고 있다. 그러나 이 파일은 항상 IDE를 기반으로 하며 쉽게 망가진다. 더우기 일을 하기 위해 IDE를 필요로 한다. IDE에 맞게 프로젝트 파일을 설정하고 개별적인 개발을 위해 이를 이용하는것도 좋다. 그러나 서버에서 사용수 있고 다른 스크립트를 실행할수 있도록 마스터 빌드를 갖는것은 중요하다. 그래서 자바 프로젝트에서 개발자가 IDE로 빌드하는것은 좋지만 개발 서버에서 실행할수 있다는걸 확신하기 위해 마스터 빌드는 앤트를 이용해야 한다.
표준 빌드 프로세스를 도와주는 툴을 찾는건 그렇게 어렵지 않다. 표준 빌드 프로세스를 정의하면 빌드 툴이 보통 제공하는 스크립트 언어를 이용해서 빌드 스크립트를 작성해야 하는데, 빌드 툴이라는게 빌드 프로세스를 대신해 주는것은 아니라 단순히 빌드 프로세스를 유지할수 있도록 도와줄 뿐이다. 그러면 빌드 스크립트는 어떤 특징을 가져야 하는가 ?
이해할수 있어야 한다. : 개발자들이 빌드 스크립트를 이해하고 이를 잘 다룰수 있어야 한다. XML은 좋은 대안이지만 자칫 너무 복잡한 XML을 양산하는 경우도 있다.
원하는 기능을 제공해야 한다. : 스크립트 언어는 많은 기능을 제공해야 한다. Java언어의 특징 뿐만 아니라 각종 OS 명령어와 같은 외부 명령어도 실행할수 있어야 한다.
확장 가능해야 한다. : 프로젝트에서는 서로 다른 기술을 사용하는 경우가 많다. 필요한 기능을 추가해서 빌드 스크립트를 작성할 수 있어야 한다.
크로스 플랫폼을 지원해야 한다. : 엔터프라이즈 환경에서는 보통은 개발을 윈도우에서 진행하지만 테스트는 윈도우가 아닌 환경에서 진행하는 경우가 많다. 빌드 스크립트는 유닉스나 윈도우와 같은 크로스 플랫폼에서 사용가능해야 한다.
이런 특징을 만족하는 빌드 툴에는 아파치 그룹에서 개발한 Ant나 Maven을 들수가 있다.