AICODEAgentic Programming · 67723 · 2026-7

Week 5 · video 6 of 8 · transcript

Type Checking

ترجمة آلية لم يراجعها إنسان.AI translation, not reviewed by a person.

0:00

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

0:18

الأمثلة في هذا الفيديو بلغة Python. والأفكار نفسها تنطبق على لغات أخرى، وسنرى أيضًا كيف نفحص TypeScript. هذه وحدة فوترة صغيرة. الدالة total تأخذ قائمة أسعار وتجمعها. وفي مكان آخر، يستدعيها أحدهم بسعر واحد بدل قائمة. Python لغة ذات أنواع ديناميكية، أي أن أنواع القيم تُفحص أثناء تشغيل البرنامج. وتعمل JavaScript و Ruby ولغات كثيرة أخرى بالطريقة نفسها. لذلك حين تشغّلون هذا الملف بـ Python، لا شيء يعترض مسبقًا على ذلك الاستدعاء. بل يفشل حين يُنفَّذ السطر أول مرة، وقد يحدث ذلك في بيئة الإنتاج. الآن شغّلوا أداة فحص ساكن للأنواع على كود Python الموصَّف نفسه. تقرأ الأداة الاستدعاء قبل تشغيل البرنامج، فترى أن الرقم الواحد ليس قائمة أرقام، وتُبلغ عن خطأ. لم يُشغَّل أي شيء حتى تلك اللحظة. في لغة ذات أنواع ساكنة، مثل Java، يكون هذا الفحص جزءًا من تصريف البرنامج. أما Python فتفحص هذه العملية عند تنفيذها. وإضافة أداة فحص ساكن للأنواع تتيح لكم أيضًا اكتشاف عدم التطابق قبل تشغيل البرنامج.

1:26

أداة فحص الأنواع واحدة من عدة فحوصات تعطي تغذية راجعة عن التغيير. ومن الفروق بينها الوقت الذي يحتاجه كلٌّ منها ليعطي نتيجته. تحلّل أداة فحص الأنواع الكود دون تشغيل التطبيق. في مشروع صغير، أو في تشغيل تزايدي، يمكنها الإبلاغ عن عدم التطابق في أقل من ثانية. أما مجموعة الاختبارات فتنفّذ الكود لتتحقّق من سلوكيات محدّدة. المجموعة الصغيرة قد تستغرق ثواني، والكبيرة قد تستغرق دقائق. تتيح التغذية الراجعة السريعة للوكيل أن يكتشف الأخطاء ويصلحها ما دام التغيير الذي سبّبها صغيرًا. الفحص الذي يستغرق ثانية واحدة سهل التشغيل بعد كل تعديل، والأنواع والاختبارات السريعة والـ linters كلها تخدم هذه الحلقة الداخلية. لكن السرعة ليست الفائدة الأساسية لأداة فحص الأنواع. في مشروع كبير، قد يستغرق فحص الأنواع الكامل وقتًا أطول من بضعة اختبارات سريعة. ما تضيفه أداة الفحص هو التغطية. فهي تفحص كل استدعاء في الكود الخاضع للفحص، بما في ذلك الاستدعاءات في مسارات لا ينفّذها أي اختبار.

2:25

