أدوات البناء والوحدات

لماذا نستخدم أدوات البناء؟

15 دقيقة الدرس 1 من 13

لماذا نستخدم أدوات البناء؟

أنتَ تعرف بالفعل كيف تكتب Java — الكلاسات والجينيريك والتدفقات والتزامن وJDBC. لكن إتقان اللغة ليس سوى جزء من الصورة. بمجرد أن ينمو المشروع ليتجاوز حفنة من ملفات الكود المصدري، تتفاقم ثلاث مشكلات مع بعضها: الترجمة على النطاق الواسع، وإدارة الاعتماديات، والتعبئة للنشر. أدوات البناء موجودة لحل هذه الثلاثة معًا، بشكل موثوق وقابل للتكرار.

حدود استخدام javac مباشرةً

المُترجم javac كافٍ تمامًا لتمارين التعلم، لكنه يصبح مرهقًا في المشاريع الحقيقية سريعًا.

تخيّل خدمة بسيطة تحتوي على 40 ملف مصدري موزعة على حزم، مع مكتبة تسجيل ومُحلل JSON وعميل HTTP ومُشغّل قاعدة بيانات. ترجمتها يدويًا تبدو هكذا:

javac -cp lib/slf4j-api-2.0.9.jar:lib/jackson-databind-2.15.2.jar:lib/postgresql-42.6.0.jar \ -d out \ src/com/example/service/*.java \ src/com/example/repository/*.java \ src/com/example/model/*.java \ src/com/example/util/*.java

يجب إعادة تجميع هذا الأمر في كل مرة يتغير فيها ملف أو اعتمادية. كما يجب تنزيل كل .jar يدويًا، وتتبع إصداره، وإيجاد اعتمادياته التعدية — أي المكتبات التي تعتمد عليها مكتباتك بدورها. هذا هو "جحيم الاعتماديات" الذي تُلغيه أدوات البناء.

مشكلة مسار الكلاس أسيّة النمو. مكتبة واحدة تسحب عادةً 5 إلى 15 اعتمادية تعدية. إدارة 4 اعتماديات مباشرة يدويًا تعني تتبع 30 إلى 60 ملف jar وإصداراتها وتوافقها المتبادل. أي عدم تطابق واحد يُسبب خطأ NoSuchMethodError أو ClassNotFoundException وقت التشغيل — بعد ساعات من ترجمة الكود بنجاح.

ما الذي تفعله أداة البناء فعليًا؟

أداة البناء برنامج يقرأ وصفًا تصريحيًا لمشروعك — ما تعتمد عليه، وكيف يُترجَم، وما الناتج الذي ينبغي إنتاجه — ثم ينفّذ تلك الخطوات بشكل حتمي. المسؤوليات الأساسية هي:

  • حل الاعتماديات. تُعلن عمّا تحتاجه (مثلًا Jackson 2.15.2). تجلب الأداة الـ jar وجميع اعتمادياته التعدية من مستودع مركزي، وتخزّنها محليًا، وتضعها على مسار الكلاس تلقائيًا.
  • تنظيم الترجمة. تكتشف الأداة جميع الملفات المصدرية وتترجمها بالترتيب الصحيح وتُعيد ترجمة ما تغيّر فقط (بناء تدريجي).
  • الاختبار. تتكامل أدوات البناء مع JUnit 5 وغيره. أمر mvn test أو gradle test يترجم مصادر الاختبار، ويشغّل جميع الاختبارات، وينتج تقريرًا — أمر واحد، لا إعداد يدوي.
  • التعبئة. تجمع الأداة الكلاسات المُترجمة والموارد والاعتماديات في ناتج قابل للنشر — ملف .jar أو .war لخوادم التطبيقات أو fat jar يحتوي على جميع الاعتماديات بداخله.
  • إدارة دورة الحياة. الخطوات مرتبة: clean ثم compile ثم test ثم package ثم install ثم deploy. تخطّي خطوة أو تغيير ترتيبها بالخطأ أمر غير ممكن.

قابلية التكرار والبناء ككود

ربما الخاصية الأهم في أداة البناء هي قابلية التكرار. واصف البناء — pom.xml في Maven أو build.gradle في Gradle — يُودَع في نظام إدارة الإصدارات. أي مطور على أي جهاز ينفّذ نفس الأمر ويحصل على نفس الناتج.

قابلية التكرار متطلب مهني. تعتمد عليها خطوط CI/CD وصور Docker وعمليات التدقيق الأمني جميعها لإعادة بناء نفس الناتج من الكود المصدري. المشروع الذي لا يستخدم أداة بناء لا يستطيع ضمان هذا — مشكلة "يعمل على جهازي فقط" هي عَرَض لغياب قابلية التكرار.

قارن بين المقاربتين:

  • javac اليدوي: لا سجل للاعتماديات، تنزيل يدوي للملفات، مسار كلاس مُجمَّع يدويًا، خطوات موثّقة في README سرعان ما تنفصل عن الواقع.
  • Maven / Gradle: جميع الاعتماديات مُعلنة بإصدارات محددة، جلبها تلقائي، خطوات البناء مُعرَّفة كأكواد، نفس الناتج على كل جهاز وفي كل بيئة.

التعبئة: من الكلاسات إلى ناتج قابل للتشغيل

نتيجة الترجمة ملفات .class منتشرة في مجلدات. شحن هذه الملفات إلى خادم أمر غير عملي. تتولى أدوات البناء التعبئة تلقائيًا في وحدة نشر واحدة.

أكثر أنواع النواتج شيوعًا:

  • Thin jar — يحتوي فقط على كلاساتك المُترجمة ومواردك. يجب أن يوفّر مسار كلاس وقت التشغيل جميع الاعتماديات بشكل منفصل. يُستخدم داخل خوادم التطبيقات والأطر التي تدير مسار الكلاس بنفسها.
  • Fat jar / uber-jar — جميع الاعتماديات مضمّنة بداخله. ترسل ملفًا واحدًا مكتفيًا بذاته: java -jar myapp.jar. هو الافتراضي في Spring Boot وQuarkus. سهل النشر لكن حجمه أكبر.
  • WAR — أرشيف تطبيق ويب للنشر في حاوية servlet مثل Tomcat أو Jetty. تذهب الاعتماديات إلى داخل WEB-INF/lib/.

بناء fat jar قابل للتشغيل مع Maven بسيط بمجرد إضافة maven-shade-plugin إلى POM وتشغيل أمر واحد:

mvn package # ينتج target/myapp-1.0.0.jar # شغّله في أي مكان تتوفر فيه Java: java -jar target/myapp-1.0.0.jar

الأداتان المهيمنتان: Maven وGradle

النظام البيئي لـ Java يحتوي على أداتَي بناء ناضجتين. ستصادف كلتيهما في المشاريع المهنية.

  • Maven — مبني على مبدأ الاتفاقية على التهيئة، يستخدم POM بصيغة XML، مراحل دورة حياة صارمة، نظام ضخم من الإضافات، معيار الصناعة لـ Java المؤسسي لعقدين. ممتاز للفرق التي تريد بنايات متوقعة وثابتة.
  • Gradle — يستخدم Groovy أو Kotlin كـ DSL، مرن للغاية، بنايات تدريجية ومُخبّأة، الافتراضي في Android ومتزايد الانتشار في مشاريع الخادم متعددة الوحدات الكبيرة. أسرع على النطاق الواسع وأكثر تعبيرية، لكنه يتطلب انضباطًا أكبر للحفاظ على الاتساق.
أيهما تختار؟ لمشروع جديد بلا قيود، Gradle مع Kotlin DSL هو الخيار العصري — أسرع وآمن النوع ومدعوم جيدًا. إذا انضممت إلى مشروع مؤسسي قائم فستجده يستخدم Maven على الأغلب. تعلّم الاثنتين؛ المفاهيم الأساسية (الاعتماديات ودورة الحياة والإضافات) تنتقل مباشرةً بينهما.

الخلاصة

لا يتوسع javac الخام بشكل جيد فيما يتجاوز المشاريع البسيطة. تحل أدوات البناء المشكلات الثلاث الجوهرية في تطوير Java الاحترافي: إدارة الاعتماديات (جلب المكتبات وحلها تلقائيًا)، والترجمة (تدريجية ومرتبة وصحيحة مسار الكلاس)، والتعبئة (إنتاج ناتج قابل للنشر). كما تجعل البنايات قابلة للتكرار — نفس الواصف ينتج نفس الناتج على كل جهاز، وهو أساس CI/CD والتعاون الجماعي ونشر الإنتاج. الدروس التالية تستعرض Maven وGradle بعمق.