개발바닥 오픈채팅방에서 호돌님이 인프런에서 질문자의 문제를 해결하는 과정에 있어서 Build Tools를 Gradle로 설정해야만 오류가 발생하지 않고 Intellij로 설정하면 오류가 발생한다는 원인을 발견하였다.
평상시에도 빌드의 속도를 높이기 위해서 Intellij IDEA를 사용한다던가 혹은 TEST 코드에서 @Slf4j가 제대로 동작하지 않을 때, Intellij IDEA로 변경하면 해결이 된다는 해결책들도 더러 있었지만 도대체 둘의 차이가 무엇인지 궁금해하다가 이젠 더이상 참을 수가 없었다.
둘의 차이가 무엇인지 알아봤다.
Intellij IDEA build를 사용하다가 발생한 에러에 대해서 정리해놓은 포스팅을 찾아 볼 수 있었다.
해당 포스팅의 오류 상황은 다음과 같다.
- 기존의 프로젝트에서 Deprecated 처리 된 객체들을 정리했다.
- 프로젝트를 실행하니 Deprecated 된 객체를 찾을 수 없다는 에러가 발생했다.
그리고 다음과 같은 시행착오를 통해 해결한 모습을 볼 수 있었다.
- 프로젝트 파일 어딘가에 존재한다는 것을 에러 메시지를 통해 파악
- 빌드 된 결과물이 있는 out 폴더에 전에 지웠던 파일이 그대로 남아있음을 확인
- out 폴더를 삭제하고 다시 빌드하니 정상 동작
그리고 다음과 같은 테스트를 진행하셨다.
- 빌드 방식을 Gradle로 변경 -> out 폴더가 삭제 됨, 기존의 out 폴더를 지우지 않은 상황에서 빌드 하더라도 정상 동작
이제 근본부터 차례대로 찾아가보자.
빌드(build)
먼저 우리가 많이 들어왔지만 잘 간과하는 빌드에 대해서 먼저 알아보자.
빌드란, 컴파일(Compile)과 링크(Link)를 합쳐서 부르는 용어라고 한다.
그럼 우리는 이어서 컴파일과 링크가 무엇인지 이해 할 필요가 있다.
컴파일(Compile)
컴파일이란 작성한 소스 코드를 컴퓨터가 이해할 수 있는 기계어로 변환하는 작업이다. 다만, 자바를 사용하고 있다면 자바 컴파일러가 자바 가상 머신인 JVM이 이해할 수 있도록 바이트 코드로 변환하는 과정을 말한다.
이어서 실제 실행 할 때에는 Execution Engine에 의해서 인터프리터 혹은 JIT 컴파일러에 의해서 바이트 코드들이 실행되는 형식이다.
자세한 내용은 JVM 에서 확인이 가능하다.
링크(Link)
이어서 링크는 무엇인지 살펴보자.
obj 파일들을 연결해서 하나의 exe 파일을 만드는 작업을 링킹이라고 하고, 이 동작을 수행하는 프로그램을 링커라고 한다고 한다.
그리고 자바에서는 이 부분이 클래스 로더에서 이루어진다. 이 부분도 위의 링크를 통해서 확인이 가능하다.
그래서 빌드란 무엇인가
우리는 위에서 컴파일과 링크에 대해서 이해를 했다. 결국 컴퓨터가 이해할 수 있는 기계어로 변환하고, 그 과정에서 여러가지 코드들을 합쳐서 프로그램을 만드는 과정이라는 것이다. 그럼 이어서 처음에 들었던 의문인 Gradle Build와 Intellij IDEA Build의 차이는 무엇인지 살펴보자.
Gradle Build vs Intellij IDEA Build
둘 다 동일한 빌드 도구이지만, 빌드 하는 방식에 차이가 있어서 위와 같은 문제가 발생했음을 추측할 수 있다.
먼저 Gradle은 오픈 소스 빌드 자동화 도구이고, Intellij IDEA는 인텔리제이 자체에서 제공하는 빌드 자동화 도구라고 한다.
이전에 Maven 빌드 도구도 있었는데, Maven의 기존 구조를 따르고 성능을 개선한 빌드 도구가 Gradle이다.
Gradle의 빌드 방식과 Intellij IDEA 빌드 방식의 큰 차이는 증분 빌드(incremental build) 라고 한다. 그럼 증분 빌드가 무엇인지 알아보자.
증분 빌드(incremental build)란?
증분 빌드는 용어 그대로, 변경된 부분만 빌드를 하는 방식을 말한다. 즉, 변경되지 않은 것에 대해서는 건너뛰고 빌드를 진행한다는 것인데, 이를 이용하면 분명히 빌드가 빠르게 될 것이다. 즉, Intellij IDEA 빌드 방식이 gradle 보다 빌드가 빠른 것으로 보아 증분 빌드를 택하고 있다는 것을 알 수 있다.
하지만, 여기서 큰 문제가 발생한다. 위에서 겪었던 문제인 삭제된 파일에 대해서는 컴파일을 하지 않는다는 것이다. jetbrains의 공식 문서에서 다음과 같은 내용을 확인할 수 있다.
When you change any class inside the build target and then execute the build action, IntelliJ IDEA performs the incremental build that compiles only the changed classes. IntelliJ IDEA also recursively builds the classes' dependencies.
빌드 대상 내부의 클래스를 변경한 다음 빌드 작업을 실행하면 IntelliJ IDEA는 변경된 클래스만 컴파일하는 증분 빌드를 수행합니다.
여기서 삭제 된 클래스는 변경 되었다기 보다는 그냥 삭제되서 빌드 대상에 속하지 않기 때문에 out 폴더에 계속 포함되어 있던 것이다.
gradle 또한 확인해봤는데 증분 빌드를 지원한다고 한다..! 어떻게 해결한 것인지 Gradle 의 공식문서에서 찾아 볼 수 있었다. 증분 빌드의 문제를 속성 파일을 통해 해결하였다고 한 부분이다.
The standard Java API for writing properties files produces a unique file every time, even when the same properties and values are used, because it includes a timestamp in the comments. Gradle’s WriteProperties task generates exactly the same output byte-for-byte if none of the properties have changed. This is achieved by a few tweaks to how a properties file is generated:
속성 파일 작성을 위한 표준 Java API는 주석에 타임스탬프를 포함하기 때문에 동일한 속성 및 값이 사용되는 경우에도 매번 고유한 파일을 생성합니다. 속성이 변경되지 않은 경우 Gradle의 WriteProperties 태스크는 바이트 단위로 정확히 동일한 출력을 생성합니다. 이것은 속성 파일이 생성되는 방법에 대한 몇 가지 조정으로 달성됩니다.
위와 같은 방식 덕분에, IntelliJ IDEA build와 같이 증분 빌드를 사용함에도 삭제 된 파일에 대해서도 정확하게 빌드하여 삭제 된 것을 확인 할 수 있었던 것이다. 참고로, 위에서 저자분께서 out 폴더를 삭제하지 않고 테스트를 진행했다고 하였는데, 이 과정에서 무심코 넘어갔지만 Gradle build는 out 폴더에 생성되는 것이 아닌 build 폴더에 생성된다는 것 또한 알 수 있었다!
결론
Gradle이 위와 같은 문제를 해결해주지만 그래도 Intellij IDEA 도 속도가 빠르다는 장점이 분명히 존재한다. 따라서 우리는 둘의 차이를 명확히하고 다음과 같이 행동하는게 좋다고 생각한다.
정확하게 빌드를 해야하고 실제로 실행하거나, 프로젝트 크기가 크다면 Gradle 빌드 방식을 선택
테스트 혹은 프로젝트 크기가 작거나, 위와 같은 문제를 인지하고 있어 ReBuild를 해도 된다면 Intellij 빌드 방식을 선택하는 것이 좋을 것 같다는 생각이 든다.
참고 자료
https://pamyferret.tistory.com/62
https://datalibrary.tistory.com/23
https://velog.io/@woongi9/JPQL%EA%B3%BC-Param-%EC%96%B4%EB%85%B8%ED%85%8C%EC%9D%B4%EC%85%98-%EA%B7%B8%EB%A6%AC%EA%B3%A0-Gradle%EA%B3%BC-IntelliJ-%EB%B9%8C%EB%93%9C-%EB%B0%A9%EC%8B%9D
https://www.jetbrains.com/help/idea/compiling-applications.html#compile_module
https://docs.gradle.org/current/userguide/building_java_projects.html
'Language' 카테고리의 다른 글
[UML] 클래스 다이어그램 (2) | 2023.05.20 |
---|---|
Lombok ToString 순환참조 방지하기 (1) | 2023.05.12 |
전략 패턴 (0) | 2023.04.16 |
템플릿 메서드 패턴 (2) | 2023.04.15 |