تحصل Python على الفحص الساكن عبر الأنواع التدريجية. والأنواع التدريجية (gradual typing) تعني أن الكود ذا الأنواع والكود بلا أنواع يعملان معًا في برنامج واحد، فتضيفون أنواعًا لبعض الأجزاء ويبقى الباقي بدونها. في Python، تُكتب هذه الأنواع على شكل توصيفات (annotations). هنا وُصِّف المُعامِل prices بأنه قائمة من قيم float. لا تفرض Python توصيفات الأنواع هذه حين تستدعون الدالة. فالرقم الواحد يصل إلى الدالة رغم ذلك، وهناك يفشل الجمع. أما أداة فحص الأنواع المنفصلة فتحلّل الكود وتوصيفاته. ويمكنها تتبّع الأنواع عبر استدعاءات الدوال دون تنفيذ تلك الاستدعاءات. يمكنكم تبنّي الفحص ملفًا بعد ملف. افتراضيًا، يتخطّى mypy أجسام الدوال التي بلا توصيفات. أما الوضع الصارم فيفحص تلك الأجسام، ويُبلغ أيضًا عن التوصيفات الناقصة. وإضافة التوصيفات تعطيه أنواعًا أدقّ ليفحصها. وبالمثل، تضيف TypeScript الفحص الساكن إلى JavaScript. وتُحذف توصيفات الأنواع فيها عند إنتاج كود JavaScript.

3:29

في Python، شغّلوا mypy --strict . يجب أولًا تثبيت mypy في بيئة المشروع، على شكل اعتمادية تطوير مثلًا. النقطة تطلب من mypy أن يجد ملفات Python داخل المجلد الحالي ومجلداته الفرعية، مع مراعاة الملفات المستثناة. ويُبلغ mypy عن الاستخدامات غير المتوافقة في الكود الذي يفحصه. الوضع الصارم يناسب مشروعًا موصَّف الأنواع مسبقًا، مثل وحدة الفوترة هذه. في TypeScript، شغّلوا npx tsc --noEmit من مشروع ثُبّتت فيه TypeScript وضُبطت إعداداتها. الخيار --noEmit يفحص المشروع بحسب إعداداته دون إنتاج ملفات JavaScript. أما مستوى الصرامة فيُضبط بإعداد منفصل في ملف الإعدادات. هكذا تبدو رسالة الخطأ. ملف، ورقم سطر، والوسيط الخاطئ، ونوعه الفعلي، والنوع الذي كان متوقَّعًا. هذه تغذية راجعة مفيدة للوكيل. فهي تذكر النوع الذي كان سيناسب. كلتا الأداتين تحلّل ملفات المشروع المحدّدة دون تنفيذ التطبيق. وهذا يتيح لهما الإبلاغ عن عدم تطابق حتى في مسار لم تشغّلوه بأي اختبار.

4:35

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

5:30

والتوصيفات تسجّل أيضًا معلومات للقرّاء. الـ docstring يقول إن prices قائمة من قيم float، لكن لا شيء يتحقّق من هذا الوصف حين تتغيّر الدالة. أما التوصيف فيذكر النوع المتوقَّع نفسه بصيغة تستخدمها أداة الفحص. وأي عملية غير متوافقة في الكود الخاضع للفحص تُنتج خطأً، بدل أن تترك وراءها جملة لم تعد صحيحة فحسب. لنفترض أن total تغيّرت لتُعيد المجموع نصًّا منسَّقًا، وأن توصيفها يقول الآن إنها تُعيد string. الاستدعاء الذي ما زال يضرب المجموع بنسبة الضريبة يظهر عنده خطأ في التشغيل التالي لفحص الأنواع. لو كان نوع القيمة المُعادة موصوفًا في الـ docstring فقط، لما أنتج التغيير نفسه أي رسالة على الإطلاق. التوقيع توثيقٌ يُفحص في كل تشغيل لفحص الأنواع. وداخل الكود الخاضع للفحص، تُنتج الاستخدامات غير المتوافقة أخطاءً لا يُنتجها docstring عادي.

6:24

