يعد مبدأ "لا تكرر نفسك" أو DRY مبدأً مهمًا في تطوير البرمجيات. سيوضح لك هذا المنشور كيفية تطبيقه على تكوين Apache APISIX.
"عدم تكرار نفسك" (DRY) هو مبدأ في تطوير البرمجيات يهدف إلى تقليل تكرار المعلومات التي من المرجح أن تتغير، واستبدالها بتجريدات أقل عرضة للتغيير، أو استخدام تطبيع البيانات الذي يتجنب التكرار في المقام الأول.
الفكرة الرئيسية وراء DRY هي أنه إذا كررت نفسك وتغيرت المعلومات، فيجب عليك تحديث المعلومات المتغيرة في أماكن متعددة. وهذا ليس مجرد جهد إضافي؛ فهناك احتمال أن تنسى الأمر وتجد معلومات مختلفة في أماكن مختلفة. يتميز DRY بإصلاح الأخطاء.
تخيل أن هناك مقتطفًا من التعليمات البرمجية يحتوي على خطأ. تخيل الآن أنك قمت بتكرار المقتطف في مكانين مختلفين. الآن، يجب عليك إصلاح الخطأ في هذين المكانين، وهذا هو الجزء السهل؛ أما الجزء الصعب فهو معرفة التكرار في المقام الأول.
هناك احتمال كبير أن يكون الشخص الذي يقوم بالتكرار والشخص الذي يقوم بالإصلاح مختلفين. إذا تمت إعادة صياغة المقطع بحيث يمكن مشاركته واستدعاؤه من المكانين بدلاً من ذلك، فلن تحتاج إلى إصلاح الخطأ إلا في هذا المكان الواحد.
يربط معظم الأشخاص بين DRY والترميز. ومع ذلك، قد يكون أكثر تقييدًا ويتعارض مع الفكرة الأصلية.
لقد تم صياغة هذا المبدأ بواسطة آندي هانت وديف توماس في كتابهما The Pragmatic Programmer. وقد طبقاه على نطاق واسع ليشمل مخططات قواعد البيانات وخطط الاختبار ونظام البناء وحتى الوثائق.
تسمح أنظمة تكوين الصوت بالتجفيف أو حتى تشجعه.
يوفر Apache APISIX تكوين DRY في مكانين.
في سياق التجارة الإلكترونية، من المحتمل أن تبدأ رحلتك المبتدئة لتحديد مسار على Apache APISIX على النحو التالي:
routes: - id: 1 name: Catalog uri: /products* upstream: nodes: "catalog:8080": 1
إذا كنت على دراية بـ APISIX، فقد حددنا مسارًا إلى الكتالوج ضمن عنوان URI الخاص بـ /products
. ومع ذلك، هناك مشكلة: ربما تريد أن يتصفح العملاء المحتملون الكتالوج ولكنك تريد منع الأشخاص من إنشاء المنتجات أو حذفها أو تحديثها. ومع ذلك، يتطابق المسار مع كل طريقة HTTP افتراضيًا.
يجب أن نسمح فقط للمستخدمين المعتمدين بإدارة الكتالوج حتى يتمكن الجميع من تصفحه بحرية. لتنفيذ هذا النهج، نحتاج إلى تقسيم المسار إلى قسمين:
routes: - id: 1 name: Read the catalogue methods: [ "GET", "HEAD" ] #1 uri: /products* upstream: #2 nodes: "catalog:8080": 1 - id: 1 name: Read the catalogue methods: [ "PUT", "POST", "PATCH", "DELETE" ] #3 uri: /products* plugins: key-auth: ~ #4 upstream: #2 nodes: "catalog:8080": 1
key-auth
هو أبسط مكون إضافي لهذا الغرض
لقد قمنا بإصلاح مشكلة الأمان بأبسط طريقة ممكنة: عن طريق النسخ واللصق. وبذلك، قمنا بتكرار القسم upstream
. إذا احتجنا إلى تغيير الطوبولوجيا، على سبيل المثال ، عن طريق إضافة أو إزالة العقد، فيجب علينا القيام بذلك في مكانين. وهذا يتعارض مع مبدأ DRY.
في السيناريوهات الواقعية، وخاصة عندما تتضمن حاويات، لن تقوم بتنفيذ upstream
من خلال إدراج nodes
. بل يجب عليك بدلاً من ذلك تنفيذ اكتشاف الخدمة الديناميكي لاستيعاب تغييرات الطوبولوجيا. ومع ذلك، تظل النقطة قائمة عندما تحتاج إلى تغيير تكوين اكتشاف الخدمة أو تنفيذه. وبالتالي، تنطبق وجهة نظري على العقد واكتشاف الخدمة على حد سواء.
إلى جانب تجريد المسار ، تقدم APISIX تجريدًا علويًا لتنفيذ DRY. يمكننا إعادة كتابة المقطع أعلاه على النحو التالي:
upstreams: - id: 1 #1 name: Catalog nodes: "catalog:8080": 1 routes: - id: 1 name: Read the catalogue methods: [ "GET", "HEAD" ] uri: /products* upstream_id: 1 #2 - id: 1 name: Read the catalogue methods: [ "PUT", "POST", "PATCH", "DELETE" ] uri: /products* upstream_id: 1 #2 plugins: key-auth: ~
1
إذا حدث أي شيء في الطوبولوجيا، فيجب علينا تحديث التغيير فقط في المنبع الفردي.
لاحظ أن تحديد upstream
والإشارة إليه باستخدام upstream_id
هما أمران متبادلان .
منطقة أخرى حيث يمكن أن تساعدك APISIX في تجفيف تكوينك باستخدام تجريد المكونات الإضافية . تنفذ APISIX معظم الميزات، إن لم يكن كلها، من خلال المكونات الإضافية
لنقم بتنفيذ إصدارات تعتمد على المسار على واجهة برمجة التطبيقات الخاصة بنا. نحتاج إلى إعادة كتابة عنوان URL قبل إعادة توجيهه.
routes: - id: 1 name: Read the catalogue methods: [ "GET", "HEAD" ] uri: /v1/products* upstream_id: 1 plugins: proxy-rewrite: regex_uri: [ "/v1(.*)", "$1" ] #1 - id: 1 name: Read the catalogue methods: [ "PUT", "POST", "PATCH", "DELETE" ] uri: /v1/products* upstream_id: 1 plugins: proxy-rewrite: regex_uri: [ "/v1(.*)", "$1" ] #1
/v1
قبل إعادة التوجيه
كما هو الحال مع upstream
أعلاه، يتم تكرار قسم plugins
. يمكننا أيضًا حساب تكوين المكون الإضافي في كائن تكوين مكون إضافي مخصص. المقطع التالي له نفس التأثير مثل المقطع أعلاه:
plugin_configs: - id: 1 #1 plugins: proxy-rewrite: regex_uri: [ "/v1(.*)", "$1" ] routes: - id: 1 name: Read the catalogue methods: [ "GET", "HEAD" ] uri: /v1/products* upstream_id: 1 plugin_config_id: 1 #2 - id: 1 name: Read the catalogue methods: [ "PUT", "POST", "PATCH", "DELETE" ] uri: /v1/products* upstream_id: 1 plugin_config_id: 1 #2
ربما لاحظ القراء الأذكياء أنني أفتقد جزءًا من التكوين: فقد اختفى auth-key
بشكل غامض! في الواقع، قمت بإزالته من أجل الوضوح.
على عكس upstream
والمعرف upstream_id
، لا يتعارض plugins
plugin_config_id
المضمن مع بعضهما البعض . يمكننا إصلاح المشكلة عن طريق إضافة plugin
المفقود فقط:
routes: - id: 1 name: Read the catalogue methods: [ "GET", "HEAD" ] uri: /v1/products* upstream_id: 1 plugin_config_id: 1 - id: 1 name: Read the catalogue methods: [ "PUT", "POST", "PATCH", "DELETE" ] uri: /v1/products* upstream_id: 1 plugin_config_id: 1 plugins: key-auth: ~ #1
بهذه الطريقة، يمكنك نقل التكوين المشترك إلى كائن plugin_config
والاحتفاظ بتكوين محدد في المكان الذي ينطبق عليه. ولكن ماذا لو تم استخدام نفس المكون الإضافي بتكوينات مختلفة في plugin_config
ومباشرة في route
؟ الوثائق واضحة جدًا بشأن هذا الأمر:
Consumer
>Consumer Group
>Route
>Plugin Config
>Service
باختصار، تتغلب إعدادات plugin
في route
ما على plugin_config_id
. كما تسمح لنا بتوفير متغير apikey
لبرنامج key-auth
الإضافي في consumer
وتعيينه فقط في مسار ما. سيجد APISIX المفتاح لكل consumer
ويستخدمه!
لا يتعلق DRY بالكود فقط؛ بل يتعلق بإدارة البيانات بشكل عام. التكوين عبارة عن بيانات وبالتالي يقع تحت هذه المظلة العامة.
توفر APISIX خيارين لـ DRY: أحدهما للإصدار upstream
- upstream_id
، والآخر للمكون plugin
- plugin_config_id
. الإصدارات الأعلى حصرية؛ تسمح المكونات الإضافية بالتجاوز.
يجب أن تساعدك كلتا الآليتين على تجفيف تكوينك وجعله أكثر قابلية للصيانة على المدى الطويل.
وللمضي قدمًا:
نُشرت أصلاً في A Java Geek في 1 سبتمبر 2024