مراجعة الكود في JavaScript: ما الذي يجب التحقق منه حتى لا ينهار الكود
\n\nهل سبق لك أن فتحت طلب سحب (pull request) لشخص آخر وشعرت بأن كل شيء بداخلك ينكمش؟ وكأنك تنظر إلى كتلة متشابكة من الأسلاك، حيث كل عقدة هي خطأ محتمل. مراجعة الكود في JavaScript ليست مجرد علامة في متتبع المهام. إنها خط دفاعك الأخير ضد الفوضى. خاصة في عالم JS الديناميكي، حيث الكتابة (typing) مجرد وهم، والسلوك "السحري" هو القاعدة.
\n\nفي هذه المقالة، سأخبرك بما يجب أن تركز عليه حقًا عند مراجعة كود JavaScript. انسَ الجدالات غير المجدية حول علامات التبويب مقابل المسافات. سنتحدث عن الأمور التي تؤثر بشكل مباشر على الاستقرار، وقابلية القراءة، والأداء. هذه هي قائمة مراجعة مراجعة الكود التي أستخدمها بنفسي.
\n\n1. نقاء الوظائف وغياب الآثار الجانبية
\n\nالنقطة الأولى والأكثر أهمية. يجب أن تقوم الوظيفة بشيء واحد فقط وتقوم به بشكل جيد. إذا رأيت وظيفة تقوم في نفس الوقت بالتحقق من صحة البيانات، وإرسال طلب إلى الخادم، وتحديث الحالة العامة (global state) - فهذا جرس إنذار.
\n\nما الذي يجب التحقق منه:
\n- \n
- عدد الوسائط: المثالي هو 0، والحد الأقصى هو 3. إذا كان أكثر، فقم بتجميعها في كائن إعدادات (config object). \n
- تغيير البيانات المدخلة: يجب ألا تقوم الوظيفة بتعديل المصفوفة أو الكائن الذي تم تمريره. هذا خطأ صعب التتبع. \n
- الآثار الجانبية: أي تغيير في العالم الخارجي (console.log، الكتابة في ملف، تغيير DOM) يجب أن يكون صريحًا ومبررًا. \n
مثال سيئ:
\nlet totalUsers = 0;\n\nfunction processUsers(users) {\n for (let i = 0; i < users.length; i++) {\n users[i].active = true; // تغيير البيانات المدخلة!\n totalUsers++; // تأثير جانبي!\n console.log(users[i]); // تأثير جانبي آخر\n }\n return users;\n}\n\nمثال جيد:
\nfunction activateUsers(users) {\n return users.map(user => ({ ...user, active: true }));\n}\n\n// الاستخدام:\nconst activeUsers = activateUsers(users);\nconsole.log(`تم التفعيل: ${activeUsers.length}`);\n\nتذكر: الوظائف النقية هي أساس الكود القابل للتوقع. إذا رأيت تغييرًا للبيانات أثناء مراجعة الكود - فلا تتردد في كتابة تعليق. هذا أحد الأسباب الرئيسية للأخطاء صعبة التتبع في JavaScript.
\n\n2. عدم التزامن: Promises و async/await
\n\nJS هو ملك عدم التزامن، ولكنه أيضًا ملك جحيم الاستدعاءات (callback hell). أثناء المراجعة، انتبه لكيفية معالجة العمليات غير المتزامنة. فحص كود JavaScript دون تحليل سلاسل الـ Promises هو مجرد مضيعة للوقت.
\n\nالأعلام الحمراء:
\n- \n
- غياب معالجة الأخطاء: لا يوجد
.catch()أوtry/catch. عاجلاً أم آجلاً، سيتسبب هذا في تعطل التطبيق. \n - الـ Promises المتداخلة: إذا رأيت
.then()داخل.then()- فهذا سبب لإعادة الهيكلة. \n - نسيان
await: الوظيفة مُعلَمة كـasync، ولكن داخلها استدعاءات بدونawait. النتيجة ستكون undefined بدلاً من البيانات. \n
مثال سيئ (غياب معالجة الأخطاء):
\nasync function fetchUserData(userId) {\n const response = await fetch(`/api/users/${userId}`);\n const data = await response.json();\n return data;\n}\n\nمثال جيد:
\nasync function fetchUserData(userId) {\n try {\n const response = await fetch(`/api/users/${userId}`);\n if (!response.ok) {\n throw new Error(`خطأ HTTP! الحالة: ${response.status}`);\n }\n return await response.json();\n } catch (error) {\n console.error('خطأ في تحميل المستخدم:', error);\n throw error; // نعيد رمي الخطأ، ولكن نسجله\n }\n}\n\nنصيحة للمراجع: اطلب دائمًا شرحًا لسبب عدم استخدام try/c