본문 바로가기
Homo Faber/Techniques

빌드 시간을 더 빠르게 하라

by javauser 2012. 5. 12.

빌드의 통합은 형상관리도구, 워크스페이스의 소스코드 관리 도구, 배포 바이너리 버전 관리 도구 등을 통해서 상당 부분 자동화를 시킬 수 있다. 빌드는 단순히 형상관리에 있는 소스 코드들을 모두 가지고 와서 실행 파일로 컴파일을 만들어주는 의미만 포함되는 것은 아니다. 물론, 이러한 자동화 역시 전체 소스 코드의 깨짐 현상을 방지할 수 있고, 이를 지속적으로 반복적으로 수행한다면 소스 코드 깨짐 현상에 대한 위험은 줄일 수 있을 것이다.


문제는 전체 소스 코드의 크기가 적고, 어느 정도 인내할 수 있는 시간 동안 빌드를 한다면 괜찮겠지만, 소스 크기가 상당하고 많은 사람들이 만들어내는 소스 코드 (심지어 서로 다른 지역에 있는 사람들이 만들어내는 소스 코드와 같이 빌드하는 경우) 라면 상황이 달라진다.


실제 약 20 ~ 30만 라인을 소스 체크아웃에서부터 약 3분 정도 소요되고(물론, 물리적인 환경에 따라 다르기는 하겠지만, 여기서는 동일 환경에서 빌드한 수치들로 상대적인 수치로 받아들이면 된다), 약 70 ~ 80 만 라인은 약 15분 정도가 소요되고, 120 ~ 130 만 라인 소스 빌드 시간은 약 30분 가량이 든다. 이와 같은 수치로 본다면, 소스 코드의 증가는 빌드 시간의 단순한 증가를 의미하는 것도 있겠지만, 그 수치로 봐서도 기하급수적인 수치로 늘어날 것으로 예상해볼 수 있다. 실제 약 50만 라인 정도를 빌드하는 시간이 4분 정도 소요되었는데, 7 ~ 80 만으로 늘어나는 경우에는 그 수치가 2배를 훨씬 넘어서는 기간이 걸렸다. (빌드 시간은 내부 코드의 복잡도도 영향을 미치기 때문에 서로 다른 성격의 애플리케이션이나 컴포넌트를 비교하는 경우에는 수치적으로는 다소 차이가 발생할 수도 있다.)



위의 그림에서 LOC의 증가 정도(기울기)와 그에 따른 빌드 시간의 증가 정도(기울기)의 차이가 점점 늘어나는 것으로 볼 수 있다. 즉, 한번에 빌드하는 LOC가 증가할수록 그에 따른 빌드 시간의 증가는 더 급격히 늘어난다고 볼 수 있다.


통합 빌드의 시간이 길어졌을 때 통합하는 시간이 걸리는 것은 당연하며, 특히 빌드 중에 빌드 에러가 나서 다시 빌드를 해야하는 경우의 수가 많아질수록 그 시간이 더 늘어난다는 것이다. 예를 들어, 30분에 걸쳐서 빌드하는 애플리케이션의 경우, 거의 빌드 막바지인 25분 경과 시점에 빌드 에러가 발생한다면, 이를 조치하고 다시 처음부터 빌드를 해야하기 때문에 그 시간은 거의 2배인 1시간 가량을 소비해야 한다. 이러한 시간 소비는 그 시간 동안 형상관리에 다시 새로운 코드를 커밋하는 과정에서 재반복이 될 우려가 있으며, 심지어는 몇시간 동안 빌드를 못하는 경우도 있다.


이러한 문제들에 대한 해결책은 빠른 빌드를 위해서 필요하며, 단순히 빌드 자동화만 도입한다고 해결되는 부분은 아니다. 빌드 자동화의 장점과 더불어서 원칙이 있는 각 모듈(컴포넌트)간의 관계를 형성하여 빌드 단위를 최소한을 나누어서 애플리케이션을 구성하도록 해야 한다.


