스프링과 여타 다른 웹 프로그래밍 학습을 하면서 읽었던 책들이나, 들었던 온라인 강의들은 모두 메이븐(Maven)을 사용했습니다. 때문에 메이븐을 조금씩 익히게 되었는데, 이전에는 필요한 라이브러리를 하나씩 손수 다운로드 받아왔던 터라, 비록 XML로 작성된 구조는 복잡했지만 자동으로 의존성 관리를 해주는 부분을 보며 꽤나 편리하다고 생각했습니다. 또한, 당시에는 다른 빌드 도구의 존재를 크게 지각하지 못했기에 프로젝트를 생성할 때 자연스럽게 익숙한 메이븐을 선택하게 되었습니다.
기존에 진행하던 Hello-World 프로젝트의 경우, 성능테스트 및 개선 작업까지 어느 정도 완료되어 조금 더 심화된 내용들을 학습하고 새롭게 익힌 기술 스택들도 적용해보고자 새로운 프로젝트를 구상하고 있는데요. 프로젝트를 생성하기에 앞서 이제는 빌드 도구 또한 여러 선택지가 있음을 알았으니, 최적의 선택을 위해 각 선택지에 대해 좀 더 자세히 알아보고 이를 비교해보는 시간을 가져보고자 합니다.
컴파일과 빌드란
컴파일(Compile)이란 개발자가 작성한 소스코드를 컴퓨터가 이해할 수 있는 형태의 바이너리 코드로 변환해주는 것을 의미합니다. 소스코드를 작성할 때 사용하는 프로그래밍 언어들은 대부분 사람이 이해하기 편한 형태로 만들어져 있기 때문에 이러한 작업은 필수적입니다. 자바의 경우에는 .java의 확장자를 가진 소스코드를 자바 가상머신(JVM)에서 실행가능한 바이트 코드 형태의 .class파일로 변환하게 됩니다.
빌드(Build)란 소스코드를 실행할 수 있는 가공물로 변환하는 일련의 과정과 이를 통해 결과물을 만들어내는 작업을 의미합니다. 즉, 빌드 과정 중 일부가 컴파일이며, 빌드는 컴파일 외의 다른 단계들도 포함하는 좀 더 포괄적인 개념이라고 할 수 있습니다. 대표적인 예시가 '링크(link)' 단계입니다. A라는 소스 파일에서 B라는 파일에 존재하는 기능을 호출한다고 했을 때, 단순히 컴파일만 한다면 A는 B에 존재하는 해당 기능을 찾을 수 없게 됩니다. 따라서, 이를 연결해주는 작업이 필요하며 이것이 바로 링크를 의미합니다. 즉, 컴파일만 한다고 끝나는 것이 아니라 프로그램을 실행가능하도록 하기 위해서는 이들을 서로 이어주는 과정 또한 필수적으로 행해져야 하는 것입니다.
빌드 도구
빌드 도구(Build Tool)란 앞에서 언급한 다양한 단계로 구성된 빌드 작업을 자동화하는데 도움을 주는 도구들을 의미합니다. 프로젝트의 규모가 커질수록 담고 있는 소스 코드의 양 또한 방대해지기 때문에 모든 파일을 일일이 추적해서 수동으로 호출해서 컴파일 한다는 것은 거의 불가능에 가깝습니다. 우여곡절 끝에 빌드를 마친다하더라도, 사람이 작업한 만큼 실수가 있을 수 있어 제대로 실행된다는 보장을 할 수가 없습니다. 그래서 시간은 오래 걸리면서도 생산성은 굉장히 낮은 작업이 되어 버리는 것입니다. 빌드 도구를 사용하면 이 모든 과정을 자동화 해주고 잘못된 부분이 있다면 이를 찾아서 알려줄 수 있어 빠르고 정확한 작업이 가능해집니다. 이외에도 프로젝트에 포함된 여러 라이브러리 또한 빌드 도구가 자동으로 관리해주기 때문에, 어떤 라이브러리가 필요해지면 그때마다 하나씩 추가해야하는 수고를 덜어주기도 하며, 연관된 라이브러리를 잘못 관리하게 될 위험을 줄여주기도 합니다.
빌드 도구의 종류와 특징
1) make, makefile (빌드 도구의 시초?)
make는 소프트웨어 개발을 위해 유닉스 계열 운영체제 사용되는 프로그램 빌드도구인데요. 여러 파일들끼리의 의존성을 설정하고 이때 각 파일에 필요한 명령을 정의함으로써 프로그램을 컴파일 할 수 있으며, 최종 프로그램을 만드는 과정 또한 서술할 수 있는 표준적인 문법을 가지고 있습니다. 이러한 구조로 기술된 파일은 주로 makefile이라는 파일명으로 작성되며, 해당 파일을 make가 해석해서 프로그램 빌드를 수행하게 됩니다. 빌드 자동화를 실현했음에도 make는 자바 실행환경에는 완벽하게 들어맞지 않았기 때문에 이를 대체할 도구들이 등장하기 시작합니다.
2) Apache Ant
가장 먼저 언급할 빌드 도구는 Ant(Another Net Tool)입니다. 위에서 언급한 make와 비슷하지만 자바 언어로 구현되어 있기 때문에 자바 프로젝트 빌드에 적합합니다. 이밖에도 몇 가지 뚜렷한 특징이 있는데, 요약해보면 다음과 같습니다.
- 빌드를 위한 환경구성으로 XML 파일을 사용한다.
- 특정할만한 컨벤션이 정해져 있지 않다.
Ant의 설정 내용을 담고 있는 파일은 build.xml로 XML 기반의 빌드 스크립트를 사용합니다. XML을 사용하기는 하지만 똑같이 설정파일로 XML을 사용하는 Maven과 다르게 정해진 컨벤션이 없기 때문에 더 유연하다고 할 수 있습니다. 그러나 유연성이 높다는 부분이 단점으로도 작용할 수 있는데, 정해진 틀이 없기 때문에 개발자가 모든 것을 구상해야 한다는 점, 그리고 프로젝트가 복잡해질 수록 Build 과정을 이해하기 힘들고 때문에 특히 다른 개발자들이 해당 파일을 유지보수하려면 빌드 스크립트를 이해하기 위해서 추가적인 노력이 들게된다는 점입니다.
마지막으로는 라이브러리 간의 의존관리가 이루어지지 않는다는 점이며 이는 뒤이어 언급할 빌드 도구들과 비교해서 가장 큰 단점으로 작용할 수 있습니다. 의존성 관리가 자동으로 이루어지지 않는 만큼 이를 개발자가 일일이 정의해줘야 하며, 이는 번거롭기도 하고, 잘못된 의존성 추가로 인해 프로그램에 쉽게 문제를 일으킬 수가 있기 때문입니다. 이같은 단점을 극복하기 위해 Sub 프로젝트로 Apache Ivy가 등장하긴 했지만 기존 Ant가 갖고 있는 단점 때문에 그 한계가 명확하다고 하며, 이러한 이유에서인지 요즘은 Ant를 사용하는 프로젝트를 거의 찾아보기 힘든 것 같습니다.
Ant build.xml 예시
<project>
<target name="clean">
<delete dir="classes" />
</target>
<target name="compile" depends="clean">
<mkdir dir="classes" />
<javac srcdir="src" destdir="classes" />
</target>
<target name="jar" depends="compile">
<mkdir dir="jar" />
<jar destfile="jar/HelloWorld.jar" basedir="classes">
<manifest>
<attribute name="Main-Class"
value="antExample.HelloWorld" />
</manifest>
</jar>
</target>
<target name="run" depends="jar">
<java jar="jar/HelloWorld.jar" fork="true" />
</target>
</project>
3) Apache Maven
다음은 메이븐(Maven)에 대해 살펴보도록 하겠습니다. 위에서 언급한 Ant의 단점을 극복할 대안으로 만들어져서인지 그 특징을 살펴보면 Ant의 단점에서 언급되었던 부분을 보완할만한 내용이 다소 등장합니다.
- Ant와 마찬가지로 빌드 환경 구성을 위해 XML 파일을 사용합니다.
- 엄격(Strict)한 컨벤션에 따라 파일 작성이 이루어지며, 미리 규정된 목표(goals)들을 제공합니다.
- 정해진 라이프 사이클에 의하여 작업을 수행하고, 전반적인 프로젝트 관리 기능을 가지고 있습니다.
Ant가 환경 설정을 위해 build.xml을 사용했던 것처럼 Maven도 XML 파일을 사용하는데요. 다만 이름이 pom.xml로 차이가 있습니다. 그 내부를 살펴보면 정해진 컨벤션에 맞게 파일이 작성되었다는 것을 금방 알아차릴 수 있을만큼 잘 정형화되어 있음을 발견할 수 있습니다. 때문에, 개발자들은 정해진 틀 속에서 어떻게 해야할지 보다 무엇을 해야할지에 더 집중할 수 있게 됩니다. 이 밖에도 메이븐은 Ant에 비해 여러 장점이 있지만 그 중에서도 가장 큰 장점은 라이브러리의 의존성 관리를 자동으로 해준다는 부분입니다. 특히 침투적인(transitive) 방식의 의존성 관리를 사용하기 때문에 어떤 라이브러리와 그 라이브러리가 의존하는 라이브러리까지 타고 올라가는 형태를 통해 필요한 라이브러리를 모두 자동으로 다운로드해줍니다. 때문에 central repository인 https://mvnrepository.com/ 에서 필요한 의존성만을 골라 손쉽게 추가가 가능합니다.
하지만 메이븐 또한 여러 단점이 존재하는데요. 특히 꽤나 엄격한 컨벤션을 가지고 있다는 점이 장점이자 큰 단점으로 작용하게 됩니다. 먼저, 설정내용이 길어지고 이로 인한 가독성 저하가 발생할 수 있다는 점입니다. 특히 상속구조를 활용해서 필요한 모듈들을 공유하고 있어 처음에 봤을 때, 그 구조가 확 눈에 들어오지 않을 수 있습니다. 또한, 각 프로젝트는 자신의 상황에 맞게 매번 다른 구성을 갖어서 빌드라는 작업은 동적인 요소라고 볼 수 있는데요. 하지만 메이븐은 엄격한 컨벤션을 적용하여 매우 정적인 관리를 하고 있다는 점입니다. 즉, 다양한 규칙이 적용되어야 하는 환경에 천편일률적인 방식을 적용하려다보니 프로젝트에 맞게 커스터마이징을 하는 부분이 불가능하지는 않지만 그 난이도가 올라갈 수밖에 없다는 점도 하나의 단점이 될 수 있겠습니다.
예시 코드
4) Gradle
마지막으로 살펴볼 빌드 도구는 Gradle 입니다. (그래들, 그레이들 등 한글로는 그 호칭이 명확하지 않아서 그냥 원 이름을 사용했습니다.) Gradle의 특징은 다음과 같이 정리할 수 있습니다.
- JVM 기반의 빌드도구로 Groovy 혹은 Kotlin 기반의 DSL로 빌드 관리 스크립트를 작성할 수 있습니다.
- 상속 대신 설정 주입(Configuraiton Injection) 방식을 사용해서 공통 모듈을 관리합니다.
- 빌드속도가 매우 빠릅니다.
- 메이븐처럼 침투적인(transitive) 의존성 관리 기능을 제공하며, 중앙 저장소에서 손쉽게 필요한 의존성을 다운로드할 수 있습니다.
위의 두 빌드 도구들과 다르게 Gradle은 XML이 아닌 Groovy 혹은 Kotlin 기반의 DSL 스크립트를 사용합니다. 따라서 더 간결하면서도 유연한 구성을 할 수 있습니다. 즉, 빌드라는 동적인 작업에 맞게 프로젝트에 적합한 커스터마이징이 가능하며 쉬운 확장이 가능하다는 것이 큰 장점입니다. 이러한 장점은 프로젝트의 규모가 더 커질수록 두각된다고 합니다.
다음으로는 주입 방식으로 설정을 관리하기 때문에 공통 모듈을 상속해서 발생하는 단점을 커버하면서도, 주입 시 프로젝트의 조건을 체크할 수 있어 프로젝트별로 주입되는 설정을 다르게 가져갈 수 있다는 점입니다. 마지막으로는 메이븐에 비해 빠른 빌드 속도를 자랑한다는 점입니다. 이는 Gradle이 작업의 입력/출력을 추적하여 최대한 변경된 사항만을 실행하기 때문이라고 합니다. Gradle의 공식 홈페이지를 보면 메이븐과 비교한 벤치마크가 있으며, 빌드 속도가 모든 시나리오에서 적어도 2배 이상 빠르며, 많게는 100배 까지도 차이가 남을 확인할 수 있었습니다.
(자세한 비교 결과는 https://gradle.org/maven-vs-gradle/ 해당 링크를 참고해주세요.)
Gradle의 단점에 대해서는 구글링을 해봐도 자료가 거의 없어서 많이 찾지는 못했지만 다음을 이야기 할 수 있을 것 같습니다. 먼저, 가파른 학습곡선(steep learning curve)을 가질 수 있다는 점입니다. 특히, 메이븐에 익숙한 경우 이 부분이 더욱 크게 체감이 될 듯 한데요. 이전과는 아예 다른 방식을 사용하기 때문에 새롭게 학습이 필요해 팀 전체가 메이븐에 익숙하다면 Gradle 도입 결정이 쉽지 않을 듯 합니다. 또한, Groovy와 Kotlin이 아무리 자바와 비슷하다고 하더라도 결국 이를 사용하는 법을 새롭게 배워야합니다. 이는 익숙하지 않음에서 나오는 예상치 못한 다양한 문제상황으로 까지 이어질 수가 있기 때문에 이러한 부분에 대한 비용도 사전에 고려할 필요가 있을 듯 합니다. 실제로 구글링을 해보니 Gradle이 좋다고 해서 메이븐에서 넘어왔다가 다시 메이븐으로 회귀했다는 댓글들이 생각보다 많았습니다.
새로운 프로젝트에서는...
이번에 진행할 새 프로젝트는 메이븐 대신 Gradle을 활용할 예정입니다. 그간 메이븐을 활용했기 때문에 새로운 것을 배우는 학습 비용이 뒤따르긴 하겠지만 그만큼의 성능상 이점과 간결함이 뒤따르기 때문에 배울 가치가 있다고 생각하였습니다. 특히 빠른 빌드 속도는 차후에 적용할 CI & CD에 큰 도움이 될 것이라 생각했고, 이번 프로젝트에 자바 대신 활용할 언어인 코틀린으로도 Gradle 스크립트를 작성할 수가 있다고 하니 learning curve가 약간은 줄어들지 않을까 기대도 해봅니다.
참고자료
https://medium.com/javarevisited/5-best-gradle-courses-and-books-to-learn-in-2021-93f49ce8ff8e
프로젝트 링크
https://github.com/f-lab-edu/Hello-World
f-lab-edu/Hello-World
언어교환 상대찾기 서비스. Contribute to f-lab-edu/Hello-World development by creating an account on GitHub.
github.com
https://github.com/f-lab-edu/food-is-coming
f-lab-edu/food-is-coming
'고객-라이더-가게'를 이어주는 가교 역할을 통해 편리한 배달서비스를 제공합니다. Contribute to f-lab-edu/food-is-coming development by creating an account on GitHub.
github.com