E D R , A S I H C RSS

Continuous Integration


다음은 Martin Fowler 의 ContinuousIntegration 관련 글. 일본어번역기 돌림.; 문맥에 따른 수정필수.;

원제: Continuous Integration


Martin Fowler
Chief Scientist, ThoughtWorks

Matthew Foemmel
ThoughtWorks

「확실한 빌드를 실시한다」 -- 이것은 어떤 소프트웨어 개발 프로세스든 중요한 일이다. 그 비교적은, 이것이 제대로되어 있지 않은 것에 놀라게 해진다. 본론문에서는, Matt 가 ThoughtWorks 사에서의 있는 대규모 프로젝트에 대해 채용한 프로세스를 소개한다. 이 프로세스는 전사적인 확대를 보이고 있다. 테스트 부분도 포함해 「모두가 자동화되었다」 「재현 가능한」빌드를, 「날에 몇번이나」실시하는 것에 역점이 두어지고 있다. 이 프로세스를 이용하면, 개발자는 인테그레이션을 매일 실시하게 되므로, 인테그레이션에 수반하는 문제를 줄일 수가 있다.

계속적 인테그레이션의 혜택
많이 하는 편이 바람직하다
「성공한 빌드」란?
싱글 소스 포인트
자동화된 빌드 스크립트
자기 테스트용 코드
마스터 빌드
체크인
결어
논의에는 오르지만, 실행에 옮겨지는 것이 적은 「베스트 프랙티스」가 소프트웨어 개발에는 가득 있다. 그 중에서도, 가장 기본적 한편 중요한 것 하나가, 「완전하게 자동화된 빌드와 테스트 프로세스」다. 이것은, 프로젝트 팀이 자신의 소프트웨어의 빌드나 테스트를 하루에 몇번이나 실시하는 것을 가능하게 하는 것이다. 물론, 매일의 빌드(데일리 빌드), 라고 하는 생각이 논의된 것은 이것이 처음은 아니다.McConnnell 는 데일리 빌드를 베스트 프랙티스로서 추천 하고 있어, 또 마이크로소프트에서의 개발 어프로치의 특징이라고 해도 길게 알려져 있다. 그러나 우리는,XP 커뮤니티의 소리를 모방해, 「데일리 빌드」는 최소한의 요건에 지나지 않는다, 라고 주장하고 싶다. 완전하게 자동화된 프로세스에 의해 하루에 몇번이나 빌드를 실시하는 것은, 실현 가능하다 해, 또 실현시킬만한 가치가 있는 것이다.

XP의 프랙티스의 하나로서 내걸 수 있고 있는 「계속적 인테그레이션」이라고 하는 단어를 우리는 사용하고 있다. 그러나, 이 프랙티스 자체는 XP에 관계없이 지금까지도 쭉 있던 것이고, 또 XP를 자신의 일에 사용하려고는 절대로 생각하지 않는 것 같은 사람들이라도, 이 프랙티스를 사용하고 있는 사람도 많다. 우리는 XP 를 스스로의 소프트웨어 개발 프로세스의 규준으로서 채용하고 있으므로, 우리의 표현이나 프랙티스에는 XP 의 영향을 깊게 감싸고 있다. 그러나, 당신이 다른 XP프랙티스에는 따르지 않았다고 해도, 이 「계속적 인테그레이션」을 이용하는 것은 가능하다 -- 사실 우리는, 이 「계속적 인테그레이션」은, 모든 착실한 소프트웨어 개발 활동의 기초가 되는 것이라고 생각하고 있다.

자동화된 데일리 빌드의 실현에 필요한 (일)것은, 이하의 점에 정리한다.

모든 원시 코드가 격납되어 누구라도 최신의(그리고 과거의) 소스를 꺼내는 것이 가능한, 다만 하나의 출입구를 설정하는 것
빌드 프로세스를 자동화해, 누구라도, 커멘드 하나로 소스로부터 시스템을 만들어 낼 수가 있는 것
테스트 작업을 자동화해, 커멘드 하나로 언제라도 테스트스트를 실행할 수 있도록(듯이) 하는 것
현행의 실행 가능 모듈로, 가장 적절하다라고 자신을 가질 수 있는 것 같은 것을, 누구라도 입수 가능하도록 하는 것.

위로 내건 것의 실현에는 모두, 어느 정도의 훈련을 필요로 한다. 실천해 봐 우리는, 프로젝트에 이것들을 도입하는 것은 용이하지 않는 것을 배웠다. 그러나 한편, 일단 도입된 후의 유지에는, 그만큼 노를 필요로 하지 않는 것도 알았다.

계속적 인테그레이션의 혜택
계속적 인테그레이션에 대해 말할 때에, 말로 전하기 어려운 부분이 있다. 그것은, 계속적 인테그레이션은 개발 전체에 관련되는 「패턴」에의 이행을 가져오는 것이라고 하는 것이어, 이것만은, 현장에서 체험해 보지 않는다고 이해하기 어려운 것이다. 실은, 보통 사람이라도, 개인으로 작업하고 있는 동안은 분위기로서 이 개발 패턴을 잡고 있다 -- 라고 하는 것도 그 때는, 통합 하는 상대라고 하면 자신 밖에 없기 때문이다. 팀에 의한 개발이 되면(자), 팀 개발에 대해 물건이라고 해도 괜찮은 몇개의 「귀찮음」이 나오는 것이라고 일반적으로 생각되고 있다. 계속적 인테그레이션을 사용하려면 훈련이 필요하게 되지만, 그 대신에, 이 「귀찮음」을 없애 주는 것이다.