빌드 단위의 정의


빌드 단위를 정의하려면, 최소한 아키텍처에서 배포 단위를 결정해야 한다. 통상 배포 단위는 하나의 컴포넌트 단위로 매핑하며, 이는 컴파일된 바이너리 파일들의 묶음이기도 하다. 이 배포 단위는 서로 의존관계를 형성하고, 그 의존관계들로 인해서 배포 단위는 빌드의 순서를 결정하게 된다. 즉, 컴포넌트는 해당 비즈니스 로직의 성격으로 분류되어야 하며, 이러한 컴포넌트 유형 간의 의존관계 원칙이 최소한 정의되어야 한다.


빌드 단위를 컴포넌트로 정하는 경우, 컴포넌트 유형별로 관리를 할 필요가 있으며, 각 유형을 묶어서 관리할 수 있는 체계가 필요하다. Maven을 사용하는 경우, 컴포넌트 유형을 관리하는 단위를 하나의 POM으로 묶어서 그 하위에 해당 컴포넌트들을 위치시켜 상위에서 빌드가 되면 동일한 유형의 컴포넌트들이 동시에 빌드할 수 있는 형태로 관리가 가능하다. 컴포넌트 유형은 크게 분류해보면 Business Data Type을 모아두는 형태, Utility 형태, Entity 형태, Process 형태 등으로 나눌 수 있다. 분류체계를 더 세분화시킬 수도 있지만, 기본적인 비즈니스 로직의 근간을 이루는 컴포넌트를 이와 같이 분류를 해볼 수 있다. 이 컴포넌트들은 한꺼번에 배포를 해도 되지만, 컴포넌트 유형 간의 의존관계 규칙을 강화시키거나 규정하면 해당 의존관계를 이루는 컴포넌트의 순서에 맞추어서 자동 빌드에 대한 프로세스를 나누어 볼 수 있다. 예를 들어, Process가 Entity나 Utility로의 의존관계만 형성되어 있다면, Entity나 Utility를 먼저 빌드/배포하고, Process를 그 후에 배포하도록 순서를 결정할 수 있다.


마찬가지로, 외부 시스템과 연결되는 부분을 모아두는 유형을 별도로 모아둘 수 있으며, UI와 연계되는 로직을 구성하는 UI 관련 컴포넌트를 별도의 유형으로 분류할 수도 있다. 이 경우에도 다른 컴포넌트 유형과의 의존관계를 고려해서 빌드 순서를 조정할 수도 있다.


빌드 프로세스 세팅


통상 빌드 자동화 도구(CI, Continuous Integration)를 사용하는 하나의 빌드 작업과 다른 빌드 작업을 연결시킬 수가 있으며, 이 빌드 작업은 여러개의 빌드 작업으로 분화(fork) 가능하다.


즉, 컴포넌트 유형의 빌드 순서가 A -> B -> (C | D | E) 라고 한다면, A의 빌드 작업이 종료함과 동시에 B의 빌드 작업을 연결해서 기동시킬 수 있으며, B의 빌드작업이 종료됨과 동시에 C, D, E의 빌드 작업이 동시에 수행하는 것이 가능하다.


이와 같이 하나의 애플리케이션을 구성하는 컴포넌트를 빌드하는데 빌드 프로세스 형태로 구성했을 때의 장점은 무엇보다 적은 코드의 빌드 작업이 수행되기 때문에 전체 코드를 빌드하는 것보다도 시간이 더 적게 걸릴 수 있으며, 중간에 빌드 에러가 발생되면, 멈춘 작업에서 에러를 수정하여 다시 이전에 수행된 작업을 다시 기동하지 않고 그 이후부터 다시 빌드를 시작할 수 있는 장점을 가진다.



