مراجعة الكود في Go: ما يجب التحقق منه وكيفية تقديم الملاحظات عمليًا

مدرب بايثون أونلاين للمبتدئين

تعلم Python بسهولة دون إرهاق نظري. حل مهام عملية مع التحقق التلقائي واكتب الكود مباشرة في المتصفح.

ابدأ الدورة

مقدمة: لماذا مراجعة الكود في Go ليست مجرد علامة اختيار

\n

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

\n

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

\n\n

1. ما يجب التحقق منه أولاً: من بناء الجملة إلى الأخطاء

\n

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

\n\n

1.1. معالجة الأخطاء (error handling)

\n

Go لا يستخدم الاستثناءات - يتم إرجاع الأخطاء كقيم. مشكلة شائعة: المطور يتجاهل الخطأ المرتجع باستخدام _. هذا مقبول فقط في حالات نادرة (مثل fmt.Println).

\n
// سيء: تجاهل الخطأ\nresp, _ := http.Get("https://api.example.com/data")\n\n// جيد: معالجة الخطأ\nresp, err := http.Get("https://api.example.com/data")\nif err != nil {\n    log.Printf("فشل في الحصول على البيانات: %v", err)\n    return err\n}\ndefer resp.Body.Close()
\n

ما يجب التحقق منه:

\n
    \n
  • هل تمت معالجة جميع الأخطاء (وليس فقط _)؟
  • \n
  • هل تم استخدام defer لإغلاق الموارد (الملفات، الاتصالات)؟
  • \n
  • هل يتم "ابتلاع" الأخطاء في goroutines؟
  • \n
\n\n

1.2. التسمية والأسلوب (Go idioms)

\n

Go يتطلب الإيجاز: camelCase للخاص، PascalCase للعام. تجنب "التدوين الهنغاري" والأسماء الطويلة.

\n
// سيء\nfunc GetUserDataFromDatabase(userID int) (*UserData, error)\n\n// جيد\nfunc GetUser(id int) (*User, error)
\n

الأعلام الحمراء:

\n
    \n
  • أسماء متغيرات مثل temp، data، val (عامة جدًا).
  • \n
  • دوال أطول من 30-40 سطرًا (تحتاج للتقسيم).
  • \n
  • غياب التعليقات على الدوال العامة (هذا مطلب golint).
  • \n
\n\n

1.3. Goroutines والمزامنة

\n

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

\n
// سيء: سباق البيانات (data race)\nvar counter int\nfor i := 0; i < 100; i++ {\n    go func() {\n        counter++ // غير آمن\n    }()\n}\n\n// جيد: استخدام mutex\nvar mu sync.Mutex\nvar counter int\nfor i := 0; i < 100; i++ {\n    go func() {\n        mu.Lock()\n        counter++\n        mu.Unlock()\n    }()\n}
\n

ما يجب التحقق منه:

\n
    \n
  • هل يوجد sync.Mutex أو atomic للبيانات المشتركة؟
  • \n
  • هل تم نسيان إغلاق القناة (close(ch))؟
  • \n
  • هل هناك "تسرب" للـ goroutines (لا يوجد select مع مهلة)؟
  • \n
\n\n

2. الفحوصات المعمارية: من الواجهات إلى الحزم

\n

بعد بناء الجملة الأساسي، ننظر إلى هيكل الكود. Go يشجع التركيب (composition) بدلاً من الوراثة.

\n\n

2.1. الواجهات: صغيرة وعلى جانب المستهلك

\n

في Go، يتم تنفيذ الواجهات ضمنيًا. الواجهة الجيدة تحتوي على 1-3 طرق. تحقق مما إذا كان المؤلف يحاول إنشاء واجهة "شاملة".

\n
// سيء: واجهة ضخمة\ntype Storage interface {\n    Save(data []byte) error\n    Load(id string) ([]byte, error)\n    Delete(id string) error\n    List() ([]string, error)\n    Connect() error\                

المدونات

توصيات الكتب