어느 사람이 만든 버그가 다른 사람의 작업에 영향을 주어 버려, 게다가 그것에 당사자들이 눈치채지 않은, 이라고 하는 상황에서의 디버그 작업에 시간이 걸려져 버리는 일이 있다. 계속적 인테그레이션의 최대의 혜택은, 이러한 세션을 없게 해 주기로 있다. 이 손의 버그 발견은 매우 어렵다. 버그가, 한 명의 담당 범위내가 아니고, 두 개의 작업 결과가 일으키는 상호작용안에 잠복하고 있기 때문이다. 시간의 경과가 이 문제를 한층 더 곤란한 것으로 한다. 이 손의 인테그레이션 버그가 짜넣어진 시점은, 버그가 최초로 그 모습을 나타내는 몇주간이나 몇개월도 전이라고 하는 것이 많다. 결과적으로, 원인 발견에도 긴 시간이 소비되게 된다.

계속적 인테그레이션을 사용하면, 이 손의 버그의 대다수는, 짜넣어진 그 날 동안에 곧바로 모습을 나타낼 것이다. 게다가 상호작용의 적어도 한편의 옆을 담당하는 모듈이 어떤 것일까하고 말하는 일도 즉석에서 판명된다. 이렇게 되면, 버그의 수색 범위는 큰폭으로 좁힐 수가 있다. 만일 버그가 발견되지 않았다고 해도, 버그 있어 코드를 제품에 넣지 않게 할 수 있으므로, 최악에서도 「 아직 버그가 잡히지 않은 기능을 떨어뜨린다」라고 하는 라인을 유지하는 것이 가능하게 된다(물론, 버그를 제외한 것보다도 기능을 추가하는 것 쪽이 중요하다고 하는 상황도 있든지, 그러나 그 경우에서도, 정보를 얻은 다음의 판단(informed choice)을 실시할 수가 있다).

물론, 이 방법으로 인테그레이션에 관련되는 버그는 모두 포착 가능하다면 보장하는 것은 아니다. 이 방법은 테스트를 하는 것만으로, 테스트는 「에러가 존재하지 않는다」것을 증명할 수 없다. 중요한 (일)것은, 계속적 인테그레이션은 코스트에 알맞을 뿐(만큼)의 충분한 수의 버그를 포착해 준다, 라고 하는 것이다.

이것들을 조합하면(자), 인테그레이션에 얽히는 버그의 추적에 소비되는 시간이 절약되는 것으로부터, 생산성이 증대하게 된다. 이 점을 과학적인 어프로치로 연구한 사람은 내가 아는 한 없는 것 같지만, 매우 유력한 경험적 증거라면 있다. 계속적 인테그레이션은 「인테그레이션 지옥」에서 보내지 않을 수 없는 시간을 줄여 준다. 그 뿐만 아니라, 이 지옥을, 평범의 아무것도 아닌 것(non-event)으로 바꾸어 준다.

많이 하는 편이 바람직하다
계속적 인테그레이션이 미치는 근본적인 영향에는, 직감을 배반하는 곳(중)이 있다. 그것은 「보다 빈번하게 인테그레이션을 실시하는 편이, 보기 드물게 밖에 실시하지 않는 것 보다도 바람직하다」라고 하는 것이다. 실천하고 있는 사람에게는 이것은 당연한 일이다. 그러나 실천하고 있지 않는 사람에게 있어, 이것은, 자신의 시가의 경험과 모순되도록(듯이) 비쳐 버린다.

보기 드물게 밖에, 예를 들면 하루 이상의 간격으로 밖에 인테그레이션을 실시하지 않는 것이면, 인테그레이션은 시간으로 노력을 소비하는 폐일이다. 너무나 귀찮아서, 이것을 좀 더 빈번하게 하자 등이라고는 생각하지 않을 것이다. 「프로젝트가 이만큼 커지면(자), 데일리 빌드는 불가능해」라고 하는 코멘트를 우리도 잘 들은 것이다.

그러나 실제로 그 데일리 빌드를 실시하고 있는 프로젝트가 있다. 50명의 개발 팀이 작업을 실시하는, 20만행에 가까운 코드 베이스를 기초로, 우리는 날에 20회 이상이나 빌드를 실시하고 있다. 마이크로소프트는 수천만행의 코드가 있는 프로젝트로, 이 데일리 빌드를 실시하고 있다.

