Skip to content

لغات النطاق المحدد (DSL): "الكود الذي لا يشبه الكود" في عالم الخلفية

مقدمة

في حالة واقعية، قام المهندس Armin ببناء خدمة بنية تحتية في شركته الجديدة باستخدام الذكاء الاصطناعي، بإجمالي حوالي 40,000 سطر من الكود (Go + YAML + Pulumi + كود SDK اللاصق)، حيث تم إنشاء أكثر من 90% منها بواسطة الذكاء الاصطناعي. ظهرت في هذه الحالة العديد من المصطلحات غير المألوفة للمبتدئين: YAML، Pulumi، HCL، Lua، كود SDK اللاصق… وهي ليست Python ولا JavaScript، لكنها موجودة في كل مكان في مشاريع الخلفية. ستقدم هذه المقالة هذه التقنيات بشكل منهجي من منظور موحد — لغات النطاق المحدد (DSL).

أهداف التعلم لهذه المقالة

في تطوير الخلفية، بالإضافة إلى منطق الأعمال المكتوب بلغات البرمجة العامة (Python، Go، Java، إلخ)، هناك أيضًا كمية كبيرة من الملفات والأكواد ذات الأغراض المختلفة، والقواعد المختلفة، ولكن لا تنتمي إلى لغات البرمجة العامة. لها مفهوم موحد أعلى: DSL (Domain-Specific Language، لغة النطاق المحدد).

بعد دراسة هذه المقالة، ستكون قادرًا على:

  • فهم الفرق الجوهري بين DSL ولغات البرمجة العامة (GPL)
  • إتقان نظام تصنيف DSL: صيغ تسلسل البيانات، لغات البرمجة النصية المضمنة، لغات تعريف البنية التحتية
  • التمييز بين سيناريوهات استخدام XML، JSON، YAML، TOML، CSV، Protobuf وغيرها من صيغ البيانات
  • فهم الغرض التصميمي للغات البرمجة النصية المضمنة مثل Lua
  • شرح مبدأ واختلاف Terraform (HCL) و Pulumi
  • فهم مواصفات OpenAPI ومبدأ عمل التوليد التلقائي لـ SDK
  • تحديد أنواع الأكواد المناسبة للتوليد بواسطة الذكاء الاصطناعي
الفصلالموضوعالمفاهيم الأساسية
الفصل 1مقدمة عامة عن DSLتعريف DSL مقابل GPL، نظام التصنيف والصورة الشاملة
الفصل 2صيغ تسلسل البياناتXML، JSON، YAML، TOML، CSV، Protobuf وغيرها
الفصل 3لغات البرمجة النصية المضمنةفلسفة تصميم Lua وغيرها من اللغات وتطبيقاتها النموذجية
الفصل 4البنية التحتية ككودمبدأ Terraform (HCL) و Pulumi والمقارنة بينهما
الفصل 5الكود اللاصق وتوليد SDKمواصفات OpenAPI والتوليد التلقائي لكود العميل
الفصل 6علاقة الذكاء الاصطناعي بـ DSLلماذا يتفوق الذكاء الاصطناعي بشكل خاص في توليد كود DSL

1. مقدمة عامة عن DSL: عالم آخر خارج اللغات العامة

1.1 ما هي DSL؟

DSL (Domain-Specific Language، لغة النطاق المحدد) هي لغة مصممة لمجال أو مهمة محددة. في مقابلها تأتي GPL (General-Purpose Language، لغة البرمجة العامة)، مثل Python، Java، Go، C++ وغيرها — وهي مصممة لحل أي مشكلة حسابية.

الفروق الجوهرية بين الاثنين:

البعدGPL (لغة البرمجة العامة)DSL (لغة النطاق المحدد)
هدف التصميمحل أي مشكلة حسابيةحل مشكلة في مجال محدد
نطاق التعبيرتورينج كاملة، نظريًا يمكنها حساب أي شيءعادةً ما يكون نطاق التعبير محدودًا عن قصد
تكلفة التعلممرتفعة، تتطلب فهم نظام اللغة الكاملمنخفضة، تحتاج فقط لفهم مفاهيم المجال
أمثلة نموذجيةPython، Java، Go، C++، JavaScriptSQL، HTML/CSS، التعابير النمطية، YAML، HCL

أنت في الواقع تستخدم DSL منذ فترة طويلة:

  • SQL هي DSL لمجال استعلام قواعد البيانات — تستخدم SELECT * FROM users WHERE age > 18 للاستعلام عن البيانات، بدلاً من كتابة منطق تكرار يدوي بلغة Python
  • HTML/CSS هي DSL لمجال هيكل وأنماط صفحات الويب — تصف الصفحة باستخدام الوسوم والخصائص، بدلاً من التعامل مع البكسلات بلغة C++
  • التعابير النمطية هي DSL لمجال مطابقة أنماط النصوص — تستخدم \d{3}-\d{4} لمطابقة رقم الهاتف، بدلاً من كتابة حلقة مقارنة حرفية يدوية