위의 그림에서 위의 알파벳으로 표현된 부분은 제일 하단에 있는 하나의 애플리케이션을 구성하는 컴포넌트 유형을 분리하여 빌드 프로세스로 구성한 것이며, 그 순서는 오른쪽에 나타나 있다. 이들 각각의 빌드 작업들의 걸리는 시간의 총합은 총 10분 30초 정도가 되며, 전체를 하나의 빌드 작업으로 구성하는 경우에 약 14분 정도가 소요되었다. 즉, 약 1.5배의 시간이 더 걸리는 셈이다.


빌드를 이와 같이 애플리케이션 전체를 통합하여 하나의 작업을 만드는 것보다 가능하면 나누어서 빌드를 하도록 구성하는 편이 시간적인 비용 측면에서 크게 이익이 된다.


고려 사항(한계)


빌드를 자그마한 단위로 나누어서 작업을 만드는 경우, 도구의 지원에 따라서 분화(fork) 프로세스는 가능하지만, 병합(join) 프로세스를 지원을 하지 않는 경우가 있다. 위의 경우에도 H, J, L, N으로 나누어진 빌드 프로세스가 모두 O 작업으로 병합되지만, 실제로는 O가 4번 실행되는 형태로 빌드 작업으로 구성되어 있다. 하지만, 이렇다 하더라도 빌드 중간에 에러나는 부분에 있어서는 다시 A부터 실행하지 않아도 되기 때문에 큰 이익이 있으며, O가 4번 빌드된다고 하더라도 전체적으로 통합/빌드/배포 작업에 있어서 아무런 영향은 미치지는 않는다. 다만, 불필요한 작업이 발생할 뿐이다. CI 도구가 이러한 부분을 잘 지원해주거나, 혹은 내부적으로 플러그인이나 스크립트를 사용해서 이러한 불필요한 작업에 대해서는 여력이 된다면 보정을 해줄 수도 있을 것이다.


빌드 프로세스에 맞게 컴포넌트 유형 간의 의존관계가 형성되어 있어야 한다. 예를 들어, C 작업 후 D를 수행해야 하는데, C 유형의 컴포넌들이 D 작업 이후의 유형에 대해 의존관계를 형성한다면, 위의 빌드 프로세스는 조정을 해야 하거나 해당 의존관계를 다른 형태로 구성해야 한다. 이는 아키텍처 관점에서 컴포넌트 유형의 의존관계를 빌드를 통해서 규제하거나 강제하는 효과를 낳는다.


빌드 작업에 대한 인스턴스가 하나만 수행하도록 하는 경우에는 전체적인 시간에 대한 차이가 그리 크지는 않는다. 예를 들어, 위의 빌드 프로세스에서 H, J, L, N으로 나뉘어서 동시적으로 빌드 프로세스가 수행되지 않고, 하나의 빌드 작업만을 차례로 수행하게 한다면, 전체 빌드 시간은 차이가 얼마 나지 않을 수도 있다. 하지만, 이전에 언급했듯이 처음부터 다시 빌드하는 수고는 덜 수 있는 충분한 장점을 가진다.



빌드는 자동화시키려는 노력은 필요하며, 나름대로 원칙을 세워서 작은 단위로 빌드하려는 작업들이 필요하다. 또한, 빌드를 하는 시간을 빠르게 하면 할수록 개발자가 자신이 만든 코드에 대한 피드백을 빨리 받을 수 있는 장점을 가지게 된다. (실제로 에러 수정시 수정된 내용이 제대로 되었는지를 파악하는데 통합/빌드/배포의 긴 시간으로 아무런 진전을 못하는 경우도 많다)





반응형

'Homo Faber > Techniques' 카테고리의 다른 글

신중하게 행동하라  (0) 2010.06.16
Spring의 AOP로 구현한 테스트 스파이(Spy)  (0) 2009.12.04
비즈니스 컴포넌트와 데이터 ownership  (4) 2009.10.05
m2eclipse 설치  (0) 2009.09.22
m2eclipse 소개  (0) 2009.09.22