왜 이것이 가능한가? 인테그레이션에 걸리는 노력은, 인테그레이션을 실시하는 간격의 길이에 대해서 지수함수적으로 증가해 가기 때문이다. 어떠한 측도가 적격인가는 확실하지 않다. 그러나, 이것의 의미하는 곳은, 주에 1회의 인테그레이션은 날에 1회의 인테그레이션의 5배 걸리는, 것은 아니고, 아마 25배는 걸려 버린다고 하는 것이다. 당신이 만약, 인테그레이션이 귀찮다고 느끼고 있었다고 해도, 이것을 「한층 더 많은 회수의 인테그레이션등으로 올 리가 없다」것이 증거로 해 파악해서는 안된다. 잘 하면, 몇번이나 인테그레이션을 실시하는 작업은 편해지고, 또 인테그레이션 그 자체에 걸리는 시간도 훨씬 적게 된다.

여기서 중요해지는 것은 「자동화」이다. 대부분의 인테그레이션은 자동화할 수 있고, 또 그렇게 해야 한다. 소스를 배달시켜 와, 컴파일 해, 링크해, 철저하게 테스트하는, 이것들 전부를 자동화해야 한다. 전부 끝나면(자), 빌드가 성공했는지 어떠했는지, 마지막에 결과를 예스나 노우로 출력한다. 예스라면 무시해 상관없다. 노우였다고 해도, 마지막에 간 소프트웨어 구성에의 변경을 취소하고 나서 빌드 하면, 이번에는 성공할 것이다. 굳이 머리를 사용하지 않아도, 「움직인다」빌드를 작성할 수 있는 것이다.

이러한 자동화 프로세스가 있으면, 몇번이나 좋아할 뿐(만큼) 빌드를 할 수가 있다. 제약이 되는 것은, 1회의 빌드에 걸리는 시간만이다.

「성공한 빌드」란?
무엇때문에 「성공한 빌드」라고 간주하는지? 이것을 결정하는 것은 중요하다. 그런 것은 당연하다고 생각될지도 모르지만, 이것이 꽤 만만치 않은 것이다. 어느 프로젝트의 리뷰를 Martin 가 간 것 때의 일이다. 「데일리 빌드를 실시하고 있을까?」라고 하는 질문에 대해서 멤버는 「하고 있다」라고 하는 대답을 돌려주었다. 그러나, 다행히도 Ron Jeffries 가 그 자리에 있어, 그가 한층 더 돌진해 「빌드의 에러가 일어났을 경우는 어떻게 하는지?」라고 신 있었다. 대답은 「담당하고 있는 사람에게 E메일로 통지한다」라고 하는 것인……실제로는, 프로젝트에서는 이제 몇개월도 빌드에 성공하지 않았다. 이것으로는 데일리 빌드는 아니다. 빌드를 「하려고 하는 매일의 시도」에 지나지 않는다.

우리는 매우 욕심장이인 정의를 「성공한 빌드」에 부과하기로 한다.

모든 최신의 원시 파일이 구성 관리 시스템으로부터 체크아웃 된다
모든 파일이, 신품인 상태로부터 컴파일 된다
생성된 오브젝트 파일(이 경우는 Java 클래스 파일)이, 링크되어 실행 가능한 장소에 배치된다(jar 파일안에 넣어진다)
할 수 있던 시스템의 실행을 개시해, 동시에 이 시스템에 대해서 테스트스트(우리의 경우는, 약 150개에 이르는 테스트 클래스)를 실행한다.
만약 상기의 모든 스텝이, 에러도 일으키지 않고 , 또 사람의 손도 빌리지 않고 실행되어 한편 모든 테스트에 패스한 것이면, 우리는 「성공한 빌드」를 손에 넣은 것이 된다.


보통 사람은, 컴파일 작업과 링크 작업을 빌드라고 생각하고 있다. 그러나 우리는, 빌드에는 적어도 「어플리케이션을 실행하는 것」 「간단한 테스트를 실시하는 것」까지 포함해야 한다고 생각한다(McConnnell 는 이것을 「스모크 테스트」라고 부르고 있는 -- 스윗치를 넣으면(자) 연기가 뭉게뭉게……, 등은 되지 않지만 것을 확인하고 있는 것이다. ). 이것들에 가세해, 게다가 철저한 테스트를 실시하면, 계속적 인테그레이션이 가져오는 가치는 보다 큰 것이 되므로, 그것도 아울러 실시하는 편이 바람직할 것이다.

싱글 소스 포인트
간단하게 인테그레이션을 실시하기 위해서(때문에)는, 모든 개발자가, 현행의 원시 코드 전일식을 간단하게 손에 넣을 수 있도록(듯이) 해 두지 않으면 안 된다. 「최신의 코드는 어디다!」라고 많은 개발자에게 (들)물어 주위, 게다가로 코드를 카피해, 그런데 이것은 그 디렉토리에 있어…등과 배치를 생각하거나 하지 않으면 빌드가 시작할 수 없다고 하는 것은 최악이다.

채워야 할 기준은 간단하다:「누구라도, 진신인 머신을 1대 준비해, 네트워크에 이으면, 후는 개발중의 시스템의 빌드에 필요한 최신의 원시 파일의 모두를 커멘드 일발로 호출할 수 있다.」이것이다.

