Gradle הוא כלי Build מודרני, מלא פיצ’רים ואופטימיזציות – שנמצא דור או שניים לפנים מהחלופה העיקרית שלו: Maven. גריידל יודע לבצע Caching ו Incremental Build ברמות הפשטה שונות – ומסוגל לשפר מאוד את זמני ה Build של פרויקטים גדולים.
לגריידל אין מערכת Repositories משלה, והיא משתמשת בזו של מייבן, של ivy, או פשוט בתיקיה של מערכת הקבצים המקומית. זה יתרון גדול, מכיוון שכך אין תחרות בין “Maven Repositories” ל “Gradle Repositories”.
מה גריידל יכולה להציע מול מייבן?
![]() |
הבדלי ביצועים בין מייבן, גריידל, ובאזל. מקור: האתר של גריידל. |
הדבר הראשון, וכנראה החשוב ביותר הוא ביצועים:
- בהרצה ראשונה, גריידל ומייבן יהיו דיי דומים. אולי גריידל תרוץ טיפה יותר מהר.
- בהרצה השנייה והלאה, ייכנסו לשימוש מנגנונים ייחודיים ל Gradle:
- Incremental Build – גריידל עוקבת אחר מערכת הקבצים ומקמפלת רק קבצים שהשתנו, או קבצים שתלויים בהם.
- Config Cache ו Build Cache – שימוש חוזר בתוצרים (ברמות שונות) מהפעולות בילד קודמות.
- תאורטית גם מייבן עושה זאת – אך בצורה משמעותית פחות יעילה.
- Gradle Daemon – גרדייל מחזיקה תהליך (process) של מערכת ההפעלה שממשיך לחיות ברקע, להחזיק caches מיידיים בזכרון ולהנות מאופטימיזציות של Java JIT compilation.
- למייבן יש מחזור-חיים קבוע וקשיח, validate > compile > test > package > install, שלא ניתן לסטות ממנו, אלא ב”תרגילים”. בגרדייל יש עץ של Tasks (כמו Compile או Test) שניתן לקנפג וקל הרבה יותר להתאים את שלבי הריצה לצרכים שלכם.
- למשל: בכדי לדלג על שלב הבדיקות או הקומפילציה ב Maven יש לעשות “תרגילים” שלא תמיד מצליחים. בגרדייל דילוג על שלבים זו אופציה מובנית.
- קל להגדיר Custom Tasks בגריידל – וזו גמישות רבת-עוצמה. המקבילה במייבן היא למצוא Plugin שמתאים בדיוק לצרכים, או לכתוב Plugin בעצמכם – שזה הרבה יותר מסובך
- גריידל מספקת ניהול תלויות עשיר וחכם הרבה יותר ממייבן – מה שמשמעותי בפרויקטים גדולים ו/או מורכבים.
- למשל: במייבן תלות במודול יגרור קבלת כל התלויות של אותה ספריה (propograted dependencies, שלעתים נקרא בטעות transitive dependencies). הדבר לא מאפשר לעקוב ולנהל במדויק תלויות של מודולים.
בגריידל אפשר לבחור או בגישה זהה למייבן, או בגישה מדויקת ונשלטת יותר.
- למשל: במייבן תלות במודול יגרור קבלת כל התלויות של אותה ספריה (propograted dependencies, שלעתים נקרא בטעות transitive dependencies). הדבר לא מאפשר לעקוב ולנהל במדויק תלויות של מודולים.
- גריידל מממשת את העיקרון של Conventions over Configuration, ואין צורך באמת להשתמש בכל הכלים המתקדמים יותר שלה. קושי נפוץ של newcomers הוא להבחין אלו מנגנונים הם פשוטים ו straightforward, ואלו מנגנונים הם רבי-עוצמה, אך דורשים גם הבנה מעמיקה יותר.
-
גריידל זוכה לתמיכה טובה יותר, ועדכונים תכופים יותר. למשל: כבר שנה וחצי כשיש בעיה בהרצה של JUnit 5 ב Failsafe של מייבן בצורה מקבילית – אך בגריידל הכל עובד כשורה מהגרסה הראשונה של Junit 5.
-
לגריידל יש כלים תומכים משמעותיים וטובים יותר:
- Build Scan עוזר לנתח ולהבין בדיוק מה קרה ב Build. האם הגדרה מסוימת שרצינו אכן פעלה? לא צריך לנחש מתוך הלוגים – אפשר לבדוק בצורה ישירה.
- גריידל מספקת Build Scan רזה יותר גם למייבן – בעיקר בכדי לתמוך במעבר ולוודא שה Build בגריידל מכסה את כל מה שקרה במייבן.
- Continuous Build – גרדייל יכול להאזין למערכת הקבצים ולקמפל את הקוד תוך כדי שאתם עובדים.
- Gradle Profiler – שעוזר למצוא bottlenecks בבילד ולשפר אותם. ניתן לגשת לתוצאות שלו בתוך ה Build Scan.
- Gradle Build Debugger – בגלל שה build Script הוא שפת תכנות – אפשר ממש לדבג את תהליך הבילד כדי לנתח תקלות קשות-להבנה.
- Gradle Enterprise – הם סט של יכולות נוספות שחברת Gradle מספקת בתשלום – כמו Central build Cache (שימוש משותף בתוצרים: מפתח אחד קימפל מודול, כל השאר יכולים להשתמש בתוצר), או כלי Diagnostic ו Analytics משופרים לבילד ולהרצת הבדיקות.
- Build Scan עוזר לנתח ולהבין בדיוק מה קרה ב Build. האם הגדרה מסוימת שרצינו אכן פעלה? לא צריך לנחש מתוך הלוגים – אפשר לבדוק בצורה ישירה.
- נטפליקס, היא תורמת גדולה של Gradle Plugins. רבים מהם היו הבסיס לפיצ’רים שהיום הם סטנדרטיים בגריידל.
- Gradle Wrapper (שמירת תאימות מדויקת של גרסת גריידל בין מפתחים) הוא כלי פופולארי בגריידל, אך שווה לציין שהוא קיים גם במייבן (אם כי שם הוא פחות נפוץ בשימוש).
- Bazel ו Gradle דומות זו לזו, יותר משהן דומות ל Maven או Ant.
- גריידל מספקת גמישות רבה יותר, באזל היא יותר מובנה.
- באזל בנויה יותר מסביב לניהול מרכזי (למשל: ניהול גרסאות של תלויות) בעוד גריידל לא לוקחת הנחות כאלו, ותומכת טוב יותר במציאות מבוזרת של שליטה.
- לגרדייל יש קהילה גדולה יותר, ובגרות גדולה יותר – במיוחד בעולם ה JVM. סיכוי טוב שקהילות כמו Go ו ++C יזכו לתמיכה טובה יותר בבאזל.
- היכולת להשתמש ב Cache מרכזי ומשותף היא יכולת ליבה של Bazel (שעליה מתבססים במידה הביצועים הטובים של הספריה) בעוד ב Gradle זו יכולת פרמיום בתשלום (Gradle Enterprise).
- בסה”כ באופן דיי עקבי (מסקירת מאמרים ומבחנים) Gradle מהירה יותר מ Bazel – גם כאשר משתמשים ב Build Cache מרכזי.
- מבחני ביצועים לא מעטים משווים את שתי התצורות בגרסה החינמית שלהן – ואז ל Bazel יש יתרון משמעותי על יכולת שב Gradle היא בתשלום (Central Build Cache).
- הנה מאמר מ 2015 של יוצרי גריידל שמנתחים את באזל.
תכל’ס
- אנו מייבאים את הפלאגין של Java.
- בגריידל, Plugin מביא איתו שורה של Tasks ו Lifecycle Tasks (ועוד הגדרות רבות) – ובעצם קובע את השלבים השונים ב build והסדר ביניהם. במייבן ניסו לבנות תהליך אחד גנרי לכל שפות-התכנות, למרות שלשפות שונות (JavaScript, ++C) – יש צרכים שונים. בגריידל לרוב יהיה לנו בפרויקט Plugin אחד שיגדיר את ליבת התהליך ויספק גם את ה Tasks הנדרשים (Compile, Test, Jar, וכו’ – המתאימים לשפה / תהליך)
בנוסף אולי נרצה להשתמש ב Plugins נוספים כמו: למשל War, PMD, או Reports – ולהרחיב את התהליך.
- בגריידל, Plugin מביא איתו שורה של Tasks ו Lifecycle Tasks (ועוד הגדרות רבות) – ובעצם קובע את השלבים השונים ב build והסדר ביניהם. במייבן ניסו לבנות תהליך אחד גנרי לכל שפות-התכנות, למרות שלשפות שונות (JavaScript, ++C) – יש צרכים שונים. בגריידל לרוב יהיה לנו בפרויקט Plugin אחד שיגדיר את ליבת התהליך ויספק גם את ה Tasks הנדרשים (Compile, Test, Jar, וכו’ – המתאימים לשפה / תהליך)
- ה default scope שלנו ברמה הגבוהה ביותר היא אובייקט הפרויקט, וכך אנו קובעים properties מסוימים על הפרויקט.
- כאן אנו קובעים באלו Repositories לחפש את ה dependencies שלנו. כמו במייבן, אפשר ומומלץ לקבוע כמה repositories בכדי שיהיה גיבוי (לא עשינו את זה בדוגמה) – והחיפוש יעשה ע”פ הסדר בו נרשמו.
- במקום לספק את ה URL ל jCenter, אנו יכולים להשתמש בפונקציה שמסופקת ע”י גריידל ומחזירה אובייקט Repository עם ה URL הנכון (קיימים כאלו ל repositories נפוצים). פחות מקום לטעויות.
- כאן אנו נכנסים ל scope של ה Java Plugin (שהגדרנו בתחילת הקובץ) – ומוסיפים לו הגדרות.
- כברירת מחדל, גריידל תשתמש ב build בגרסת הג’אווה שמריצה אותה. זה יכול ליצור חוסר עקביות אם במחשבים שונים מריצים את הבילד בגרסאות ג’אווה שונות.
- בכדי “ליישר” את תהליך הבילד בצורה מדויקת יותר, אנו יכולים להגדיר לגריידל באזו גרסת ג’אווה להשתמש בתהליך הבילד. ה toolchain עוזר בקלות רבה לקנפג ולטפל בהגדרה של הגרסה שבחרנו. אם לא מצליחים למצוא מקומית את הגרסה המתאימה – ה toolchain יוריד לצורך ה build עותק מקומי של גרסת הגא’ווה שנבחרה.
- גם אם אתם מתכנתים בג’אווה 8 (ממגבלות מוכרות), הרצה של תהליך הבילד בגרסה מתקדמת יותר – יכולה להאיץ אותו מעט.
- כאן אנו נכנסים ל scope של ה tasks בפרויקט. אמנם אנו רוצים להתייחס ל Tasks שהגיעו מה Java Plugin, אך מרגע שהוספנו את ה Java Plugin והוא רשם את ה Tasks שלו – הם כבר לא משויכים אליו, אלא פשוט רשמים בפרויקט.
- ספציפית יש כאן כתיבה מקוצרת בשורה אחת להכנס גם ל scope של ה test plugin.
- ה Test Plugin תומך גם ב Junit וגם ב TestNG – ועלינו לציין לו במי להשתמש. הכל עטוף בפונקציות פשוטות ובטוחות לשימוש.
- בניגוד ל Maven בו יש שני Plugins: גם Surefire (לבדיקות יחידה) ו Failsafe (לבדיקות אינטגרציה) – בגריידל ה Java Test Tasks מספק את שני הצרכים, וניתן פשוט לקבוע בהגדרות אם לעצור בכשלון ראשון – או לא. אם אחנו רוצים להגדיר שלב של “בדיקות יחידה איטיות” – קל לעשות זאת ע”י שימוש חוזר ב Test Task.
- אנו צריכים להגדיר את התלויות לגרסה הספציפית של Junit שבה אנו רוצים להשתמש. לא פינקו אותנו ב wrapper לקונפיגורציה הזו. כמו במייבן – הגדרה של dependency בקובץ הראשי תשפיע על כל תתי-הפרויקטים (במייבן: מודולים) שלו.
- ההגדרה הזו מקבילה במייבן לתחביר הבא:
אני מניח שלא היה לכם קשה לעשות את המיפוי הבסיסי.
- מהן הפונקציות הללו,()testImplenentation ו ()testRuntimeOnly?
נסביר עליהן בהמשך.
- ההגדרה הזו מקבילה במייבן לתחביר הבא:
The Java Plugin
- Tasks – בהם נוכל להשתמש.
- LifeCycle Tasks (במייבן: “Goals”) – אליהם Plugins שונים יוכלו להתחבר, ולחבר Tasks שונים.
- מבנה התיקיות של קוד המקור (במקרה זה ה Java Plugin שומר על הקונבנציה המורכת לנו ממייבן)
- Dependency Management (כללים) – כללים כיצד תלויות מנוהלות. מכיוון שלסביבות פיתוח שונות (Go, ++C, JVM) יש צרכים שונים – נתנו בגריידל ל Plugin להגדיר את הכללים המדויקים לניהול התלויות.
גריידל מספקת תשתית/כלים עליהם כל Plugin יכול לבנות את המודל שהוא זקוק לו.
ל Java Plugin יש כמה הרחבות סטנדרטיות:
- Java Library Plugin – עבור build script של ספריה המופצת לקהל רחב כספריה.
- Java Application Plugin – עבור build script של אפליקציה. מוסיף Tasks כגון start או install. הוא מתאים הן לכתיבת שרת או אפליקציה שולחנית.
- Java Platform Plugin – לכתיבה של סט ספריות קשורות (למשל: Junit 5 מורכב מכמה תתי-פרויקטים, הקשורים זה לזה)
- גרסאות ספציפיות ל Groovy ו Scala – המרחיבות
מחזור החיים של בילד ב Java Plugin בגריידל
![]() |
מקור: פוסט על מייבן בבלוג ארכיטקטורת תוכנה. וואהו, זה היה מזמן. |
Dependency Configurations
- קוד האפליקציה יכול להשתמש בקוד מספריות שלא הייתה כוונה להשתמש בהן.
- המקרה הזה בעייתי במיוחד בקוד פנימי שלנו, שאנו רוצים במפורש להימנע מהשימוש בו – אך מפתחים עשויים לא לשים לב (כי ה package name תואמים).
- בשל האופי הטרנזיטיבי של התלויות, מרחב הקוד שאני שחשוף לשימוש ע”י קוד האפליקציה עשוי להיות גדול מאוד: האפליקציה תלויה ישירות ב 3 ספריות, אך ב 50 ספריות בצורה טרנזיטיבית – הוא תסריט נפוץ.
- יש עבודה מיותרת לתהליך ה build – בהבאת כל הספריות, טרנזיטיבית, ל classpath בזמן קומפילציה.
- יש עבודה מיותרת לתהליך ה build – בכך שכל שינוי קוד בספריה שהובאה טרנזיבית, מעלה ספק אולי צריך לקמפל את הספריות שתלויות בו (טרנזיטיבית) – וכך קשה לבסס build cache יעיל.
הורשה משמע שכל תלות שהוספנו לאב – זמינה גם לבן. הקוביות הצבעוניות מתארות מה עושים עם כל גרף תלויות בפועל. אציין שוב ש “api” הן התלויות הכלליות ביותר – ושמומלץ להימנע משימוש בה עד כמה שאפשר.