هل يتحدث كودك لغة الأعمال؟ حان الوقت لإنشاء DSL بلغة جافا
\n\nتخيل: أنت لا تكتب if-else و for المملة، بل تكتب كودًا يُقرأ كتعليمات لزميل. لا تصدق؟ لا داعي. اللغات المخصصة للمجال (DSL) بلغة جافا ليست سحرًا، بل أداة عملية تحول المنطق المعقد إلى تركيبات أنيقة.
في هذه المقالة، سنشرح كيفية إنشاء DSL بلغة جافا يجعل كودك أنظف، والعمل به أكثر وضوحًا لمحللي الأعمال. ستتعرف على الفرق بين DSL الداخلي و DSL الخارجي، وكيفية بناء fluent API، ومتى يجب كتابة المحلل النحوي الخاص بك. هيا بنا!
\n\nما هو DSL ولماذا يحتاجه مطور جافا؟
\n\nDSL (لغة مخصصة للمجال) هي لغة تم إنشاؤها لحل مشاكل في مجال معين. على عكس لغة البرمجة العامة (جافا، بايثون)، فإن DSL متخصص بشكل ضيق. أمثلة من الحياة الواقعية: SQL لقواعد البيانات، التعبيرات النمطية للعمل مع السلاسل النصية، HTML لبناء صفحات الويب.
\n\nفي جافا، يُستخدم DSL من أجل:
\n- \n
- زيادة قابلية قراءة الكود — يصبح منطق الأعمال تصريحيًا؛ \n
- خفض حاجز الدخول — يمكن للمحللين تعديل القواعد دون معرفة عميقة بجافا؛ \n
- تقليل عدد الأخطاء — بناء الجملة المحدود يمنع ارتكاب الأخطاء؛ \n
- تسريع التطوير — بدلاً من آلاف الأسطر من الكود، عشرات الأوامر الواضحة. \n
هام: إنشاء DSL بلغة جافا لا يتطلب كتابة مترجم. غالبًا ما نستخدم DSL الداخلي — وهي طبقات فوق بناء جملة جافا القياسي.
\n\nDSL داخلي مقابل DSL خارجي: أيهما تختار؟
\n\nDSL داخلي (Embedded DSL)
\nهو DSL يعيش داخل جافا. تستخدم الدوال، وسلاسل الاستدعاءات، والدوال lambda، وتحميل المشغلين (من خلال الدوال). مثال: Java Stream API هو DSL داخلي لمعالجة المجموعات.
\n\nList<String> result = orders.stream()\n .filter(o -> o.getAmount() > 1000)\n .map(Order::getCustomerName)\n .collect(Collectors.toList());\n\nالإيجابيات: لا حاجة لكتابة محلل نحوي، متكامل بإحكام مع جافا، سهل التصحيح. السلبيات: بناء الجملة محدود بإمكانيات جافا.
\n\nDSL خارجي (External DSL)
\nهي لغة منفصلة ببنائها النحوي الخاص. تكتب محللًا نحويًا (على سبيل المثال، باستخدام ANTLR أو JavaCC) ومفسرًا. مثال: SQL هو DSL خارجي ترسله إلى قاعدة البيانات.
\n\nالإيجابيات: حرية كاملة في بناء الجملة، يمكن جعلها جميلة جدًا. السلبيات: تحتاج لكتابة وصيانة محلل نحوي، أصعب في التصحيح.
\n\nمعظم المهام تكفيها DSL الداخلي. DSL الخارجي مبرر عندما يستخدم اللغة عدد كبير من الأشخاص (مثل SQL) أو عندما يكون بناء الجملة مهمًا جوهريًا.
\n\nتطبيق عملي: إنشاء DSL داخلي بلغة جافا لنظام مراقبة
\n\nلنفترض أننا نبني نظام مراقبة للخوادم. بدلاً من كتابة:
\n\nAlertRule rule = new AlertRule();\nrule.setMetric("cpu_usage");\nrule.setOperator(GREATER_THAN);\nrule.setThreshold(90.0);\nrule.setDuration(5, TimeUnit.MINUTES);\nrule.setAction(new SendEmailAction("admin@example.com"));\n\nنريد أن نكتب هكذا:
\n\nAlertRule rule = AlertRuleBuilder\n .whenMetric("cpu_usage")\n .isGreaterThan(90.0)\n .forDuration(5, TimeUnit.MINUTES)\n .thenSendEmail("admin@example.com")\n .build();\n\nجميل، أليس كذلك؟ دعنا ننفذ fluent API هذا.
\n\nالخطوة 1: إنشاء فئة AlertRule
\n\npublic class AlertRule {\n private String metric;\n private String operator;\n private double threshold;\n private long duration;\n private TimeUnit timeUnit;\n private String actionType;\n private String actionTarget;\n\n // تم حذف الدوال الواصلة والموصلة للاختصار\n}\n\n