이 문제의 분명한(라고 믿고 싶지만) 해결 방법은, 구성 관리(원시 코드 관리) 시스템을 이용해, 여기에 모든 코드를 두는 것이다. 보통 구성 관리 시스템은 네트워크 넘어로 사용되는 것을 전제로 하고 있고, 소스의 진전을 추적하기 위한 툴도 준비해 있다. 게다가 판 관리의 기능도 붙어 있어, 각 파일의 구판을 꺼내는 일도 간단하다. 코스트도 문제가 되지 않는다. 그렇다고 하는 것도,CVS 라고 하는 open source의 뛰어난 구성 관리툴이 있기 때문이다.

이것이 기능하려면 , 모든 원시 파일을 구성 관리 시스템에 넣을 필요가 있다. 이 「모두」에는, 보통에 상정되고 있는 이상가 포함되는:스크립트, 속성 파일, 데이타베이스 schema를 정의한 DLL, 인스톨용 스크립트, 어쨌든 진신인 머신상에서 빌드를 실시할 때에 필요한 것 「모두」이다. 관리하에 있는 코드는 발견되었지만, 중요한 파일로 발견되지 않는 것이 있어, 찾지 않으면 안 되는, 이라고 하는 것이 자주(잘) 있기 때문이다.

그러니까, 모든 것이, 다만 하나의 원시 코드 트리하에 있도록(듯이) 해야 한다. 자주(잘), 별개의 컴퍼넌트에 대해서 구성 관리 시스템의 다른 프로젝트를 할당하는 사람이 있다. 이것이라면 「어느 컴퍼넌트의 어느 버젼이, 다른 컴퍼넌트의 어느 버젼과 잘 움직이는 것인가」기억하지 않으면 안 된다. 아무래도 소스를 나누지 않아안 되는 상황도 있을 것이다. 그러나 그런 상황은 생각되고 있는 것보다 훨씬 보기 드물다. 원시 코드 트리를 한데 합쳐도, 거기로부터 복수의 컴퍼넌트의 빌드를 실시하는 것은 가능하기 때문이다. 이런 일은, 보존 영역의 구조로 나누는 것이 아니라, 빌드용 스크립트의 처리로 거절해 나누어야 하는 것이다.

자동화된 빌드 스크립트
1 다스나 그 정도의 파일군으로부터 되는 소규모의 프로그램을 쓰고 있다면, 어플리케이션의 빌드 등,javac *. java 라고 하는 컴파일러 기동의 커멘드 일발로 해결되는 이야기일 것이다. 대규모 프로젝트에서는 그렇게는 가지 않는다. 파일은 많은 디렉토리에 분산하고 있다. 생성된 오브젝트 파일이 올바른 장소에 놓여지는 것을 확인하지 않으면 안 된다. 컴파일 뿐만이 아니라 링크 작업도 있을 것이다. 컴파일의 전에, 다른 코드로부터 생성해 두지 않으면 안 되는 코드도 있다. 테스트도, 자동적으로 실행되도록(듯이) 하지 않으면 안 된다.

큰 빌드에는 시간이 걸리는 것이다. 그러니까, 더한 변경이 적었을 때 등은 빌드의 전부의 스텝을 실행하고 싶지 않다, 라고 생각할 것이다. 좋은 빌드 툴은, 빌드 프로세스 중 어디를 변경하면 좋은가 해석을 해 준다. 자주 있는 방법은, 소스와 오브젝트의 일자를 체크해, 소스의 일자 쪽이 새로울 때만 컴파일 한다고 하는 것이다. 그러나 의존관계(dependencies)는 이것만에 머무르지 않는다. 어느 오브젝트 파일이 변경되었을 때에는, 그 파일에 의존하고 있는 다른 오브젝트 파일도 재빌드 할 필요가 있다. 컴파일러는 이러한 기능을 서포트하고 있을지도 모르고, 하고 있지 않을지도 모른다.

필요에 따라서, 다른 것을 빌드 하는 일이 있다. 테스트 코드 붙어, 또는 없음의 시스템이나, 보통은 사용하지 않는 테스트를 포함한 시스템 등이다. 단독으로 빌드 가능한 컴퍼넌트도 있다. 빌드 스크립트는 「개별의 케이스에 응해 별개의 타겟을 빌드 한다」라고 하는 요구를 채우는 것이 아니면 안 된다.

커멘드 라인으로부터의 입력을 졸업하면(자), 나머지는 스크립트가 무거운 짐을 부담해 준다. 이것들을 셸 스크립트로 쓰거나 또는 perl나 python라고 했던 것보다 고기능의 스크립트 언어로 쓰고 있을지도 모르다. 그러나 그 중에서 이 목적으로 설계된 환경, 예를 들면 Unix의 Make등을 사용하는 것이 좋은, 이라는 것이 될 것이다.

그러나 우리가 간 Java 밤개발에서는, 곧바로, 보다 철저한 해결안을 생각하는 필요하게 직면했다. 실제로 Matt 는 Enterprize Java 에서의 개발용으로 설계된 "Jinx"로 불리는 빌드용 툴에, 상당한 시간을 할애했다. 그런데 최근이 되어, open source의 빌드용 툴 Ant 로 전환하기로 했다. Ant는 매우 Jinx에 설계가 닮아 있어 어느쪽이나, Java 파일을 컴파일 해 그 패키지를 Jar 에 넣는 작업을 해 준다고 하는 것이다. Ant 에 독자적인 확장을 써 입에 물어, 빌드내에서 다른 작업을 실시하게 하는 일도 용이했다.