ولا تقتصر توصيفات الأنواع في Python على ذكر float أو string. فهي تستطيع أيضًا أن تعطي القيمة اسمًا يدلّ على معناها. الإحداثي x والإحداثي y كلاهما float، لكن الخلط بينهما خطأ برمجي حقيقي. والدالة NewType تُنشئ نوعًا مستقلًا لكلٍّ منهما. وفي وقت التشغيل يبقى كلٌّ منهما float عاديًا. لكن أداة الفحص تعامل X وY على أنهما نوعان مختلفان. لذلك حين يُمرَّر y مكان x في استدعاء، يُبلغ mypy عن ذلك، مع أن القيمتين كلتيهما float. والأمر نفسه ينطبق على مُعرِّف الزبون ومُعرِّف الطلبية، وكلاهما عدد صحيح. والاسم المستعار للنوع (type alias) يسمّي نوعًا أكبر. هنا المربّع زوج من الأرقام، ولوحة الشطرنج قاموس يربط المربّعات بالقطع. وبهذه الأسماء، يقول التوقيع إن الدالة piece_at تأخذ لوحة ومربّعًا. وتُعيد قطعة، أو None إذا كان المربّع فارغًا. الخط العمودي يُنشئ نوع اتحاد (union)، وهو نوع يقبل قيمة من هذا النوع أو ذاك. من يعملون على هذا الكود يتحدّثون عن لوحات ومربّعات، لا عن قواميس من الأزواج. والأسماء تجعل الكود يستخدم الكلمات نفسها. يرى القارئ Board وSquare، ولا يحتاج أبدًا إلى أن يستنتج أن قاموسًا من الأزواج يعني لوحة شطرنج. إذن، الأنواع المسمّاة تسجّل قصد المبرمج. فهي تخبر القارئ، والوكيلَ أيضًا، بما تمثّله كل قيمة، وأداة الفحص تُبقي الكود متّسقًا مع ذلك القصد.

7:52

والتغذية الراجعة من الأنواع سبب أيضًا لاختيار لغة ذات أنواع ساكنة عند العمل مع الوكلاء. وجدت دراسات على نماذج تكتب TypeScript أن معظم أخطاء التصريف لديها كانت أخطاء في الأنواع. تلك الدراسات تناولت كودًا كتبه نموذج دفعةً واحدة، قبل أن يشغّل أي أداة فحص. أما الوكيل الذي يشغّل أداة الفحص فيرى تلك الأخطاء ويصلحها قبل أن تروها أنتم. وهناك خيار آخر، هو البدء بلغة ذات أنواع ساكنة. أفادت GitHub بأن TypeScript صارت اللغة الأكثر استخدامًا لديها من حيث عدد المساهمين الشهريين، في أغسطس 2025. هذا التقرير يقيس الشعبية، لا أسبابها. والتغذية الراجعة من الفحص الساكن أحد الأسباب التي تجعل اللغة ذات الأنواع الساكنة مفيدة مع الوكلاء. إذن، أداة فحص الأنواع تلتقط معظم أخطاء التصريف التي ترتكبها النماذج حين تكتب كودًا ذا أنواع. وتعطي الوكيل تغذية راجعة محدّدة ليصلح تلك الأخطاء دون أن يطلب من نموذج آخر الحكم على الكود.

8:44

ومثال الفوترة يُظهر أيضًا ما تفوّته الأنواع. لنبدأ بالعقد. الدالة price_after_discount تأخذ سعرًا ونسبة مئوية، ويجب أن تُعيد السعر النهائي بعد خصم تلك النسبة. وهذا هو تنفيذها. سنجرّبها بسعر 100 وخصم 20%. يجب أن يصبح السعر 80. لكن هذا التنفيذ يُعيد 20، وهي قيمة الخصم، لا السعر بعد الخصم. أما mypy في الوضع الصارم فراضٍ تمامًا عن هذا الكود. الوسيطان كلاهما float، والقيمة المُعادة float، وكل استدعاء يعامل النتيجة على أنها السعر النهائي يحصل على رقم خاطئ. إذن، الأنواع تتحقّق من أن القيم تُستخدم بشكل متوافق. أما التحقّق من أن القيمة هي الصحيحة فمهمة الاختبار. ولهذا تتكامل فحوصات الأنواع واختبارات السلوك.

9:36

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

9:47 of video · 1,334 words · 11 slides← Back to the video