شعار ConstructiCat
CodeBust.
تصفح القسم ▾

الاقتران الوثيق.

الاقتران الوثيق نمط مضاد تعتمد فيه الموديولات على التفاصيل الداخلية لبعضها إلى حد أن تغيير أحدها يفرض تغيير الأخرى.

في هندسة البرمجيات، الاقتران (coupling) هو درجة الاعتماد المتبادل بين موديولات البرمجيات: مقياس لمدى ارتباط روتينين أو موديولين ارتباطاً وثيقاً ولقوة العلاقات بينهما. والاقتران في حد ذاته مقياس وليس عيباً، فكل نظام يعمل فيه قدر منه، وهو ليس ثنائياً بل متعدد الأبعاد. أما النمط المضاد فهو الاقتران الوثيق (tight coupling، ويسمى أيضاً الاقتران العالي أو القوي): موديولات تعتمد على التفاصيل الداخلية لبعضها، أو تتشارك حالة عامة، أو يجب أن تتغير معاً دائماً، فلا يمكن فهم أي منها أو اختباره أو إعادة استخدامه بمعزل عن غيره.

عادة ما يُقارن الاقتران بـ التماسك (cohesion). وغالباً ما يرتبط الاقتران المنخفض (Low coupling) بالتماسك العالي، والعكس صحيح. وغالباً ما يُنظر إلى الاقتران المنخفض على أنه علامة على نظام حاسوبي جيد الهيكلة وتصميم جيد، وعندما يجتمع مع التماسك العالي، فإنه يدعم الأهداف العامة المتمثلة في سهولة قراءة الكود وقابلية الصيانة.

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

التاريخ

تم ابتكار مقاييس جودة البرمجيات الخاصة بالاقتران والتماسك من قبل لاري كونستانتين في أواخر الستينيات كجزء من التصميم المهيكل، استناداً إلى خصائص ممارسات البرمجة "الجيدة" التي قللت من تكاليف الصيانة والتعديل. ونُشر التصميم المهيكل، بما في ذلك التماسك والاقتران، في مقال Stevens, Myers & Constantine (1974) وكتاب Yourdon & Constantine (1979)، وأصبح الأخيران لاحقاً من المصطلحات القياسية.

الاقتران مقابل التماسك

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

الدرجة

يمكن أن يكون الاقتران "منخفضاً" (يُسمى أيضاً "مرناً" وضعيفاً) أو "عالياً" (يُسمى أيضاً "وثيقاً" وقوياً). وتأتي بعض أنواع الاقتران، مرتبة من الأعلى إلى الأدنى اقتراناً، على النحو التالي:

البرمجة الإجرائية

يشير الموديول هنا إلى روتين فرعي من أي نوع، أي مجموعة من جملة برمجية واحدة أو أكثر لها اسم ويفضل أن يكون لها مجموعتها الخاصة من أسماء المتغيرات.

