استخراج المتغيرات (Extract Variables)

من موسوعة حسوب

المشكلة

وجود تعبيرٍ (expression) معقِّد يصعُب فهمه.

الحل

وضع ناتج التعبير أو جزءٍ منه في متغيِّرات (variables) واضحةٍ تُسهِّل الفهم.

مثال

قبل إعادة التصميم

نلاحظ وجود تعبيرٍ شرطيٍّ (conditional expression) معقَّدٍ وبعدّة أجزاء كما في الشيفرة الآتية:

في لغة Java:

void renderBanner() {
  if ((platform.toUpperCase().indexOf("MAC") > -1) &&
       (browser.toUpperCase().indexOf("IE") > -1) &&
        wasInitialized() && resize > 0 )
  {
    // افعل شيئًا
  }
}

في لغة #C:

void RenderBanner() 
{
  if ((platform.ToUpper().IndexOf("MAC") > -1) &&
       (browser.ToUpper().IndexOf("IE") > -1) &&
        wasInitialized() && resize > 0 )
  {
    // افعل شيئًا
  }
}

في لغة PHP:

if (($platform->toUpperCase()->indexOf("MAC") > -1) &&
     ($browser->toUpperCase()->indexOf("IE") > -1) &&
      $this->wasInitialized() && $this->resize > 0)
{
  // افعل شيئًا
}

في لغة Python:

def renderBanner(self):
    if (self.platform.toUpperCase().indexOf("MAC") > -1) and \
       (self.browser.toUpperCase().indexOf("IE") > -1) and \
       self.wasInitialized() and (self.resize > 0):
        # افعل شيئًا

في لغة TypeScript:

renderBanner(): void {
  if ((platform.toUpperCase().indexOf("MAC") > -1) &&
       (browser.toUpperCase().indexOf("IE") > -1) &&
        wasInitialized() && resize > 0 )
  {
    // افعل شيئًا
  }
}

بعد إعادة التصميم

ستحتوي كلٌّ من المتغيِّرات isMacOs و isIE و wasResized قيمةً منطقيّةً (boolean) ناتجةً عن المُعامِل المنطقي <، وستُستخدَم تلك المتغيِّرات في الشرط ليصبح أسهل فهمًا وقراءةً كما في الشيفرة:

في لغة Java:

void renderBanner() {
  final boolean isMacOs = platform.toUpperCase().indexOf("MAC") > -1;
  final boolean isIE = browser.toUpperCase().indexOf("IE") > -1;
  final boolean wasResized = resize > 0;

  if (isMacOs && isIE && wasInitialized() && wasResized) {
    // افعل شيئًا هنا
  }
}

في لغة #C:

void RenderBanner() 
{
  readonly bool isMacOs = platform.ToUpper().IndexOf("MAC") > -1;
  readonly bool isIE = browser.ToUpper().IndexOf("IE") > -1;
  readonly bool wasResized = resize > 0;

  if (isMacOs && isIE && wasInitialized() && wasResized) 
  {
    // افعل شيئًا
  }
}

في لغة PHP:

$isMacOs = $platform->toUpperCase()->indexOf("MAC") > -1;
$isIE = $browser->toUpperCase()->indexOf("IE")  > -1;
$wasResized = $this->resize > 0;

if ($isMacOs && $isIE && $this->wasInitialized() && $wasResized) {
  // افعل شيئًا
}

في لغة Python:

def renderBanner(self):
    isMacOs = self.platform.toUpperCase().indexOf("MAC") > -1
    isIE = self.browser.toUpperCase().indexOf("IE") > -1
    wasResized = self.resize > 0

    if isMacOs and isIE and self.wasInitialized() and wasResized:
        # افعل شيئًا

في لغة TypeScript:

renderBanner(): void {
  const isMacOs = platform.toUpperCase().indexOf("MAC") > -1;
  const isIE = browser.toUpperCase().indexOf("IE") > -1;
  const wasResized = resize > 0;

  if (isMacOs && isIE && wasInitialized() && wasResized) {
    // افعل شيئًا
  }
}

لم إعادة التصميم؟

يهدف استخراجُ المتغيِّرات إلى تبسيط التعابير المعقَّدة عبر تقسيمها لعدّة أجزاء مرحليّة، وهذا يشمل:

  • التعابير الشرطيّة للمعامل if أو أيَّ جزءٍ من المعامل الثلاثي ‎?:‎ في لغات البرمجة المعتمدة على لغة C‏ (C-based).
  • التعابير الرياضيّة (arithmetic) الطويلة غير المعتمدة على النتائج المرحليّة.
  • الأسطر الطويلة متعددة الأجزاء.

وقد يكون استخراج المتغيِّرات كخطوةٍ سابقةٍ لاستخراج التوابع (extract methods) إن كان التعبير المُستخرَج مستخدمًا بمواضع متفرِّقة في الشيفرة.

فوائد تطبيق الحل

الحصول على شيفرة واضحةٍ سهلة القراءة وخاصّة بإعطاء المتغيِّرات أسماء معبِّرةً مساعدةً توضِّح عيانًا الهدف من المتغيِّر، مثل: customerTaxValue و cityUnemploymentRate و clientSalutationString و ...إلخ. إذ كلما زادت قابلية قراءة الشيفرة (code readability) قلّت الحاجة إلى التعليقات (comments) التوضيحيّة الطويلة.

مساوئ تطبيق الحل

احتواء الشيفرة متغيِّراتٍ إضافيّةً ولكنّ توضيح الشيفرة وتحسينها يبرِّران ذلك.

آلية الحل

  1. إضافة سطرٍ جديدٍ قبل التعبير المعقَّد المُراد تبسيطه والتصريح عن متغيِّر جديدٍ فيه، ومن ثمّ إسناد جزءٍ من التعبير لهذا المتغيِّر.
  2. تبديل ذلك الجزء من التعبير إلى المتغيِّر المعبِّر عنه (المُنشأ في الخطوة السابقة).
  3. تكرار الخطوتين السابقتين لكل الأجزاء المعقَّدة في التعبير حتى الوصول إلى نتيجة مُرضية.

انظر أيضًا

مصادر