المكتبة

Chapter 10: Functions & Scope - The Reusable Machines

الفصل 10: الدوال والنطاق.. آلاتك البرمجية القابلة لإعادة الاستخدام

المبدأ الذي يفصل بين الهاوي والمحترف

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

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

المحترف لا يفعل ذلك. المحترف يبني “آلة” صغيرة تؤدي مهمة واحدة بشكل مثالي. في مثالنا، سيبني آلة لتركيب العجلات. يضغط زراً واحداً، والآلة تقوم بالعمل كله. هذه الآلة في عالم البرمجة هي الدالة (Function).

الدوال هي حجر الأساس للكود النظيف والمنظم. هي التي تسمح لك بتطبيق مبدأ “لا تكرر نفسك” (Don’t Repeat Yourself - DRY)، وهو أحد أقدس المبادئ في هندسة البرمجيات. إذا لم تتقن الدوال، سيبقى كودك فوضوياً، صعب القراءة، ومستحيل الصيانة.

في هذا الفصل، لن تتعلم مجرد بناء هذه الآلات، بل ستفهم أيضاً القواعد التي تحكمها، وأهمها: النطاق (Scope).


1. بناء الآلة: المدخلات، العملية، والمخرجات

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

  1. الاسم (Name): معرف فريد للوصول إليها (مثل calculateTotalPrice).
  2. المدخلات (Parameters/Arguments): البيانات التي تحتاجها الدالة لتعمل (مثل سعر المنتج والضريبة).
  3. المخرجات (Return Value): القيمة التي تنتجها الدالة بعد انتهاء عملها (مثل السعر الإجمالي).

لنرَ مثالاً حياً بلغة JavaScript، لكن المبدأ ينطبق على كل اللغات تقريباً:

// تعريف الدالة (بناء الآلة)
function calculateTotalPrice(price, taxRate) {
  const total = price * (1 + taxRate);
  return total; // إرجاع الناتج
}

// استخدام الدالة (تشغيل الآلة)
const itemPrice = 100;
const salesTax = 0.15;

const finalPrice = calculateTotalPrice(itemPrice, salesTax); // استدعاء الدالة

console.log(finalPrice); // سيطبع: 115

هنا، calculateTotalPrice هي آلتنا. price و taxRate هما المدخلات التي نمررها لها. داخل الدالة، تتم عملية حسابية. وأخيراً، تستخدم الكلمة المفتاحية return لإخراج القيمة النهائية.

الجمال هنا هو أنه يمكننا الآن استخدام هذه الدالة في أي مكان في تطبيقنا لحساب السعر الإجمالي لأي منتج، بدلاً من كتابة price * (1 + taxRate) في كل مرة. إذا تغيرت طريقة حساب الضريبة لاحقاً، سنحتاج لتعديل مكان واحد فقط: داخل الدالة. هذا هو معنى القوة والقابلية للصيانة.


2. قانون المكان: ما هو النطاق (Scope)؟

الآن بعد أن بنيت آلتك، يجب أن تفهم “قانون المكان”. لا يمكنك الوصول إلى كل شيء من أي مكان. هذا هو جوهر مفهوم النطاق (Scope).

النطاق يحدد “مكان عيش” المتغيرات، ومن يملك صلاحية الوصول إليها. هناك نوعان أساسيان من النطاق:

  1. النطاق العام (Global Scope): أي متغير يتم تعريفه خارج أي دالة. يمكن الوصول إليه من أي مكان في الكود. فكر فيه كساحة عامة في مدينة، متاحة للجميع.
  2. النطاق المحلي (Local/Function Scope): أي متغير يتم تعريفه داخل دالة. لا يمكن الوصول إليه إلا من داخل تلك الدالة. فكر فيه كغرفة خاصة في منزلك، محتوياتها تخصك وحدك.

لنوضح بمثال:

const appName = "My Awesome App"; // متغير عام (Global)

function showMessage(userName) {
  const message = "Welcome, " + userName; // متغير محلي (Local)
  console.log(message + " to " + appName); // يمكن الوصول للاثنين هنا
}

showMessage("Ahmed"); // يطبع: "Welcome, Ahmed to My Awesome App"

// console.log(message); // خطأ! Error! message is not defined

في هذا المثال:

  • appName هو متغير عام، لذلك استطاعت دالة showMessage قراءته واستخدامه.
  • message هو متغير محلي، وُلد داخل الدالة وسيموت بمجرد انتهاء تنفيذها. محاولة الوصول إليه من الخارج ستؤدي إلى خطأ.

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