الاقتران بالمحتوى Content coupling (عالٍ)
يحدث الاقتران بالمحتوى عندما يستخدم موديول كود موديول آخر، مثل فرع (branch) برميجي. هذا ينتهك مبدأ إخفاء المعلومات (information hiding) – وهو مفهوم أساسي في تصميم البرمجيات.
الاقتران المشترك Common coupling
يحدث الاقتران المشترك عندما يكون لعدة موديولات إمكانية الوصول إلى نفس البيانات العامة (global data). ولكن يمكن أن يؤدي ذلك إلى انتشار غير منضبط للأخطاء وآثار جانبية غير متوقعة عند إجراء التغييرات.
الاقتران الخارجي External coupling
يحدث الاقتران الخارجي عندما يشترك موديولان في تنسيق بيانات مفروض خارجياً، أو بروتوكول اتصالات، أو واجهة جهاز. ويرتبط هذا أساساً بالاتصال بالأدوات والأجهزة الخارجية.
الاقتران بالتحكم Control coupling
الاقتران بالتحكم هو تحكم موديول واحد في تدفق موديول آخر، عن طريق تمرير معلومات إليه حول ما يجب القيام به (مثل تمرير علم يحدد الإجراء المطلوب).
الاقتران بالوسم Stamp coupling (اقتران هيكل البيانات)
يحدث الاقتران بالوسم عندما تشترك الموديولات في هيكل بيانات مركب وتستخدم أجزاءً منه فقط، وربما أجزاءً مختلفة (مثل تمرير سجل كامل إلى دالة تحتاج فقط إلى حقل واحد منه).
في هذه الحالة، قد يؤدي التعديل في حقل لا يحتاجه الموديول إلى تغيير طريقة قراءة الموديول للسجل. ولتوضيح مفهوم الاقتران بالوسم، ضع في اعتبارك سيناريو يتضمن مكون ملف المستخدم UserProfile. تم تصميم هذا المكون لإرجاع معلومات ملف تعريف المستخدم بأكملها استجابة لـ الطلبات، حتى عندما يطلب المستخدمون فقط خاصية (attribute) محددة. يمثل هذا السلوك اقتراناً بالوسم، والذي يمكن أن يؤدي إلى مشاكل كبيرة في عرض النطاق الترددي (bandwidth)، خاصة عند العمل على نطاق واسع. وعندما تتغير أي خاصية داخل مكون UserProfile، فقد يحتاج جميع المستهلكين الذين يتفاعلون معه إلى الخضوع لـ اختبار، حتى لو لم يستخدموا الخاصية المعدلة.
الاقتران بالبيانات Data coupling
يحدث الاقتران بالبيانات عندما تشترك الموديولات في البيانات من خلال المعاملات، على سبيل المثال. وتكون كل معلومة عبارة عن عنصر أساسي بسيط، وهذه هي البيانات الوحيدة المشتركة (مثل تمرير عدد صحيح إلى دالة تحسب الجذر التربيعي).

البرمجة كائنية التوجه

اقتران الفئات الفرعية Subclass coupling
يصف العلاقة بين الفئة الابن والفئة الأب. يرتبط الابن بالأب، ولكن الأب غير مرتبط بالابن.
الاقتران الزمني Temporal coupling
يحدث الاقتران الزمني عندما لا يمكن استخدام موديول إلا في وقت محدد أو بترتيب محدد بالنسبة إلى موديول آخر – مثلاً يجب استدعاء open() قبل read() – دون أن تفرض واجهته ذلك؛ راجع الاقتران التسلسلي. أما تجميع إجراءات في موديول واحد لمجرد أنها تحدث في الوقت نفسه فهو مفهوم مختلف يسمى التماسك الزمني (temporal cohesion).

في الأعمال الحديثة، تم التحقيق في مفاهيم اقتران مختلفة أخرى واستخدامها كمؤشرات لمبادئ تقسيم الموديولات المختلفة المستخدمة في الممارسة العملية.

الاقتران الديناميكي

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

الاقتران الدلالي

يأخذ هذا النوع من مقاييس الاقتران في الاعتبار التشابه المفاهيمي بين الكيانات البرمجية باستخدام التعليقات والمعرفات والاعتماد على تقنيات مثل الفهرسة الدلالية الكامنة (LSI).

الاقتران المنطقي

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

أبعاد الاقتران

وفقاً لغريغور هوب، فإن الاقتران متعدد الأبعاد:

  • الاعتماد على التكنولوجيا
  • الاعتماد على الموقع
  • الاعتماد على الهيكلية (Topology)
  • الاعتماد على نوع وتنسيق البيانات
  • الاعتماد الدلالي
  • الاعتماد على المحادثة
  • الاعتماد على الترتيب
  • الاعتماد الزمني

عيوب الاقتران الوثيق

تميل الأنظمة ذات الاقتران الوثيق إلى إظهار الخصائص التطويرية التالية، والتي غالباً ما يُنظر إليها على أنها عيوب:

  1. يؤدي التغيير في موديول واحد عادةً إلى فرض تأثير تموجي ripple effect للتغييرات في موديولات أخرى.
  2. قد يتطلب تجميع الموديولات مزيداً من الجهد و/أو الوقت بسبب زيادة الاعتماد المتبادل بين الموديولات.
  3. قد يكون من الأصعب إعادة استخدام موديول معين و/أو اختباره لأن الموديولات المعتمد عليها يجب تضمينها.

مشكلات الأداء

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

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

الحلول

أحد المناهج لتقليل الاقتران هو التصميم الوظيفي (functional design)، الذي يسعى إلى تحديد مسؤوليات الموديولات على طول الوظائف. ويزداد الاقتران بين فئتين A و B إذا كان:

  • لدى A خاصية تشير إلى (هي من نوع) B.
  • تقوم A باستدعاء خدمات كائن B.
  • لدى A دالة تشير إلى B (عبر نوع الإرجاع أو المعامل).
  • A هي فئة فرعية من الفئة B (أو تطبقها).