1.2 تصنيف DSL

يمكن تقسيم DSL إلى فئتين رئيسيتين بناءً على "ما إذا كانت تورينج كاملة":

DSL الخارجية (External DSL)

تمتلك قواعد ومحللًا مستقلين، ولا تعتمد على أي لغة برمجة عامة. تتم معالجة الكود الذي يكتبه المستخدم بواسطة مفسر أو مترجم مخصص.

  • نوع وصف البيانات البحت: JSON، YAML، XML، TOML، CSV، Protobuf (لا تحتوي على أي منطق)
  • نوع الاستعلام/التشغيل: SQL، GraphQL، التعابير النمطية (قدرة منطقية محدودة)
  • نوع نمذجة المجال: HCL (Terraform)، Dockerfile، قواعد تكوين Nginx (وصف تصريحي لحالة مجال محدد)

DSL الداخلية (Internal DSL / Embedded DSL)

تتطفل داخل لغة برمجة عامة، مستفيدة من قواعد اللغة المضيفة لبناء تعبيرات خاصة بالمجال. الكود نفسه هو كود قانوني للغة المضيفة، لكنه يُقرأ كلغة مخصصة.

  • Pulumi (مكتوب بلغة TypeScript/Python/Go، لكن واجهة API مصممة لتبدو كتكوين تصريحي)
  • تعريف المسارات في Ruby on Rails (get '/users', to: 'users#index'، كود Ruby قانوني، لكنه يُقرأ كتكوين)
  • قواعد التأكيد في أطر الاختبار (expect(value).toBe(42)، JavaScript قانوني، لكنه يُقرأ كلغة طبيعية)

1.3 الصورة الشاملة لـ DSL في مشاريع الخلفية

في مشروع خلفية نموذجي، ستواجه الفئات التالية من DSL:

DSL في مشاريع الخلفية
├── صيغ تسلسل البيانات (وصف هيكل البيانات)
│   ├── الصيغ النصية: JSON، YAML، XML، TOML، CSV، INI
│   └── الصيغ الثنائية: Protobuf، MessagePack، Avro، BSON
├── لغات البرمجة النصية المضمنة (طبقة تكوين قابلة للبرمجة)
│   ├── Lua (محركات الألعاب، Nginx، Redis)
│   ├── GDScript (محرك Godot)
│   └── Jsonnet (توليد قوالب التكوين)
├── DSL البنية التحتية والعمليات (وصف تصريحي لحالة النظام)
│   ├── HCL (Terraform)
│   ├── Dockerfile / Docker Compose YAML
│   └── قواعد تكوين Nginx / Apache
└── لغات وصف الواجهات (وصف عقد API)
    ├── OpenAPI / Swagger
    ├── Protocol Buffers (ملفات .proto)
    └── GraphQL Schema

بعد فهم هذه الصورة الشاملة، ستتوسع الفصول التالية في كل فرع على حدة.


2. صيغ تسلسل البيانات: وصف البيانات المهيكلة بالنص

2.1 ما هو تسلسل البيانات؟

التسلسل (Serialization) هو عملية تحويل هياكل البيانات في الذاكرة (الكائنات، القواميس، المصفوفات، إلخ) إلى تيار نصي أو بايتي يمكن تخزينه أو نقله. والعكس، إعادة تحويل التيار النصي أو البايتي إلى هياكل بيانات في الذاكرة، يسمى إلغاء التسلسل (Deserialization).

صيغ تسلسل البيانات هي الفئة الأساسية في DSL — تنتمي إلى DSL الخارجية من نوع وصف البيانات البحت، لا تمتلك أي قدرة منطقية، وتقتصر مسؤوليتها على الوصف الثابت لـ "ما هي القيمة".

2.2 لماذا نحتاج إلى هذه الصيغ؟

افترض أنك طورت خدمة خلفية، وعنوان قاعدة البيانات هو localhost:5432. إذا قمت بتضمين هذا العنوان مباشرة في الكود المصدري، فلن يكون هناك مشكلة في التطوير المحلي، لكن عند النشر إلى بيئة الإنتاج، يتغير عنوان قاعدة البيانات إلى db.prod.company.com:5432، وستحتاج إلى تعديل الكود المصدري وإعادة الترجمة.

الممارسة العامة في الهندسة هي: فصل المعاملات القابلة للتغيير عن الكود، وتخزينها في ملفات تكوين مستقلة. يقرأ البرنامج ملف التكوين عند بدء التشغيل، ويتخذ القرارات بناءً على القيم الموجودة فيه.

بالإضافة إلى التكوين، تُستخدم صيغ تسلسل البيانات على نطاق واسع في: تبادل البيانات بين الأنظمة (طلبات/استجابات API)، التخزين المستمر للبيانات، التواصل بين اللغات المختلفة وغيرها من السيناريوهات.

2.3 الصيغ النصية القابلة للقراءة البشرية

