الفرق بين المراجعتين ل"Refactoring/replace error code with exception"

من موسوعة حسوب
اذهب إلى التنقل اذهب إلى البحث
(أنشأ الصفحة ب'<noinclude>{{DISPLAYTITLE: استبدال شيفرات الأخطاء باستثناءات (Replace Error Code with Exception)}}</noinclude> == المشكلة == يعي...')
 
ط (مراجعة وتدقيق.)
 
سطر 9: سطر 9:
  
 
==== قبل إعادة التصميم ====
 
==== قبل إعادة التصميم ====
في لغة Java:<syntaxhighlight lang="java">
+
يعيد التابع <code>()withdraw</code> القيمة 1- التي تمثِّل خطأً إن تحقق شرط محدَّد:
 +
 
 +
في لغة [[Java]]:<syntaxhighlight lang="java">
 
int withdraw(int amount) {
 
int withdraw(int amount) {
 
   if (amount > _balance) {
 
   if (amount > _balance) {
سطر 19: سطر 21:
 
   }
 
   }
 
}
 
}
</syntaxhighlight>في لغة C#‎:<syntaxhighlight lang="c#">
+
</syntaxhighlight>في لغة [[C#]]‎:<syntaxhighlight lang="c#">
 
int Withdraw(int amount)  
 
int Withdraw(int amount)  
 
{
 
{
سطر 32: سطر 34:
 
   }
 
   }
 
}
 
}
</syntaxhighlight>في لغة PHP:<syntaxhighlight lang="php">
+
</syntaxhighlight>في لغة [[PHP]]:<syntaxhighlight lang="php">
 
function withdraw($amount) {
 
function withdraw($amount) {
 
   if ($amount > $this->balance) {
 
   if ($amount > $this->balance) {
سطر 41: سطر 43:
 
   }
 
   }
 
}
 
}
</syntaxhighlight>في لغة Python:<syntaxhighlight lang="python">
+
</syntaxhighlight>في لغة [[Python]]:<syntaxhighlight lang="python">
 
def withdraw(self, amount):
 
def withdraw(self, amount):
 
     if amount > self.balance:
 
     if amount > self.balance:
سطر 48: سطر 50:
 
         self.balance -= amount
 
         self.balance -= amount
 
     return 0
 
     return 0
 +
</syntaxhighlight>في لغة [[TypeScript]]:<syntaxhighlight lang="typescript">
 +
withdraw(amount: number): number {
 +
  if (amount > _balance) {
 +
    return -1;
 +
  }
 +
  else {
 +
    balance -= amount;
 +
    return 0;
 +
  }
 +
}
 
</syntaxhighlight>
 
</syntaxhighlight>
  
 
==== بعد إعادة التصميم ====
 
==== بعد إعادة التصميم ====
في لغة Java:<syntaxhighlight lang="java">
+
رمي استثناء يصف الخطأ الحاصل عبر <code>throw</code> (أو <code>raize</code>):
 +
 
 +
في لغة [[Java]]:<syntaxhighlight lang="java">
 