يشير الاقتران المنخفض إلى علاقة يتفاعل فيها موديول مع موديول آخر من خلال واجهة بسيطة ومستقرة ولا يحتاج إلى الاهتمام بالتطبيق الداخلي للموديول الآخر (انظر إخفاء المعلومات).

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

الاقتران مقابل التلازم

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

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

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

وعادة ما تكون للاعتمادات التي تمتد عبر حدود الموديولات أو الأنظمة الموزعة تكاليف تنسيق أعلى، مما يزيد من صعوبة إعادة الهيكلة ونشر التغييرات عبر الحدود البعيدة. وغالباً ما يتم استخدام الممارسات الحديثة، مثل حقن التبعية (dependency injection) والبرمجة القائمة على الواجهات، لتقليل قوة الاقتران وتحسين إمكانية صيانة الاعتمادات.

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

اقتران الموديولات

يختصر أحد المقاييس المنشورة هذه الأعداد في قيمة اقتران واحدة للموديول.

لاقتران البيانات وتدفق التحكم:

  • d_i: عدد معاملات البيانات المُدخلة
  • c_i: عدد معاملات التحكم المُدخلة
  • d_o: عدد معاملات البيانات المُخرجة
  • c_o: عدد معاملات التحكم المُخرجة

للاقتران العام (global coupling):

  • g_d: عدد المتغيرات العامة المستخدمة كبيانات
  • g_c: عدد المتغيرات العامة المستخدمة للتحكم

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

  • w: عدد الموديولات المستدعاة (fan-out)
  • r: عدد الموديولات التي تستدعي الموديول المعني (fan-in)

وعندئذ يكون اقتران الموديول:

Coupling(C) = 1 − 1 / (d_i + 2×c_i + d_o + 2×c_o + g_d + 2×g_c + w + r)

تزداد القيمة كلما زاد اقتران الموديول، وتتراوح تقريباً بين 0.67 (اقتران منخفض) و1.0 (اقتران عالٍ).

على سبيل المثال، إذا كان للموديول معامل بيانات واحد مُدخل وآخر مُخرج فقط:

C = 1 − 1 / (1 + 0 + 1 + 0 + 0 + 0 + 1 + 0) = 1 − 1/3 = 0.67

وإذا كان للموديول 5 معاملات بيانات مُدخلة و5 مُخرجة، وعدد مماثل من معاملات التحكم، ويصل إلى 10 عناصر من البيانات العامة، مع fan-in يساوي 3 وfan-out يساوي 4:

C = 1 − 1 / (5 + 2×5 + 5 + 2×5 + 10 + 0 + 4 + 3) = 0.98

مثال

Report هذه مقترنة اقتراناً وثيقاً بكل ما تلمسه: بكائن قاعدة بيانات وحيد (singleton) عام، وبمخطط SQL، وبموضع عمود في نتيجة الاستعلام، وبوحدة التحكم (console).

class Report {
    void run() {
        List<Object[]> rows = Db.connection().query("select * from orders");
        for (Object[] row : rows) {
            System.out.println(row[3]); // العمود 3 هو المجموع، حالياً
        }
    }
}

بعد إعادة الهيكلة لم تعد تعتمد إلا على واجهة ضيقة ونوع قيمة يُمرَّران إليها من الخارج:

interface OrderSource {
    List<Order> orders();
}

record Order(String id, BigDecimal total) {}

class Report {
    private final OrderSource source;
    private final PrintStream out;

    Report(OrderSource source, PrintStream out) {
        this.source = source;
        this.out = out;
    }

    void run() {
        for (Order order : source.orders()) {
            out.println(order.total());
        }
    }
}

صار بالإمكان الآن تغيير قاعدة البيانات والمخطط والمخرجات، أو استبدالها بكائنات وهمية في الاختبارات، دون المساس بـReport.

مقتبس من مقالة ويكيبيديا “Coupling (computer programming)” (المراجعة 1355254577)، والمتاحة بموجب رخصة CC BY-SA 4.0؛ تمت ترجمة النص وتحريره وإضافة أمثلة.