فيما يلي صيغ التسلسل النصية الأكثر شيوعًا في الهندسة، مقدمة بالترتيب التاريخي.

INI

أقدم صيغة تكوين، نشأت من أنظمة Windows. هيكل بسيط، يتكون من أقسام (section) وأزواج مفتاح-قيمة:

ini
[database]
host = localhost
port = 5432

[server]
debug = true

الميزة هي قابلية القراءة العالية. القيد هو عدم دعم الهياكل المتداخلة وأنواع المصفوفات، وعدم القدرة على التعبير عن التكوينات المعقدة. تظهر حاليًا بشكل رئيسي في الأنظمة القديمة وبعض تكوينات Linux (مثل php.ini، my.cnf).

CSV

CSV (Comma-Separated Values، القيم المفصولة بفواصل) هي أبسط صيغة للبيانات الجدولية:

csv
name,age,city
Alice,30,Beijing
Bob,25,Shanghai

كل سطر هو سجل، والحقول مفصولة بفواصل. يُستخدم CSV على نطاق واسع في استيراد وتصدير البيانات، تبادل جداول البيانات، وخطوط أنابيب تحليل البيانات. قيده هو أنه يمكنه فقط التعبير عن جداول ثنائية الأبعاد مسطحة، ولا يدعم الهياكل المتداخلة، ويفتقر إلى معلومات النوع (جميع القيم سلاسل نصية).

XML

XML (eXtensible Markup Language، لغة الترميز القابلة للتوسع) وُلدت في عام 1998، وكانت المعيار السائد لتبادل البيانات:

xml
<?xml version="1.0" encoding="UTF-8"?>
<config>
  <database>
    <host>localhost</host>
    <port>5432</port>
  </database>
  <server>
    <debug>true</debug>
    <allowed_origins>
      <origin>https://example.com</origin>
      <origin>https://app.example.com</origin>
    </allowed_origins>
  </server>
</config>

قوة تعبير XML عالية جدًا، وتدعم التداخل، الخصائص، مساحات الأسماء، التحقق بواسطة Schema وغيرها من الميزات المتقدمة. لكن قواعدها مطولة — الكمية الكبيرة من وسوم الفتح والإغلاق تؤدي إلى انخفاض نسبة الإشارة إلى الضوضاء، وتجربة الكتابة والقراءة اليدوية سيئة.

لا تزال XML مستخدمة على نطاق واسع في المجالات التالية:

  • نظام Java البيئي (pom.xml لـ Maven، تكوين Spring، ملفات تخطيط Android)
  • خدمات الويب المؤسسية (بروتوكول SOAP)
  • صيغ مستندات المكتب (.docx، .xlsx هي في الأساس مجموعات من ملفات XML مضغوطة بـ ZIP)
  • خلاصات RSS/Atom، رسوميات SVG المتجهة

JSON

JSON (JavaScript Object Notation) وُلد في عام 2001، وسرعان ما حل محل XML كمعيار فعلي لتبادل البيانات في واجهات Web API بسبب بساطته:

json
{
  "database": {
    "host": "localhost",
    "port": 5432
  },
  "server": {
    "debug": true
  }
}

الميزة هي الهيكل الواضح، وتقريبًا جميع لغات البرمجة لديها دعم تحليل أصلي. العيب الرئيسي هو عدم دعم التعليقات، وكثرة الأقواس وعلامات التنصيص تجعل الكتابة اليدوية عرضة للأخطاء. JSON هو أيضًا الصيغة القياسية لتكوين مشاريع الواجهة الأمامية (package.json، tsconfig.json).

YAML

