w ,

FajneFajne Dobre!Dobre! ŚwietnieŚwietnie WnerwWnerw

Maven i Gradle – porównanie narzędzi i ich wydajności

maven i gradle

Maven i Gradle to najpopularniejsze narzędzia automatyzujące proces tworzenia aplikacji napisanych w Java. Kwestią pełną sporów jest próba wskazania lepszego rozwiązania. Dlatego w tym materiale przedstawiam Ci na chłodno porównanie obu tych rozwiązań i obiektywne badanie ich wydajności przy tożsamych operacjach. Jednak w pierwszej kolejności zaczniemy od przybliżenia czemu te systemu dokładnie one służą.

System budowania

Zarówno Maven i Gradle są narzędziami klasyfikowanymi jako build automation, czyli odpowiadają za proces konwertujący kod źródłowy do postaci użytkowej lub wykonywalnej. Zasadniczo automatyzacja budowania polega na pisaniu skryptów lub automatyzacji różnorodnych zadań wykonywanych przez programistów w ich codziennych działaniach, takich jak:

  • pobieranie zależności,
  • kompilowanie kodu źródłowego na kod binarny,
  • pakowanie kodu binarnego,
  • uruchamianie testów,
  • wdrożenie do systemów produkcyjnych.

Budowanie jest zautomatyzowane wtedy, gdy powyższe kroki można powtarzać bez wymogu interwencji ze strony człowieka i mogą być one wykonane bez informacji spoza repozytorium kodu źródłowego. Obecnie wyróżnić można dwie kategorie narzędzi do automatyzacji budowania oprogramowania (z ang. build automation):

  • Narzędzia automatyzujące budowę – obejmuje to oprogramowanie takie m.in. Ant, Maven lub Gradle itp. Głównym celem ww. narzędzi jest generowanie artefaktów poprzez działania takie jak kompilacja i łączenie kodu źródłowego.
  • Serwery automatyzujące budowę – są to narzędzia webowe, które wykonują proces zautomatyzowanego budowania na żądanie bądź też zgodnie z harmonogramem. Przykładem serwera automatyzującego proces budowy jest serwer Continuous Integration np. Jenkins.

Maven

Maven – narzędzie do automatyzacji kompilacji używane m. in. w projektach Java. Projekt Maven jest prowadzony przez Apache Software Foundation, gdzie wcześniej był częścią projektu Jakarta.

Maven zajmuje się dwoma aspektami tworzenia oprogramowania – sposobem, w jaki oprogramowanie jest tworzone oraz jego zależnościami. W przeciwieństwie do swojego historycznego poprzednika – Apache Ant, to używa on konwencji do budowania oprogramowania. Plik XML opisuje budowany projekt aplikacji, zawiera on:

  • zależności do innych zewnętrznych modułów i komponentów,
  • kolejność budowy,
  • katalogi i wymagane wtyczki,
  • zdefiniowane cele do wykonania zdefiniowanych zadań, takich jak kompilacja kodu i jego pakowanie (packaging).

Maven dynamicznie pobiera biblioteki Java i wtyczki z jednego lub więcej repozytoriów (np. Maven Central Repository) i przechowuje je w lokalnej pamięci podręcznej (tzw. katalog m2). Poniżej przykład pliku XML, opisującego projekt aplikacji:

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>
    <parent>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-parent</artifactId>
        <version>2.3.0.RELEASE</version>
    </parent>
    <groupId>pl.bykowski</groupId>
    <artifactId>springboot-buildpacks</artifactId>
    <version>0.0.1-SNAPSHOT</version>
    <name>example-maven</name>
    <description>Demo project for Spring Boot</description>

    <properties>
        <java.version>1.8</java.version>
    </properties>

    <dependencies>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>
    </dependencies>
    <build>
        <plugins>
            <plugin>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-maven-plugin</artifactId>
            </plugin>
        </plugins>
    </build>
</project>

Przede wszystkim zawiera on informacje o projekcie, wersji Java, zależności do zewnętrznych narzędzi w sekcji dependencies oraz informacji na temat budowy projektu w ranach znacznika build.

Gradle

Gradle – to system open source, który automatyzuje kompilację oprogramowania. Jest oparty na koncepcjach Apache Ant i Apache Maven. Ponadto wykorzystuje on język dziedzinowy (domain-specific language DSL – język przystosowany do rozwiązywania określonej dziedziny problemów ) oparty na Groovy.

Zamiast formy XML używanej przez Apache Maven do deklarowania konfiguracji projektu używa dedykowanego pliku .gradle:

plugins {
  id 'org.springframework.boot' version '2.3.0.RELEASE'
  id 'io.spring.dependency-management' version '1.0.9.RELEASE'
  id 'java'
}
group = 'pl.bykowski'
version = '0.0.1-SNAPSHOT'
sourceCompatibility = '1.8'
repositories {
  mavenCentral()
}
dependencies {
  implementation 'org.springframework.boot:spring-boot-starter-web'
  testImplementation('org.springframework.boot:spring-boot-starter-test') {
    exclude group: 'org.junit.vintage', module: 'junit-vintage-engine'
  }
}
test {
  useJUnitPlatform()
}

Witać tu analogie, gdzie również wskazujemy na wersje Java, informacje na temat zależności. Warto pamiętać, że Gradle w większości przypadów pobiera informacje na temat zależności z repozytorium Maven co widać przy repositories.

Aby uniknąć niejasności – Maven i Maven Repository to zupełnie dwa oddzielne byty. Pierwszy z nich to system budowy, natomiast drugi to globalne repozytorium (magazyn) gdzie składowane są artefakty (zależności), które później możemy uwzględnić w projekcie.