우리의 팀 중(안)에서도, IDE(역주:통합 개발 환경)를 사용하고 있는 사람은 많다. 그리고, 몇개의 IDE에는 빌드 관리 프로세스같은 것이 짜넣어지고 있다. 그러나, 그 관리 프로세스의 과정에서 IDE 전용의 파일을 이용하고 있어 이것들은 취약하다라고 하는 것이 많다. 게다가 IDE가 없으면 움직이지 않는다고 하는 문제도 있다. 따라서, IDE 의 이용자가 개인의 개발을 하려면 자신용의 프로젝트 파일을 설정받지만, 메인이 되는 빌드는 Ant 로 실시하고, 또 마스터 빌드는, Ant 가 달리는 서버상에서 실행된다.

자기 테스트용 코드
프로그램을 컴파일러에 통했던이라는 것만으로는 불충분하다. 강하고 형지를 무늬를 박아서 염색한 것 된 언어의 컴파일러는 많은 문제점을 지적해 주겠지만, 그런데도, 컴파일이 성공했을 때에 간과되어 버리는 실수의 수는 너무 많다. 이러한 실수를 찾아내는 도움으로서 우리가 강조하고 싶은 것은, 「자동화된 테스트」 -- XP 로 창도 되고 있는 프랙티스의 하나 -- 라고 하는 규율에 따르는 것이다.

XP 에서는 테스트를, 「단체 테스트」와「acceptance test(기능 테스트)」라고 하는 두 개의 카테고리로 분류하고 있다. 「단체 테스트」는 개발자에 의해 쓰여져 클래스 한 개만이라든지, 몇개의 클래스라든지를 테스트하는 것이 보통이다. 「acceptance test」는(개발자의 조력을 얻으면서) 고객이나 외부의 테스트 그룹에 의해 쓰여져 시스템 전체의 구석에서 구석까지를 테스트하는 것이다. 우리는 양쪽 모두의 테스트를 사용하고, 또 어느 쪽의 테스트에 관해서도, 할 수 있는 한 자동화를 실시하고 있다.

빌드의 일부로서"BVT"(Build Verification Tests:빌드검증 테스트)라고 부르고 있는 테스트스트를 실행한다. 「빌드가 성공했다」라고 말할 수 있으려면 ,"BVT"에 포함되는 모든 테스트가 성공하지 않으면 안 된다. XP스타일의 단체 테스트는 모두"BVT"에 포함된다. 이 논문은 빌드에 대해 쓰여진 것이기 때문에, BVT에 대한 기술이 중심이 된다. 그러나, 「테스트 작업」의 전선에는 BVT 만이 아니고 제2진도 있는 것이어, BVT만으로, 테스트 작업과 QA에 걸리는 공정수를 추측할 수 있다고는 생각하지 않으면 좋겠다. 실제, 우리의 곳의 QA그룹의 사람들은, BVT를 패스할 때까지는 우리의 코드를 볼 것도 없다. 그들은 동작하는 빌드 밖에 취급하지 않기 때문이다.

「개발자가 코드를 쓸 때는, 코드 대응하는 테스트도 쓴다」이것이 기본 원칙이다. 태스크가 종료하면(자), 제품용의 코드 만이 아니게 테스트용의 코드도 체크인 한다. XP를 충실히 실천하고 있는 사람이라면,「테스트가 앞」이라고 하는 프로그래밍·스타일을 채용할 것이다:처음은 실패하는 것 같은 테스트가 쓸 때까지 , 코드를 써선 안 된다. 새로운 기능을 시스템에 가세하려고 하면(자), 우선은, 그 기능이 실장되었을 때에 처음 통과하는 것 같은 테스트를 써, 그 후에, 테스트를 통하도록 노력하는 것이다.

우리는, Java로 테스트를 쓰고 있다. 이것은, 개발에 사용하고 있는 언어와 같은가들 , 「테스트 쓰기」도 「코드 쓰기」도 같은이라는 것이 된다. 테스트의 작성이나 정리를 위한 체제에는, JUnit 를 사용하고 있다. JUnit 는 심플한 체제이며, 이것을 사용하면(자), 조금 테스트를 쓰거나 그것을 테스트스트에 가세하거나 대화형이나 배치형인가 선택해 스트를 실행하거나 할 수가 있다(JUnit는, 거의 모든 언어에 대한 판이 갖추어져 있는xUnit 패밀리의 Java판인 것이다).

개발자가 소프트웨어를 쓸 때에는, 컴파일을 실시할 때에, 유니트 테스트의 일부를 실행하는 것이 보통이다. 이것을 하면(자), 개발 시간이 실은 단축된다. 왜냐하면 테스트가, 작업중의 코드에 있는 논리의 실수를 찾아&A 심부름을 해 주기 때문이다. 실수가 있으면, 당신은 디버그 작업을 하는 대신에, 「마지막에 테스트를 성공시킨 코드로부터 더한 변경분 」에만 주의를 지불하면 좋은 것이다. 이러한 변경은 작을 것이므로, 버그를 찾아내는 것도 간단할 것이다.