void withdraw(int amount) throws BalanceException {
 
void withdraw(int amount) throws BalanceException {
 
   if (amount > _balance) {
 
   if (amount > _balance) {
سطر 58: سطر 72:
 
   balance -= amount;
 
   balance -= amount;
 
}
 
}
</syntaxhighlight>في لغة C#‎:<syntaxhighlight lang="c#">
+
</syntaxhighlight>في لغة [[C#]]‎:<syntaxhighlight lang="c#">
 
///<exception cref="BalanceException">Thrown when amount > _balance</exception>
 
///<exception cref="BalanceException">Thrown when amount > _balance</exception>
 
void Withdraw(int amount)
 
void Withdraw(int amount)
سطر 68: سطر 82:
 
   balance -= amount;
 
   balance -= amount;
 
}
 
}
</syntaxhighlight>في لغة PHP:<syntaxhighlight lang="php">
+
</syntaxhighlight>في لغة [[PHP]]:<syntaxhighlight lang="php">
 
function withdraw($amount) {
 
function withdraw($amount) {
 
   if ($amount > $this->balance) {
 
   if ($amount > $this->balance) {
سطر 75: سطر 89:
 
   $this->balance -= $amount;
 
   $this->balance -= $amount;
 
}
 
}
</syntaxhighlight>في لغة Python:<syntaxhighlight lang="python">
+
</syntaxhighlight>في لغة [[Python]]:<syntaxhighlight lang="python">
 
def withdraw(self, amount):
 
def withdraw(self, amount):
 
     if amount > self.balance:
 
     if amount > self.balance:
 
         raize BalanceException()
 
         raize BalanceException()
 
     self.balance -= amount
 
     self.balance -= amount
 +
</syntaxhighlight>في لغة [[TypeScript]]:<syntaxhighlight lang="typescript">
 +
withdraw(amount: number): void {
 +
  if (amount > _balance) {
 +
    throw new Error();
 +
  }
 +
  balance -= amount;
 +
}
 
</syntaxhighlight>
 
</syntaxhighlight>
  
 
== لم إعادة التصميم؟ ==
 
== لم إعادة التصميم؟ ==
إعادة شيفرة الخطأ هو ميراث عفا عليه الزمن من البرمجة الإجرائية. في البرمجة الحديثة، يكون التعامل مع الأخطاء من قبل أصناف خاصة، والتي تسمى الاستثناءات. إذا حدثت مشكلة، "يُطلِق" خطأً، والذي "يُلتقط" من قِبل أحد معالجات الاستثناءات. وتُفعَّل شيفرة معالجة الخطأ الخاصة، والتي تُتجاهل في الظروف العادية، كي تستجيب.
+
إعادة شيفرة الخطأ هو ميراث عفا عليه الزمن من البرمجة الإجرائية. في البرمجة الحديثة، يكون التعامل مع الأخطاء من قبل أصناف خاصة، والتي تسمى "الاستثناءات". إذا حدثت مشكلة، "يُطلِق" خطأً، والذي "يُلتقط" من قِبل أحد معالجات الاستثناءات. وتُفعَّل شيفرة معالجة الخطأ الخاصة، والتي تُتجاهل في الظروف العادية، كي تستجيب للاستثناء وتعالجه.
  
 
== فوائد تطبيق الحل ==
 
== فوائد تطبيق الحل ==
* يحرر الشيفرة البرمجية من عدد كبير من الشرطيات للتحقق من رموز الخطأ المختلفة. معالجات الاستثناءات هي طريقة أكثر إيجازًا للتمييز بين مسارات التنفيذ الطبيعية وبين تلك الغير طبيعية.
+
* تحرير الشيفرة البرمجية من عدد كبير من الشرطيات للتحقق من رموز الخطأ المختلفة. معالجات الاستثناءات هي طريقة أكثر إيجازًا للتمييز بين مسارات التنفيذ الطبيعية وبين تلك الغير طبيعية.
* ويمكن لأصناف الاستثناءات أن تنفذ توابعها الخاصة، وبالتالي تحتوي على جزء من وظائف معالجة الخطأ (مثل إرسال رسائل الخطأ).
+
* ويمكن لأصناف الاستثناءات أن تنفِّذ توابعها الخاصة، وبالتالي تحتوي على جزء من وظائف معالجة الخطأ (مثل إرسال رسائل الخطأ).
 
* على عكس الاستثناءات، لا يمكن استخدام شيفرات الأخطاء في المُنشئ، إذ أن المُنشئ يجب أن يعيد فقط كائنًا جديدًا.
 
* على عكس الاستثناءات، لا يمكن استخدام شيفرات الأخطاء في المُنشئ، إذ أن المُنشئ يجب أن يعيد فقط كائنًا جديدًا.
  
 
== مساوئ تطبيق الحل ==
 
== مساوئ تطبيق الحل ==
* يمكن أن يتحول معالج الاستثناء إلى عكاز يشبه جملة goto. تجنب هذا! لا تستخدم الاستثناءات لإدارة تنفيذ الشيفرة. لا ينبغي إطلاق الاستثناءات إلا للإبلاغ عن خطأ أو حالة حرجة فقط.
+
* يمكن أن يتحول معالج الاستثناء إلى عكاز يشبه جملة <code>goto</code>. إن كان كذلك، فتجنبه! لا تستخدم الاستثناءات لإدارة تنفيذ الشيفرة. أي لا ينبغي إطلاق الاستثناءات إلا للإبلاغ عن خطأ أو حالة حرجة فقط.
  
 
== آلية الحل ==
 
== آلية الحل ==
 
حاول تنفيذ هذه الخطوات لإعادة تصميم شيفرة خطأ واحد فقط في كل مرة. سيوفر هذا سهولة إبقاء كل المعلومات المهمة في رأسك وتجنب الأخطاء.
 
حاول تنفيذ هذه الخطوات لإعادة تصميم شيفرة خطأ واحد فقط في كل مرة. سيوفر هذا سهولة إبقاء كل المعلومات المهمة في رأسك وتجنب الأخطاء.
# ابحث عن كافة الاستدعاءات إلى تابعٍٍٍٍٍٍٍٍٍٍٍٍٍٍ إعادة شيفرات الخطأ، وبدلًا من التحقق من وجود شيفرة خطأ، غلفها في كُتَل <code>try/catch</code>.
+
# ابحث عن كافة الاستدعاءات إلى التابع الذي يعيد شيفرات الخطأ، وبدلًا من التحقق من وجود شيفرة خطأ، غلفها في كُتَل <code>try/catch</code>.
 
# أطلِق استثناءً داخل التابع، بدلًا من إعادة شيفرة الأخطاء.
 
# أطلِق استثناءً داخل التابع، بدلًا من إعادة شيفرة الأخطاء.
# غير توقيع التابع بحيث يحتوي معلومات حول الاستثناء التي يجري إلقاءه (قسم ‎<code>@throws</code>).
+
# غير توقيع التابع بحيث يحوي معلومات حول الاستثناء الذي يجري إلقاءه (قسم ‎<code>@throws</code>).
  
 
== مصادر ==
 
== مصادر ==
سطر 103: سطر 124:
 
[[تصنيف:Refactoring]]
 
[[تصنيف:Refactoring]]
 
[[تصنيف:Refactoring Techniques]]
 
[[تصنيف:Refactoring Techniques]]
[[تصنيف:Simplifying Method Calls]]
+
[[تصنيف:Refactoring Simplifying Method Calls]]

المراجعة الحالية بتاريخ 08:36، 26 فبراير 2019

المشكلة

يعيد التابع قيمة خاصة تشير إلى خطأ.

الحل

إطلاق استثناء بدلًا من ذلك.

مثال

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

يعيد التابع ()withdraw القيمة 1- التي تمثِّل خطأً إن تحقق شرط محدَّد:

في لغة Java:

int withdraw(int amount) {
  if (amount > _balance) {
    return -1;
  }
  else {
    balance -= amount;
    return 0;
  }
}

في لغة C#‎:

int Withdraw(int amount) 
{
  if (amount > _balance) 
  {
    return -1;
  }
  else 
  {
    balance -= amount;
    return 0;
  }
}

في لغة PHP:

function withdraw($amount) {
  if ($amount > $this->balance) {
    return -1;
  } else {
    $this->balance -= $amount;
    return 0;
  }
}

في لغة Python:

def withdraw(self, amount):
    if amount > self.balance:
        return -1
    else:
        self.balance -= amount
    return 0

في لغة TypeScript:

withdraw(amount: number): number {
  if (amount > _balance) {
    return -1;
  }
  else {
    balance -= amount;
    return 0;
  }
}

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

رمي استثناء يصف الخطأ الحاصل عبر throw (أو raize):

في لغة Java:

void withdraw(int amount) throws BalanceException {
  if (amount > _balance) {
    throw new BalanceException();
  }
  balance -= amount;
}

في لغة C#‎:

///<exception cref="BalanceException">Thrown when amount > _balance</exception>
void Withdraw(int amount)
{
  if (amount > _balance) 
  {
    throw new BalanceException();
  }
  balance -= amount;
}

في لغة PHP:

function withdraw($amount) {
  if ($amount > $this->balance) {
    throw new BalanceException;
  }
  $this->balance -= $amount;
}

في لغة Python:

def withdraw(self, amount):
    if amount > self.balance:
        raize BalanceException()
    self.balance -= amount

في لغة TypeScript:

withdraw(amount: number): void {
  if (amount > _balance) {
    throw new Error();
  }
  balance -= amount;
}

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

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

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

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

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

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

آلية الحل

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

  1. ابحث عن كافة الاستدعاءات إلى التابع الذي يعيد شيفرات الخطأ، وبدلًا من التحقق من وجود شيفرة خطأ، غلفها في كُتَل try/catch.
  2. أطلِق استثناءً داخل التابع، بدلًا من إعادة شيفرة الأخطاء.
  3. غير توقيع التابع بحيث يحوي معلومات حول الاستثناء الذي يجري إلقاءه (قسم ‎@throws).

مصادر