Porównanie Maven z Gradle

Istnieją pewne fundamentalne różnice w sposobie podejścia do budowania przez oba systemy:

  • Gradle opiera się na wykresie zależności od zadań, gdzie zadania to byty wykonujące pracę;
  • Maven natomiast opiera się na stałym i liniowym modelu faz – w Maven cele są powiązane z fazami projektu, a cele pełnią podobną funkcję jak zadania Gradle’a, czyli to one wykonują pracę.

Pod względem wydajności oba systemy umożliwiają równoległą pracę wielomodułowych konstrukcji. W przypadku Gradle, pozwala on na stopniowe budowanie, gdyż dzięki regularnym sprawdzeniom wie on, które taski są aktualizowane, a które nie. Jeśli zadanie jest zaktualizowane to jest ono pomijane, czego skutkiem jest krótszy czas budowania. Inne cechy wyróżniające wydajność, które można znaleźć w Gradle, to między innymi:

  • użycie API dla przyrostowych podzadań,
  • kompilacje inkrementalne dla klas Java,
  • unikanie kompilacji dla Javy,
  • daemon, który utrzymuje gotowy proces w tle i sprawia, że kompilowanie i budowa grafu zadań do wykonania jest o wiele szybsza.

Jeśli chodzi o zarządzanie zależnościami, zarówno Gradle, jak i Maven mogą nimi zarządzać dynamicznie i przejściowo, korzystać z buforów zależności i czytać metadane w formacie POM.

W obu przypadkach można również deklarować wersje wykorzystywanych zależności. Podobnie Gradle oraz Maven pobierają współzależności przechodnie z ich repozytoriów artefaktów. Domyślnie Maven korzysta z Maven Central, natomiast Gradle z JCenter, ale można również zdefiniować dowolne repozytorium. Jeśli istnieje kilka wymaganych zależności, to Maven może pobrać je równolegle, podobnie jak Gradle.

Ponadto w temacie wykonania, to Maven jak i Gradle korzystają z grup zadań i opisów. Dlatego oba te systemy umożliwiają budowanie tylko określonego projektu i jego zależności. W Gradle możemy wykorzystać w pełni konfigurowalny DAG (directed acyclic graph), podczas gdy cel Maven’a może być dołączony tylko do jednego innego celu – wiele celów ma postać uporządkowanej listy. Gradle pozwala również na porządkowanie i finalizowanie zadań, wykluczanie zadań, wykluczanie przesunięć i interferencje w zależność zadań.

Wydajność Maven i Gradle w Windows i Linux

Do porównania działania Maven jak i Gradle wykorzystamy projekt napisany w Spring Boot, który udostępnia proste REST API. Potem został on uruchomiony na dwóch systemach:

  • Linux Mint 19.3 Tricia
  • Windows 10 Pro, wersja 1809

Oba systemy zostały uruchomione natywnie na tym samym urządzeniu (Lenovo Thinkpad X230 w konfiguracji Intel Core i5-3320M, 8GB RAM) w celu uzyskania jak najbardziej miarodajnych wyników. Przede wszystkim Jakubowi Kowalskiemu dziękuje za przygotowanie sprzętu i sporządzenie wyników.

Czas budowy aplikacji w zależności od OS wynosił:

Czas czyszczenia aplikacji w zależności od OS wynosił:

Finalnie rezultat w zależności od iteracji i OS wykonywał się:

Wnioski

Podsumowując testy można zauważyć, że pierwszy proces budowania projektu był znacząco dłuższy przy użyciu Gradle – niezależnie od wykorzystanego systemu. Z każdym kolejnym uruchomieniem procesu jednak zyskiwał on na czasie, przeganiając Maven w środowisku Linux.

Niestety nie udało się jednak osiągnąć tego na Windowsie, co można tłumaczyć wieloma czynnikami takimi jak narzut systemu czy też procesy uruchomione w tle przez system. Należy również zwrócić uwagę na różnice w wersjach systemów budowy dla wymienionych systemów operacyjnych, co wydaje się najbardziej prawdopodobną przyczyną takich różnic.

W przypadku czyszczenia projektu Gradle zdecydowanie wygrywa niezależnie od systemu, na którym czynność została wykonana. Potem widoczne są różnice w wykonaniu między systemami – na systemie Windows dalej otrzymujemy wartości o wiele większe niż na Linuxie.

Na koniec dodam tabelę zestawiającą porównanie, które wzbogaciłem również o system budowy Ant:

AntMavenGradle
ImperatywnyDeklaratywnyDeklaratywny i imperatywny
Brak ustandaryzowaniaOkreślony standardOkreślony standard
Posiada centralne repozytoriumPosiada centralne repozytorium
Bazuje na XMLBazuje na XMLBazuje na Gradle DSL
Możliwa integracja z IDEŚwietna integracja z IDEŚwietna integracja z IDE

Źródła:
https://maven.apache.org/
https://gradle.org/
https://stackify.com/gradle-vs-maven/
https://www.jrebel.com/blog/java-build-tools-comparison

Który system budowy preferujesz?

Napisane przez Przemysław Bykowski

Aktywny programista i energiczny trener. Specjalizuje się w Spring Boot i uczę go w ramach AkademiaSpring.pl. Po godzinach udzielam się na YouTubach. Więcej o mnie.

Dodaj komentarz

Ładowanie…

Docker i Spring Boot z wykorzystaniem Buildpacks

Nowe podejście do budowy obrazów Dockera w Spring Boot 2.3

debugowanie - wyszukiwanie błędów w kodzie

Debugowanie – sprytne sposoby na odnajdowanie błędów w kodzie