YAML (YAML Ain't Markup Language) وُلد أيضًا في عام 2001، وهو حاليًا صيغة التكوين الأكثر استخدامًا في مجالات الخلفية و DevOps. أدوات مثل Docker Compose، Kubernetes، GitHub Actions تعتمد جميعها على YAML:

yaml
# تكوين قاعدة البيانات
database:
  host: localhost
  port: 5432

# تكوين الخادم
server:
  debug: true
  allowed_origins:
    - https://example.com
    - https://app.example.com

الميزة هي دعم التعليقات، القواعد المختصرة، والقدرة على التعبير عن الهياكل المتداخلة المعقدة. العيب هو الاعتماد على المسافة البادئة لتمثيل العلاقات الهرمية، حيث تؤدي أخطاء المسافة البادئة إلى فشل التحليل، وهذه هي المشكلة الأكثر شيوعًا التي يواجهها المبتدئون.

ملاحظة: الاسم الكامل لـ YAML "YAML Ain't Markup Language" هو اختصار تعاودي.

TOML

TOML (Tom's Obvious Minimal Language) وُلد في عام 2013، وتم تبنيه من قبل مدير الحزم Cargo في Rust و pyproject.toml في Python:

toml
[database]
host = "localhost"
port = 5432

[server]
debug = true
allowed_origins = [
  "https://example.com",
  "https://app.example.com"
]

تحاول TOML الجمع بين بساطة INI وقوة تعبير YAML، مع تجنب المشاكل الناتجة عن حساسية المسافة البادئة.

2.4 صيغ التسلسل الثنائية

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

الصيغةالمطورالخصائصسيناريوهات الاستخدام النموذجية
Protocol Buffers (Protobuf)Googleتتطلب تعريف ملف Schema .proto مسبقًا، كتابة قوية، حجم صغير جدًااتصال gRPC، خدمات Google الداخلية، الخدمات المصغرة عالية الأداء
MessagePackالمجتمعنسخة ثنائية مشابهة لـ JSON، لا تتطلب Schemaالترميز الداخلي لـ Redis، اتصال عالي الأداء بين اللغات
AvroApacheيدعم تطور Schema، مناسب لسيناريوهات البيانات الضخمةتسلسل البيانات في نظام Hadoop / Kafka البيئي
BSONMongoDBامتداد ثنائي لـ JSON، يدعم أنواع بيانات أكثرصيغة التخزين الداخلي لقاعدة بيانات MongoDB

بأخذ Protocol Buffers كمثال، يجب أولاً تعريف Schema:

protobuf
// user.proto
syntax = "proto3";

message User {
  string name = 1;
  int32 age = 2;
  string email = 3;
}

ثم من خلال المترجم (protoc) يتم توليد كود التسلسل/إلغاء التسلسل لكل لغة تلقائيًا. هذا النمط "تعريف Schema أولاً، ثم توليد الكود" يتوافق مع فكرة توليد OpenAPI SDK التي سيتم تقديمها لاحقًا.

2.5 مقارنة شاملة

الصيغةالنوعسنة النشأةقابلية القراءةدعم التعليقاتسيناريوهات الاستخدام النموذجية
INIنصية1980sعاليةتكوين النظام، المشاريع القديمة
CSVنصية1972عاليةاستيراد وتصدير البيانات، تبادل الجداول
XMLنصية1998متوسطةنظام Java البيئي، خدمات الويب المؤسسية، صيغ المستندات
JSONنصية2001عاليةتبادل بيانات Web API، تكوين الواجهة الأمامية
YAMLنصية2001عاليةDocker، K8s، CI/CD، تكوين خدمات الخلفية
TOMLنصية2013عاليةتكوين مشاريع Rust / Python
Protobufثنائية2008لا يوجدgRPC، اتصال الخدمات المصغرة عالية الأداء
MessagePackثنائية2008لا يوجداتصال عالي الأداء بين اللغات
Avroثنائية2009لا يوجدخطوط أنابيب البيانات الضخمة Hadoop / Kafka
BSONثنائية2009لا يوجدالتخزين الداخلي لـ MongoDB

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


3. لغات البرمجة النصية المضمنة: طبقة تكوين قابلة للبرمجة

3.1 تعريف المفهوم

لغات مثل Python، JavaScript، Go هي لغات برمجة عامة (General-Purpose Language)، يمكنها العمل بشكل مستقل وبناء تطبيقات كاملة.

على النقيض من ذلك، هناك فئة من اللغات مصممة خصيصًا لتضمينها في برامج مضيفة أخرى، لتوفير قدرات توسعة قابلة للبرمجة للبرنامج المضيف. تسمى هذه الفئة لغات البرمجة النصية المضمنة (Embedded Scripting Language).

المشكلة الأساسية التي تحلها هي: عندما تكون قوة التعبير لملفات التكوين الثابتة (YAML/JSON) غير كافية، وتحتاج إلى إدخال منطق مثل الشروط والحلقات، كيف يمكن تحقيق سلوك ديناميكي دون تعديل الكود المصدري للبرنامج المضيف.

3.2 Lua: أكثر لغات البرمجة النصية المضمنة تمثيلاً

Lua (تعني "القمر" باللغة البرتغالية) هي لغة برمجة نصية خفيفة الوزن للغاية، حجم المفسر المترجم بالكامل لا يتجاوز بضع مئات من الكيلوبايتات. هدفها التصميمي ليس العمل بشكل مستقل، بل أن تكون طبقة توسعة قابلة للتضمين.

سيناريوهات التطبيق النموذجية لـ Lua:

  • محركات الألعاب: نظام الإضافات في لعبة "World of Warcraft"، وسكربتات الألعاب في "Roblox" تستخدم Lua. محرك اللعبة مطبق بلغة C/C++ للتعامل مع العرض والحسابات الفيزيائية الأساسية، بينما يتم تفويض منطق المستويات وحوارات الشخصيات وغيرها من الأجزاء المتغيرة بشكل متكرر إلى سكربتات Lua. بهذه الطريقة، يمكن للمصممين تعديل محتوى اللعبة دون الحاجة إلى إعادة ترجمة المحرك.

  • خوادم الويب: يقوم OpenResty بتضمين Lua داخل Nginx، مما يسمح لمسؤولي العمليات بتنفيذ منطق تصفية الطلبات، تحديد المعدل، المصادقة وغيرها باستخدام سكربتات Lua، دون الحاجة إلى تعديل كود Nginx المصدري بلغة C.

  • قواعد البيانات: يدعم Redis إرسال سكربتات Lua إلى الخادم للتنفيذ، لتحقيق عمليات مركبة تتطلب ضمان الذرية (مثل "القراءة ثم الكتابة").

فيما يلي مثال لسكربت Lua مضمن في Nginx (OpenResty):

lua
-- الوظيفة: مصادقة token لمسار /api/secret
local uri = ngx.var.uri
local token = ngx.req.get_headers()["Authorization"]

if uri == "/api/secret" and token ~= "Bearer my-secret-token" then
    ngx.status = 403
    ngx.say("Access denied")
    return ngx.exit(403)
end

3.3 لغات برمجة نصية مضمنة أخرى

اللغةالبيئة المضيفةالاستخدامات النموذجية
Luaمحركات الألعاب، Nginx (OpenResty)، Redisمنطق الألعاب، سياسات البوابة، عمليات التخزين المؤقت
VimScript / Luaمحرر Vim / Neovimتطوير إضافات المحرر
Emacs Lispمحرر Emacsتخصيص سلوك المحرر
GDScriptمحرك ألعاب Godotسكربتات منطق الألعاب
Jsonnetنظام Kubernetes البيئي / أدوات توليد التكوينتوليد كميات كبيرة من تكوينات JSON/YAML المتشابهة باستخدام القوالب

النقطة الأساسية: لغات البرمجة النصية المضمنة في تصنيف DSL تنتمي إلى المنطقة الحدودية بين DSL الداخلية وDSL الخارجية — إنها لغات مستقلة (لها قواعدها ومفسرها الخاص)، لكن هدفها التصميمي هو التضمين في برنامج مضيف للتشغيل، وليس بناء تطبيقات مستقلة. إنها تملأ الفجوة بين "ملفات التكوين الثابتة" (DSL وصف البيانات البحت) و "لغات البرمجة العامة" (GPL): عندما يحتاج التكوين إلى التعبير عن منطق (شروط، حلقات، استدعاء دوال)، فإن تضمين لغة برمجة نصية خفيفة الوزن هو الحل الهندسي القياسي.


4. البنية التحتية ككود (Infrastructure as Code)

4.1 ما هي "البنية التحتية"

في هندسة الخلفية، تشير "البنية التحتية" (Infrastructure) إلى الموارد الأساسية التي تعتمد عليها التطبيقات للتشغيل:

  • موارد الحوسبة: الخوادم (أجهزة افتراضية أو حاويات)
  • تخزين البيانات: نسخ قواعد البيانات، حاويات تخزين الكائنات
  • الشبكة: قواعد جدار الحماية، موازنات الحمل، تكوين DNS
  • البرمجيات الوسيطة: طوابير الرسائل، مجموعات التخزين المؤقت

في عصر الحوسبة السحابية، يتم إنشاء وإدارة هذه الموارد من خلال لوحات تحكم مزودي الخدمات السحابية (مثل AWS، Alibaba Cloud، Tencent Cloud) بواجهة رسومية.

4.2 قيود الإدارة اليدوية

الإدارة من خلال لوحة التحكم اليدوية ممكنة في المشاريع صغيرة الحجم، لكن مع نمو حجم المشروع، تظهر المشاكل التالية:

  1. غير قابلة للتكرار: خطوات التشغيل غير مسجلة، ولا يمكن إعادة إنتاج نفس البيئة بدقة
  2. غير قابلة للتدقيق: لا يمكن تتبع "من عدل ماذا ومتى"
  3. غير قابلة للتعاون: عملية التشغيل لا يمكن إدراجها في نظام التحكم بالإصدارات، ولا يمكن إجراء مراجعة للكود
  4. عرضة للأخطاء: التشغيل اليدوي في بيئة الإنتاج يحمل مخاطر الأخطاء التشغيلية

الفكرة الأساسية لـ البنية التحتية ككود (Infrastructure as Code، اختصارًا IaC) هي: استخدام الكود لتعريف موارد البنية التحتية بشكل تصريحي، مما يمنحها قدرات التحكم بالإصدارات، التنفيذ الآلي، والنشر القابل للتكرار.

4.3 Terraform

Terraform هي أداة IaC الأكثر استخدامًا حاليًا، طورتها شركة HashiCorp. تستخدم لغة HCL (HashiCorp Configuration Language) المخصصة.

تتبنى Terraform نموذجًا تصريحيًا: يصف المستخدم الحالة النهائية المرغوبة، ويقوم Terraform تلقائيًا بحساب العمليات المطلوبة للانتقال من الحالة الحالية إلى الحالة المستهدفة.

hcl
# تعريف خادم سحابي
resource "aws_instance" "my_server" {
  ami           = "ami-0c55b159cbfafe1f0"  # صورة نظام التشغيل
  instance_type = "t3.micro"               # مواصفات النسخة

  tags = {
    Name = "my-first-server"
  }
}

# تعريف نسخة قاعدة بيانات PostgreSQL
resource "aws_db_instance" "my_database" {
  engine         = "postgres"
  instance_class = "db.t3.micro"
  username       = "admin"
  password       = "please-use-secrets-manager"
}

سير التنفيذ:

bash
terraform plan    # معاينة التغييرات التي سيتم تنفيذها
terraform apply   # تأكيد وتنفيذ، إنشاء الموارد تلقائيًا في المنصة السحابية

4.4 Pulumi

تقدم Pulumi نهجًا آخر: استخدام لغات البرمجة العامة مباشرة (TypeScript، Python، Go، إلخ) لتعريف البنية التحتية، بدلاً من تعلم قواعد HCL المخصصة.

نفس تعريف الخادم، معبرًا عنه بـ Pulumi + TypeScript:

typescript
import * as aws from "@pulumi/aws";

const server = new aws.ec2.Instance("my-server", {
    ami: "ami-0c55b159cbfafe1f0",
    instanceType: "t3.micro",
    tags: { Name: "my-first-server" },
});

const bucket = new aws.s3.Bucket("my-bucket", {
    acl: "private",
});

export const serverIp = server.publicIp;

نظرًا لاستخدام لغات البرمجة العامة، يمكن للمطورين الاستفادة من ميزات اللغة مثل الحلقات، الشروط، والتجريدات الوظيفية للتعامل مع منطق البنية التحتية المعقد.

4.5 مقارنة بين Terraform و Pulumi

البعدTerraformPulumi
اللغةHCL (لغة مخصصة)TypeScript / Python / Go وغيرها من اللغات العامة
تكلفة التعلمتحتاج إلى تعلم قواعد HCLاستخدام لغة برمجة متقنة بالفعل، تكلفة تعلم أقل
النظام البيئي المجتمعيناضج جدًا، يغطي تقريبًا جميع مزودي الخدمات السحابيةينمو بسرعة، لكنه أصغر حجمًا من Terraform
السيناريوهات المناسبةإدارة البنية التحتية الموحدة بقيادة فريق العملياتمشاريع بقيادة المطورين، سيناريوهات تحتاج إلى منطق معقد
ملاءمة توليد كود الذكاء الاصطناعيعالية (أنماط ثابتة)عالية جدًا (هي في جوهرها كود بلغة برمجة عامة)

النقطة الأساسية: HCL في أدوات IaC هي DSL خارجية نموذجية — لها قواعد ومحلل مستقلان، مصممة خصيصًا للوصف التصريحي لحالة البنية التحتية. بينما تتبنى Pulumi استراتيجية DSL الداخلية — استخدام قواعد لغة البرمجة العامة للتعبير عن مفاهيم خاصة بالمجال. كلاهما لهما نفس الهدف (تحويل إدارة البنية التحتية من التشغيل اليدوي إلى التشغيل بالكود)، لكن بمسارات مختلفة (لغة مخصصة مقابل لغة عامة). يمكن إدراج الكود في نظام التحكم بالإصدارات Git، ومراجعته من قبل الفريق، وتنفيذه آليًا والتراجع عنه.


5. الكود اللاصق وتوليد SDK التلقائي

5.1 ما هو الكود اللاصق

في هندسة البرمجيات، يشير الكود اللاصق (Glue Code) إلى الكود الذي لا يحتوي في حد ذاته على منطق أعمال، ويستخدم فقط لربط نظامين أو وحدتين.

يشمل الكود اللاصق النموذجي:

  • كود طلبات HTTP المكتوب عندما تستدعي الواجهة الأمامية API الخلفية (تجميع URL، إعداد رؤوس الطلب، تحليل الاستجابة)
  • كود عميل HTTP المكتوب عندما تستدعي الخدمة الخلفية A واجهة الخدمة B
  • كود تكييف الواجهات بين لغات البرمجة المختلفة

سمة هذا النوع من الكود هي: متكرر بدرجة عالية، ذو أنماط ثابتة، لكن لا يمكن حذفه.

5.2 مواصفات OpenAPI والتوليد التلقائي للكود

بما أن الكود اللاصق يتميز بدرجة عالية من النمطية، فإن الحل الهندسي هو: أولاً وصف واجهة API بصيغة قياسية، ثم استخدام أدوات لتوليد كود العميل تلقائيًا.

مواصفات OpenAPI (المعروفة سابقًا باسم Swagger) هي المعيار الصناعي لوصف REST API. تستخدم صيغة YAML أو JSON، لتعريف مسارات API، المعاملات، جسم الطلب وهيكل الاستجابة بدقة:

yaml
openapi: 3.0.0
info:
  title: API خدمة البريد
  version: 1.0.0

paths:
  /emails:
    post:
      summary: إرسال بريد إلكتروني
      requestBody:
        content:
          application/json:
            schema:
              type: object
              properties:
                to:
                  type: string
                  example: "user@example.com"
                subject:
                  type: string
                body:
                  type: string
      responses:
        '200':
          description: تم الإرسال بنجاح

بناءً على ملف المواصفات هذا، يمكن استخدام أدوات مثل openapi-generator لتوليد SDK عميل بلغات متعددة تلقائيًا:

  • Python: client.emails.send(to="user@example.com", subject="Hi", body="Hello")
  • TypeScript: client.emails.send({ to: "user@example.com", subject: "Hi", body: "Hello" })
  • Go: client.Emails.Send(ctx, &SendEmailRequest{To: "user@example.com", ...})

يقوم SDK المُنشأ بتغليف جميع تفاصيل طلب HTTP، ولا يحتاج المستدعي إلى الاهتمام بمسار URL، طريقة الطلب، صيغة التسلسل وغيرها من التفاصيل منخفضة المستوى.

5.3 إعادة فهم حالة Armin

بالعودة إلى الحالة في بداية المقال، يمكننا الآن فهم كل مكون بدقة:

المكونالطبيعةالوصف
Goكود منطق الأعمالتنفيذ الوظائف الأساسية لخدمة البريد الإلكتروني
YAMLملفات التكوينتكوين الخدمة، تعريف خط أنابيب CI/CD، ملف مواصفات OpenAPI
Pulumiكود البنية التحتيةتعريف الموارد السحابية (خوادم، قواعد بيانات، شبكة) باستخدام Go/TypeScript
كود SDK اللاصقمكتبة عميل مولدة تلقائيًاSDK لـ Python و TypeScript مولدة تلقائيًا من مواصفات OpenAPI

من بينها، تكوينات YAML، تعريفات موارد Pulumi، وكود SDK اللاصق — هذه الفئات الثلاث جميعها تنتمي إلى أكواد ذات أنماط عالية، مقيدة بمواصفات واضحة، وهذا هو المجال الذي تكون فيه قدرة توليد الكود بالذكاء الاصطناعي في أقوى حالاتها. لذلك فإن "90% من 40,000 سطر كود تم توليدها بواسطة الذكاء الاصطناعي" أمر معقول.


6. علاقة الذكاء الاصطناعي بـ DSL

6.1 تحليل ملاءمة توليد الكود بالذكاء الاصطناعي

بعد الخاصيةمناسب لتوليد الذكاء الاصطناعيغير مناسب لتوليد الذكاء الاصطناعي
درجة النمطيةمتكرر بدرجة عالية، يوجد قالب ثابتيحتاج إلى تصميم إبداعي، لا يوجد سابقة
القيود المعياريةيوجد schema أو قواعد نحوية واضحةمتطلبات غامضة، حدود غير واضحة
الاعتماد على السياقمكتفٍ ذاتيًا محليًا، التعريف الواحد لا يعتمد على فهم شامليحتاج إلى فهم القصد المعماري للنظام بأكمله
قابلية التحققيمكن التحقق منه تلقائيًا بالأدوات (مثل terraform validate)يعتمد فقط على الحكم البشري لمعقولية التصميم

الفئات الأربع من التقنيات المقدمة في هذه المقالة — ملفات التكوين، السكربتات المضمنة، كود IaC، كود SDK اللاصق — جميعها تمتلك خصائص العمود الأيسر. هذا يفسر لماذا يكون تأثير توليد الكود بالذكاء الاصطناعي في هذه المجالات أفضل بشكل ملحوظ من كود منطق الأعمال.

6.2 إطار التقييم

عند الحكم على ما إذا كان جزء من الكود مناسبًا لتوليده بواسطة الذكاء الاصطناعي، يمكن الرجوع إلى المعايير الثلاثة التالية:

  1. هل يوجد معيار أو schema جاهز؟ — إذا وجد، فهو مناسب للذكاء الاصطناعي
  2. هل ينتمي إلى أنماط متكررة بكميات كبيرة؟ — إذا كان كذلك، فهو مناسب للذكاء الاصطناعي
  3. هل يمكن التحقق من نتيجة التوليد تلقائيًا بواسطة الأدوات؟ — إذا كان ممكنًا، فهو مناسب للذكاء الاصطناعي

الكود الذي يحقق المعايير الثلاثة جميعها (مثل توليد SDK من مواصفات OpenAPI، تعريف موارد متجانسة بشكل جماعي باستخدام Terraform)، يمكن الاعتماد بشكل كبير على الذكاء الاصطناعي في توليده. الكود الذي لا يحقق أيًا من المعايير الثلاثة (مثل تصميم بروتوكول تناسق موزع جديد)، لا يزال بحاجة إلى إنجازه يدويًا من قبل المهندسين.


7. مسرد المصطلحات

المصطلحالاسم الكامل / بالعربيةالتعريف
DSLDomain-Specific Language / لغة النطاق المحددلغة مصممة لمجال محدد، مقابل لغة البرمجة العامة
GPLGeneral-Purpose Language / لغة البرمجة العامةلغة برمجة يمكنها حل أي مشكلة حسابية، مثل Python، Java، Go
DSL الخارجيةExternal DSLلغة نطاق محدد ذات قواعد ومحلل مستقلين، مثل SQL، HCL، YAML
DSL الداخليةInternal DSL / Embedded DSLتعبير خاص بالمجال مبني داخل لغة برمجة عامة باستخدام قواعد اللغة المضيفة، مثل Pulumi
تسلسل البياناتData Serializationعملية تحويل هياكل البيانات في الذاكرة إلى صيغة قابلة للتخزين أو النقل
INIInitializationأقدم صيغة تكوين بأزواج مفتاح-قيمة، نشأت من أنظمة Windows
CSVComma-Separated Values / القيم المفصولة بفواصلصيغة جداول نصية خالصة تفصل بين الحقول بفواصل
XMLeXtensible Markup Language / لغة الترميز القابلة للتوسعصيغة بيانات نصية مبنية على الوسوم، قوية التعبير لكن قواعدها مطولة
JSONJavaScript Object Notationصيغة تبادل بيانات خفيفة مبنية على أزواج المفتاح-القيمة، المعيار الفعلي لـ Web API
YAMLYAML Ain't Markup Languageصيغة ملفات تكوين مبنية على المسافة البادئة، مستخدمة على نطاق واسع في مجالات الخلفية و DevOps
TOMLTom's Obvious Minimal Languageصيغة تكوين بقواعد صريحة، شائعة في نظامي Rust و Python البيئيين
ProtobufProtocol Buffersصيغة تسلسل ثنائية طورتها Google، تتطلب تعريف Schema مسبقًا، صغيرة الحجم وسريعة
MessagePackصيغة تسلسل ثنائية مشابهة لـ JSON، لا تتطلب Schema
Luaلغة برمجة نصية مضمنة خفيفة الوزن، شائعة الاستخدام في محركات الألعاب وخوادم الويب وامتدادات قواعد البيانات
IaCInfrastructure as Code / البنية التحتية ككودممارسة هندسية لتعريف وإدارة موارد الحوسبة السحابية باستخدام الكود
Terraformأداة IaC طورتها HashiCorp، تستخدم لغة HCL التصريحية
HCLHashiCorp Configuration Languageلغة التكوين المخصصة المستخدمة في Terraform
Pulumiأداة IaC تدعم لغات البرمجة العامة
OpenAPIمعيار صناعي لوصف واجهات REST API (المعروفة سابقًا باسم Swagger)
SDKSoftware Development Kit / حزمة تطوير البرمجياتمكتبة عميل تغلف تفاصيل استدعاء API
الكود اللاصقGlue Codeكود لا يحتوي على منطق أعمال، يستخدم فقط لربط نظامين

الخلاصة

توجد في هندسة الخلفية كمية كبيرة من الأكواد غير المرتبطة بمنطق الأعمال. لها مفهوم موحد أعلى: DSL (لغة النطاق المحدد) — لغة مصممة لمجال محدد، مقابل لغة البرمجة العامة.

يمكن تصنيف DSL المقدمة في هذه المقالة إلى أربع فئات:

  1. صيغ تسلسل البيانات (XML / JSON / YAML / TOML / CSV / Protobuf وغيرها) — DSL خارجية لوصف البيانات البحت، تحول البيانات المهيكلة إلى شكل قابل للتخزين والنقل
  2. لغات البرمجة النصية المضمنة (Lua وغيرها) — تقع بين التكوين واللغات العامة، توفر قدرات توسعة قابلة للبرمجة للبرامج المضيفة
  3. لغات تعريف البنية التحتية (HCL / Dockerfile وغيرها) — DSL خارجية تصريحية، تصف الحالة المرغوبة للنظام؛ Pulumi تحقق نفس الهدف بطريقة DSL الداخلية
  4. لغات وصف الواجهات وتوليد الكود اللاصق (OpenAPI / .proto) — توليد كود الربط بين الأنظمة تلقائيًا من خلال وصف المواصفات

بعد فهم إطار تصنيف DSL هذا، عند مواجهة أنواع مختلفة من "الكود الذي لا يشبه الكود" في مشاريع الخلفية، يمكنك التعرف بسرعة على طبيعته: إلى أي فئة من DSL ينتمي، ما المشكلة المجالية التي يحلها، ولماذا لا يتم كتابته بلغة برمجة عامة.

في الوقت نفسه، نظرًا لأن كود DSL يتميز بدرجة عالية من النمطية، ومدفوع بالمواصفات، وقابل للتحقق التلقائي، فهو أيضًا أكثر مجالات تطبيق تقنية توليد الكود بالذكاء الاصطناعي فعالية حاليًا.