모든 사람이 엄밀한 XP스타일의 「테스트가 앞」으로 작업하고 있는 것은 아니지만, 그런데도, 테스트와 코드를 동시에 쓰는 것의 이점은 크다. 동시에 쓰는 것은, 개인의 작업을 스피드업 할 뿐더러, 보다 많은 에러를 포착하기 위한 BVT를 만들어내 주기 때문이다. BVT는 날에 몇번이나 실행된다. 따라서 전술한 이유와 동일 이유로, BVT가 검지한 문제가 어디에 있는지, 찾아&A 것은 용이하다는 두다. 즉, 버그를 찾아내는데 코드의 차분 밖에 보지 않아도 되기 때문에, 라고 하는 이유이다. 차분만을 보는 디버그 작업은, 코드를 1 스텝씩 쫓아 가는 디버그 작업보다 쭉 효율적이다.

물론, 테스트로 전부를 커버할 수 있다고 생각해선 안 된다. 잘 말해지도록, 「테스트는 버그의 부재를 증명하지 않는다」 것이다. 그렇다고는 해도, 완전을 기하지 않는 한 「좋은 BVT를 쓰는 것에 대한 담보」를 바랄 수 없는, 이라고 하는 것은 아니다. 불완전한 테스트도, 빈번하게 실행된다면, 쓰여지고 바구니 완전한 테스트등보다 훨씬 좋다.

관련한 문제에 「개발자가 자기 자신의 쓴 코드의 테스트를 써야할 것인가」라고 하는 점이 있다. 스스로 테스트를 해서는 안되는, 왜냐하면 자신의 실수는 간과하기 쉽기 때문이다, 라고 잘 말해진다. 확실히 그렇지만, 자기 테스트의 프로세스를 실현하려면 , 테스트 내용이 코드 베이스에 반영될 때까지의 회전기간이 짧지 않으면 안 된다(역주:타인에게 테스트 작성을 부탁하면(자) 시간이 너무 걸린다). 테스터를 분리 하는 것보다도 짧은 회전기간 쪽이 중요도가 높은 것이다. 그렇다고 하는 것으로 BVT에 관해서는, 개발자의 손에 의한 테스트에 의지하기로 하고 있다. 다만, 독립한 다른 acceptance test도 준비되어 있다.

마스터 빌드
빌드의 자동화는, 개개의 개발자에 있어서도 의미가 있는 것이지만, 그 진가를 발휘하는 것은, 팀 전체가 사용하는 마스터 빌드를 작성할 때이다. 경험에서는, 마스터 빌드의 순서를 정돈하는 것으로, 팀이 결정되어, 인테그레이션에 수반하는 문제를 빨리 발견하는 것이 용이해졌다.

우선 최초의 스텝은, 마스터 빌드를 달리게 하는 머신을 선택하는 것이다. 우리는, 거의 빌드 전업이라고 해도 좋은, Trebuchet 라는 이름("Age Of Empires"는 몇번이나 플레이 한 것이다)의 4-CPU 서버 머신을 사용하고 있다(빌드에 매우 시간이 걸린 초기의 무렵은, 이 정도의 머신 파워가 불가결했다).

빌드 프로세스는, 항상 기동되고 있는 있는 Java 클래스안에 기술되고 있다. 빌드 실행중이 아닌 경우에는, 빌드 프로세스는 while 루프의 내부에서 대기해, 몇분 마다 레포지트리를 체크한다. 마지막 빌드를 한 시점으로부터 아무도 코드를 체크인 하고 있지 않는 경우에는, 대기로 돌아온다. 새로운 코드가 레포지트리에 있으면, 빌드를 개시한다.

빌드는, 레포지트리로부터 모두를 체크아웃 하는 곳(중)으로부터 시작된다. Starteam 가 준비한 대Java용의 API는 매우 뛰어나므로, 레포지트리에 훅을 거는 것은 간단했다. 빌드 demon가, 현재 시각부터 5분전의 레포지트리 상태를 봐, 「그 5분간의 사이에 누군가 체크인을 실시했는지 어떠했는지」를 조사한다. 만약 들어갈 수 있고 있으면, 안전을 위해서(때문에) 5분전의 코드를 체크아웃 한다(이것으로, 레포지트리를 잠그지 않은 채에 누군가가 체크인을 하고 있는 한창때에 체크아웃을 실시하는 것을 방지할 수 있다).

demon는, Trebuchet상의 디렉토리에 체크아웃을 실시한다. 모두 체크아웃 할 수 있으면(자), demon는 ant로 쓰여진 스크립트를 그 디렉토리상에서 실행한다. 여기서, 풀 빌드의 실행은 demon로부터 ant에 인계된다. 풀 빌드는, 모두 소스로부터 실시한다. 컴파일, 그리고 생성된 클래스를 반다스에 오르는 jar 파일로 분류해, EJB 서버군에의 배치에 대비하는 곳(중)까지 ant로 쓰여진 스크립트가 가 버린다.