3. لماذا يهم هذا؟ من الفوضى إلى النظام

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

فوائد استخدام الدوال والنطاق بفعالية:

  1. القابلية للقراءة (Readability): عندما تقسم كودك إلى دوال صغيرة ذات أسماء واضحة (getUserProfile, validateEmail, sendInvoice)، يصبح كودك قصة يمكن قراءتها وفهمها، بدلاً من كونه كتلة غامضة من الأوامر.
  2. إعادة الاستخدام (Reusability): بنيتَ دالة validateEmail مرة واحدة؟ يمكنك الآن استخدامها في صفحة التسجيل، صفحة تعديل الملف الشخصي، وفي أي مكان آخر يحتاج إلى التحقق من البريد الإلكتر الإلكتروني. هذا هو مبدأ DRY في أفضل صوره.
  3. سهولة التصحيح (Debugging): عندما يحدث خطأ، فإن تقسيمه إلى دوال يسهل تحديد مصدر المشكلة. إذا كانت الفواتير لا تُرسل، فمن المحتمل أن المشكلة تكمن في دالة sendInvoice. يمكنك التركيز على هذه “الآلة” الصغيرة بدلاً من البحث في آلاف الأسطر من الكود المتشابك.
  4. العزل (Isolation): بفضل النطاق المحلي، تعمل كل دالة في عالمها الخاص. يمكنك أن تكون واثقاً من أن المتغيرات داخل دالة calculateShippingCost لن تتداخل بطريق الخطأ مع المتغيرات في دالة updateInventory. هذا يمنع سلسلة من الأخطاء الكارثية التي يصعب تتبعها.

تجاهل هذه المبادئ هو أسرع طريق لكتابة “الكود السباغيتي” (Spaghetti Code) - كود متداخل ومعقد لدرجة أنك تخاف من لمسه أو تعديله. المبرمج المحترف لا يكتب كوداً يعمل فقط، بل يكتب كوداً يمكن لآخرين (ولنفسه في المستقبل) فهمه وتطويره بسهولة.


4. نصائح عملية: كيف تبني دوالاً عظيمة

المعرفة النظرية لا تكفي. إليك قواعد عملية لتطبيقها فوراً في عملك:

  1. الدالة تؤدي مهمة واحدة فقط (Single Responsibility Principle): يجب أن يكون اسم الدالة وصفاً دقيقاً لما تفعله. إذا وجدت نفسك تسمي دالة getUserAndValidateAndSave، فهذه علامة حمراء. يجب تقسيمها إلى ثلاث دوال: getUser(), validateUser(), saveUser().
  2. اجعل أسماء الدوال أفعالاً: يجب أن تدل أسماء الدوال على حركة أو إجراء. استخدم calculate..., fetch..., is..., has.... هذا يجعل الكود أسهل للقراءة. isUserValid() أفضل من userValidation().
  3. قلل عدد المدخلات (Parameters): الدالة التي تأخذ 7 مدخلات هي دالة معقدة وصعبة الاستخدام. إذا وجدت نفسك في هذا الموقف، فربما يجب أن تمرر “كائناً” (Object) واحداً يجمع كل هذه المدخلات معاً.
  4. تجنب المتغيرات العامة (Global Variables) كأنها الطاعون: المتغيرات العامة تجعل تتبع تدفق البيانات في تطبيقك كابوساً. لا تستخدمها إلا للثوابت التي لا تتغير أبداً (مثل اسم التطبيق أو إعدادات أساسية). دائماً مرر البيانات التي تحتاجها كمدخلات للدالة.
  5. اكتب “دوال نقية” (Pure Functions) كلما أمكن: الدالة النقية هي التي إذا أعطيتها نفس المدخلات، ستعطيك دائماً نفس المخرجات، وليس لها “آثار جانبية” (Side Effects) مثل تعديل متغير عام أو الكتابة في ملف. دالة calculateTotalPrice مثال جيد. هذه الدوال هي الأسهل للاختبار والفهم.

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

في الفصل القادم: بعد أن تعلمنا كيفية تنظيم الأوامر، سنتعلم كيفية تنظيم البيانات. سنتحدث عن المصفوفات والمجموعات (Arrays & Collections)، الحاويات التي نضع فيها متغيراتنا.

×

إعدادات القراءة

الوضع الليلي
حجم الخط 20px
نوع الخط
×

فهرس الكتاب