ant에 컴파일과 배치까지 실시하게 하면(자), 빌드 demon는 새로운 jar 파일에서도는 EJB 서버를 기동해, 한층 더 BVT 테스트스트를 실행한다. 테스트가 달리기 시작해, 전부 패스했더니 「성공한 빌드」의 완성이 된다. 빌드 demon는 Starteam로 돌아와, 체크아웃 된 소스에 빌드 번호로 라벨부를 실시한다. 한층 더 빌드중에 누군가 체크인 하고 있지 않는가 조사해, 만약 있으면(자), 한층 더 다음의 빌드를 개시한다. 없으면, demon는 while 루프 중(안)에서 다음의 체크인을 기다리게 된다.

빌드가 완료하면(자), 빌드 demon는, 그 빌드로 새롭게 파일을 체크인 한 모든 개발자에 대해서 E 메일을 보낸다. 이 메일에는, 빌드의 상황에 대한 통계가 써 있다. 코드를 체크인 한 사람은, 이 메일을 받을 때까지, 건물을 나오면(자) 안 됨, 이라는 것이 되고 있다. (역주:자신의 작업의 결과를 확인할 때까지, 직장을 떠나 집에 돌아가선 안 되는, 이라고 하는 것)

demon는, 각 스텝의 로그를 모두 XML 형식의 로그 파일에 써낸다. Trebuchet상에는 서브 렛이 달리고 있어 이 서브 렛으로부터 로그를 들여다 볼 수 있으므로, 누구라도 빌드의 상황을 알 수 있다는 것이다.


그림 1: 빌드 확인 서브 렛

스크린에는, 현재 실행중의 빌드의 유무, 빌드가 실행중이라면 그 개시시각이 표시된다. 좌하에는 모든 빌드의 이력이, 성공·실패를 불문하고 표시된다. 컴파일의 성공 여부, 테스트 결과, 변경 내용등의 상세를 보려면 , 그 빌드를 클릭하면 좋다.

많은 개발자가, 이 웹페이지를 정기적으로 보고 있는 것을 알 수 있었다. 이것이 있으면(자), 프로젝트로 무엇이 일어나고 있는지, 또 체크인에 의해 무엇이 변경 되려고 하고 있는지, 파악하는데 도움이 된다는 것이다. 언젠가는 이 페이지에, 프로젝트의 다른 정보도 실을까하고 생각하고 있지만, 다만, 그것이라면 정리가 없어질 우려도 있다.

중요한 것은, 어느 개발자도, 마스터 빌드를 자신의 로컬 머신에서도 모방할 수 있도록(듯이) 해 두는 것이다. 이렇게 해 두는 것으로, 인테그레이션에 관계하는 에러가 발생했을 때에도, 마스터 빌드를 멈추는 것 없고, 문제의 조사와 디버그를 개발자의 누군가가 자기로 실시할 수가 있다. 게다가 개발자가 체크인을 하기 전에 로컬에 빌드를 실시하는 것으로, 마스터 빌드로 실패할 가능성을 내릴 수가 있다.

여기서, 마스터 빌드는 깨끗하게, 즉, 모두 소스로부터 작성하는지, 그렇지 않으면 인크리멘탈에 작성해도 괜찮은지, 라고 하는 문제를 물을 수가 있을 것이다. 인크리멘타르비르드 쪽이 훨씬 빠르게 살지만, 일부를 컴파일 하지 않았던 것으로부터 오는 장해가 발생하는 위험이 남는다. 게다가 그 빌드를 재현할 수 없게 되어 버릴 가능성도 있다. 우리의 곳에서는 빌드는 충분히 빠르기 때문에(20만행의 코드에 대해서 약 15분 정도), 매회 크리비르드를 실시해도 불만은 없다. 그러나, 대부분의 경우는 인크리멘타르비르드입니다 하물며, 정기적으로(최악이어도 하루 1회) 크리비르드를 실시하는 것으로 불가사의한 에러가 나타나는 사태에 대비한다, 라고 하는 소프트웨어 하우스도 있을 것이다.

체크인
자동화된 빌드를 채용하면(자), 개발자는, 있는 「리듬」에 따라 소프트웨어의 개발을 실시하게 된다. 이 리듬의 최대중요 파트는, 인테그레이션을 「정기적으로」실시하는 것, 이다. 우리가 방문한 어느 부대에서는, 데일리 빌드를 실천하고는 있었지만, 체크인은 빈번하게 되지 않았었다. 수주간 간격으로 밖에 개발자가 체크인 하지 않는 것이면, 데일리 빌드를 실천해도 의미는 적을 것이다. 우리의 곳에서는, 어느 개발자도 대체로 하루 1회는 체크인을 실시한다, 라고 하는 대범한 지침을 세우고 있다.

새로운 태스크를 시작하기 전에는, 우선은, 개발자는 구성 관리 시스템과의 동기를 잡지 않으면 안 된다. 즉, 로컬에 카피한 원시 코드가 최신의 것임을 보장하는 것이다. 낡은 원시 코드 위에 신규 추가를 실시해도 트러블과 혼란을 야기하는 것만으로 있다.

동기를 취한 뒤에, 개발자는 필요한 파일의 변경을 실시해, 태스크를 해내 간다. 태스크가 완료했을 때나, 아직 도중에 있어도, 통합을 해 상관없다. 그러나, 통합을 실시하려면 , 모든 테스트를 통하지 않으면 안 된다.

인테그레이션을 하려면 , 우선 작업한 카피와 레포지트리의 내용과의 동기를 다시 취한다, 라고 하는 곳(중)으로부터 시작한다. 레포지트리상에서 내용이 바뀐 파일은 모두 작업 디렉토리에 카피되어 한편 충돌이 있으면 구성 관리 시스템이 warning를 낸다. 개발자는 이 「동기를 취한 후의 파일군」에 대해서 빌드를 실시해, 그리고 BVT를 통하지 않으면 안 된다.

여기까지 할 수 있어, 개발자는 새로운 파일을 레포지트리에 위탁해 상관없다. 위탁이 끝나면(자), 개발자는, 마스터 빌드가 실행될 때까지 대기한다. 마스터 빌드가 성공하면(자), 체크인이 성공했다고 하는 것이 된다. 실패라면 어떻게 할까. 문제의 해법이 명확하면, 수정한 코드를 위탁하면 좋다. 문제가 복잡한 경우에는, 우선은 변경을 철회해 한층 더 동기를 취해, 로컬 환경에서 제대로 움직이도록(듯이) 할 필요가 있다. 그 후에 재위탁을 실시한다.

체크인의 내용에 따라서는, 차례를 정해 체크인 작업을 실시할(serialization of the check-in process) 필요가 있다, 라고 하는 경우가 있다. 이 때에는, 동시에 두 명 이상의 개발자가 손에 넣을리가 없는 것 같은 「빌드 토큰」이라고 하는 것을 준비한다. 개발자는 우선 이 토큰을 입수해, 작업 내용의 동기를 취해, 변경점을 위탁해, 마지막에 토큰을 손놓는다. 이렇게 하면, 빌드의 한중간에 두 명 이상의 개발자가 레포지트리 내용을 갱신하는 것을 방지할 수 있다. 다만, 빌드 토큰이 없어도 트러블이 되는 것은 적었기 때문에, 우리는 빌드 토큰을 이용하지 않았다. 같은 마스터 빌드에 대해서 두 명 이상의 개발자가 위탁하는 것 등 언제나 있었다. 그러나 이것이 빌드의 실패로 연결되는 것은 매우 보기 드물었고, 일어났다고 해도 수정은 곧 실시할 수가 있었다.

또, 체크인에 즈음하여 어디까지 주위를 기울이는지, 라고 하는 점에 관해서도, 개개의 개발자의 판단에 맡기기로 했다. 인테그레이션 에러가 발생할 가능성이 얼마나 있는가 하는 견적은, 그것은 그 개발자에게 (들)물을 수 밖에 없기 때문이다. 만약 에러가 발생할 것 같다고 생각하면, 개발자는 로컬 환경에서 빌드 하고 나서 체크인을 실시할 것이다. 에러가 일어나지 않을 것이라고 했더니, 그대로 체크인 할 것이다. 일어나지 않을 것이라고 생각하고 있던 에러가 발생했다고 해도, 마스터 빌드가 실행된 후에 에러에 기분빌려주어진다. 그 개발자는 변경을 취소해, 어디가 이상한가 밝혀내지 않으면 안 되게 된다. -- 이와 같이, 발생해도 곧 찾아내 간단하게 없앨 수가 있는 에러이면, 관대하게 취급해도 상관없다고 하는 것이다.

결어
제대로 한 자동화 빌드 프로세스를 확립하는 것은, 제대로 프로젝트를 제어하는데 있어서 필수 항목인 -- 많은 소프트웨어·한패(지도자)가 그렇게 말해 왔지만, 아직도 현장에서는, 실현되고 있는 편이 드물다고 하는 상황이다.

키가 되는 것은, 정말로 「모두」를 자동화해, 한편 프로세스를 「빈번하게」실시하는 것으로, 인테그레이션에 관련되는 에러를 조기에 찾아내는 것이다. 그러면, 누구에 있어서도, 필요한 변경을 더하는 것이 용이하게 된다. 「만약 만일 자신이 인테그레이션 에러를 일으켰다고 해도 그것은 곧 찾아내 고칠 수 있다」라고 자신을 가질 수 있기 때문이다. 이것의 혜택은 너무나 강력하다. 그러니까, 일단 알아 버렸지만 최후, 이 혜택을 다루어질 것 같은 장면에서는, 당신은 반드시, 날뛰거나 외치거나 할 것임에 틀림없다…


ⓒ Copyright Martin Fowler , all rights reserved
번역:오노 쓰요시 $Id: Cont-j.html, v 1.4 2000/11/30 02:38:48 ono Exp $

japan.hanmir.com

Valid XHTML 1.0! Valid CSS! powered by MoniWiki
last modified 2021-02-07 05:23:00
Processing time 0.0716 sec