تعلّم بايثون في عطلة نهاية الأسبوع: من الصفر إلى مشروع متكامل
كيف يمكننا تعلم لغة برمجة جديدة بسرعة؟ في هذه المقالة، سنشارك تجربتنا في نهاية الأسبوع في تعلم بايثون من خلال بناء مشروع متكامل.
المقدمة
Logto، كخدمة هوية، يوفر تجربة سلسة عبر لغات البرمجة والأطر المختلفة أمر ضروري. وغالباً ما يتضمن ذلك إنشاء مجموعات تطوير البرمجيات (SDKs). ومع ذلك، عندما تكون لغة البرمجة خارج منطقنا التقني ويفتقد فريقنا الخبرة، يصبح إنشاء SDK قوي تحدياً.
وشكّلت بايثون مثل هذا التحدي لنا. على الرغم من وجود العديد من مستخدمي بايثون، لم نكن نمتلك SDK لبايثون، وهو أمر كان يثير القلق باستمرار. قررت معالجة هذا، وبدأت في سد هذه الفجوة.
على الرغم من أن لدي سنوات من الخبرة البرمجية، إلا أن بايثون يبقى منطقة غير مستكشفة بالنسبة لي. بينما كنت قد لعبت ببايثون 2 لفترة وجيزة لكتابة نصوص بسيطة منذ سنوات، كانت معرفتي قديمة. ومع ذلك، كان الوقت قد حان للتعمق!
اليوم 1: وضع الأساس
تحديد الهدف
في تجربتي، النهج الأكثر فعالية لتعلم لغة برمجة جديدة هو بناء مشروع متكامل. لحسن الحظ، كان هدفنا واضحاً: بناء SDK لبايثون لتطبيقات الويب لLogto.
بدلاً من القفز إلى الشيفرة البرمجية، دعونا نقسم الأمر. إليك القائمة:
- إنشاء عميل Logto لمهام مثل تسجيل الدخول، تسجيل الخروج، معلومات المستخدم، وإدارة الرموز.
- توفير دليل إرشادي ومشروع أمثلة لعرض استخدام SDK.
- نشر SDK في مكان ما بحيث يمكن للمستخدمين تثبيته بسهولة.
يبدو أن المهمة 1 بها العمل الأكثر، لذا نحتاج إلى تأكيد النطاق ومتابعة تقسيمه. هذه الخطوة ضرورية لتأمين حدود المشروع، وتجنب توسع النطاق والهندسة المفرطة.
عمل الفريق السابق وفر لي الكثير من الوقت:
- اتفاقية SDK توضح الهيكل وتصميم واجهة برمجة التطبيقات (API) للSDKs.
- SDKs الموجودة للغات مختلفة وفرت رؤى حول الأنماط والتحسينات المحتملة لبايثون.
بالاعتماد على هذه الموارد، يمكنني رؤية صورة واضحة لما يجب القيام به. بينما التفاصيل أبعد من نطاق هذه المقالة، دعونا نمضي قُدماً.
إعداد البيئة
أستخدم جهاز Mac، لذا فإن بايثون مثبت بالفعل. مع ذلك، كنت أتساءل عما إذا كان هناك طريقة أفضل لإدارة إصدارات بايثون (لقد سمعت ألم توافق الإصدار)، تماماً مثل nvm
لNode.js. سرعان ما وجدت pyenv وبدأت مباشرة في تثبيته.
المهمة التالية على جدول الأعمال: مدير الحزم والاعتمادات. عادة ما يكونان مرتبطين. فلماذا لا pip
(الإعداد الافتراضي لبايثون)؟ إذا ألقيت نظرة على requirements.txt
، ستجد أنه مجرد قائمة بحزم مع إصدارات. هذا ليس كافياً لSDK الذي قد يستخدمه مشاريع أخرى. على سبيل المثال، قد نحتاج إلى إضافة بعض الحزم للتطوير ولكن لا نريد تضمينها في SDK النهائي. requirements.txt
بسيط جداً للتعامل مع هذا.
أحد الفوائد عندما يكون لديك لغات برمجة أخرى في منطقك التقني هو أنه يمكنك البحث عن "المكافئ لبايثون". لذا بحثت عن "المكافئ لحزمة.json لبايثون" ووجدت Poetry كمرشح رائع:
- يعمل كمدير للحزم، مدير للاعتمادات، ومدير للبيئات الافتراضية.
- يحتوي على ملف
pyproject.toml
، شبيه بـpackage.json
في Node.js. - يستخدم ملف القفل لتسجيل إصدارات الاعتماد الدقيقة.
غالباً ما تُشمل واجهات الأوامر الحديثة (CLI) على أمر init
الذي يتم تخصيصه للمشاريع الجديدة. كذلك يتم فعل الشيء نفسه مع Poetry. قمت بتشغيل الأمر وأنشأ لي ملف pyproject.toml
.
أول سطر من الكود
وأخيراً، حان الوقت لكتابة الكود. البداية ببرنامج "Hello, World!" الكلاسيكي دائماً اختيار جيد. عند تعلم لغة برمجة جديدة، لا تكون البيئات المتكاملة للتطوير (IDE) الضرورية دائماً؛ محرر مدعوم من مجتمع قوي، مثل VS Code، يكون كافٍ تماماً.
بالنظر إلى أن تركيز SDK على تطبيقات الويب، بدأت بخادم ويب بسيط باستخدام إطار العمل الشهير Flask.
باستخدام قدرات Poetry، يمكن تثبيت Flask ببساطة عن طريق تشغيل poetry add flask
. ثم، باتباع دليل البدء السريع الرسمي لـ Flask، قمت بتأليف ملف 'hello.py' مع المقتطف التالي:
تشغيل الخادم عبر flask --app hello run
و التنقل إلى http://localhost:5000 على المتصفح أدى إلى النتيجة المطلوبة. لقد نجح!
كمبتدئ، لم أكن مستعجلًا لكتابة المزيد من الكود. بدلاً من ذلك، هناك الكثير من المعلومات التي يجب استيعابها من مقتطف الكود:
- استخدام
from x import y
لاستيراد وحدة أو صنف. - لا توجد فاصلة منقوطة لإنهاء الأسطر (يا لهول).
- يمكننا تعريف متغير جديد بإدخال اسم تعسفي وتخصيص قيمة له.
- إنشاء مثيل للصنف دون استخدام الكلمة المحجوزة
new
. - بايثون يدعم المزينات، و
@app.route
يعمل كمزين يسجل دالة كموجه للطرق.- يتم تفسير قيمة الإرجاع للدالة كجسم الاستجابة.
- يمكننا تعريف دالة باستخدام الكلمة المحجوزة
def
.
كما ترى، إذا حاولنا فهم كل سطر من الكود بدلاً من "جعل الأمر يعمل فقط"، يمكننا أن نتعلم الكثير من خلاله. في الوقت ذاته، وثائق Flask الرسمية شرحت المقتطف بتفصيل.
بدء المشروع
الآن حان الوقت لبدء المشروع. قريبًا قمت بتعريف صنف LogtoClient
وحاولت إضافة بعض الخصائص والأساليب للشعور باللغة:
بعد ذلك، دمج الصنف مع Flask:
بدأ يبدو الأمر كمشروع حقيقي. لكنني شعرت أن شيئًا ما ينقص: نظام النوع.
نظام النوع
نظرًا لأنه SDK، فإن تضمين نظام النوع سيساعد المستخدمين على فهم API وتقليل فرصة الأخطاء عند التطوير.
قدم بايثون إرشادات النوع في الإصدار 3.5. ليس بقدر قوة TypeScript، لكنه أفضل من لا شيء. أضفت بعض إرشادات النوع إلى صنف LogtoClient
:
يبدو الأمر أفضل بكثير الآن. لكن التحدي ظهر عندما يتعلق الأمر بنوع معقد مثل كائن ذو مفاتيح محددة مسبقًا. على سبيل المثال، نحتاج إلى تعريف صنف LogtoConfig
لتمثيل كائن الإعدادات:
يبدو هذا جيداً، لكننا قريبًا نحتاج إلى مواجهة مشاكل الترميز وفك الترميز والتحقق من الكائن من JSON.
بعد بعض البحث، اخترت pydantic كحل. إنها مكتبة تحقق من البيانات التي تعمل مع إرشادات النوع. وتدعم وظائف JSON متنوعة دون اتباع شيفرة نموذجية قابلة للتكرار.
وهكذا، يمكن إعادة كتابة صنف LogtoConfig
كما يلي:
كما علَّمتني عن الوراثة بين الأصناف في بايثون من خلال إضافة أقواس بعد اسم الصنف.
العمليات غير المتزامنة
ضمن SDK Logto، نحتاج إلى إجراء طلبات HTTP إلى خادم Logto. إذا كان لديك خبرة مع JavaScript، فإن عبارة "جحيم الاستدعاء البيني" قد ترن في ذهنك. إنها مشكلة شائعة عند التعامل مع العمليات غير المتزامنة. تقدم لغات البرمجة الحديثة حلولاً مشابهة مثل Promise
أو coroutine
.
لحسن الحظ، تمتلك بايثون حلاً مدمجًا للـ async
و await
. قبل استخدامها، تأكد من التوافق مع الأطر الشائعة. في Flask، يمكن القيام بذلك بتثبيت async
الإضافي واستخدام async def
بدلاً من def
:
ثم يمكننا استخدام await
لانتظار نتيجة العملية غير المتزامنة.
طلبات HTTP
طلبات HTTP موضوع شيق. تقريبًا كل لغة برمجة تمتلك حلاً أصليًا، ولكن عادة ما يستخدم المطورون مكتبة طرف ثالث لتيسير الاستخدام. بعض الأمثلة:
- JavaScript:
XMLHttpRequest
مقابلfetch
مقابلaxios
- Swift:
URLSession
مقابلAlamofire
- Java:
HttpURLConnection
مقابلOkHttp
وهذا صحيح أيضًا لبايثون. قراري كان استخدام aiohttp لدعمها لـ async
و await
، إلى جانب شعبيتها.
سحر Copilot
قبل Copilot، الآن يجب أن نأتي إلى الجزء الشاق من كتابة منطق الأعمال. بمساعدة اتفاقية SDK وSDKs الأخرى، يمكنني كتابة تعليقات وصفية لكل أسلوب قبل كتابة الكود.
يُضيف مزيدًا من وضوح الشيفرة البرمجية، كما يساعد المطورين على فهم API مباشرة في بيئة التطوير المتكاملة أو المحرر عبر الذكاء البرمجي.
على سبيل المثال، ضع في اعتبارك أسلوب generateCodeChallenge
، يمكن كتابة التعليقات كما يلي:
هذا كان دعوة ممتازة للنماذج اللغوية الكبيرة (LLMs): تجميع التعريفات للأساليب بواسطة تعليقات واضحة. ولم يُخفق Copilot:
قد تكون هناك حاجة إلى بعض التعديلات، لكن لا يهم. لقد غيرت اللعبة بالفعل.
ختام اليوم
هذا هو التقدم الذي تم تحقيقه في اليوم الأول بشكل كبير. كان يوماً طويلاً، لكن بإستخدام الأدوات والتقنيات الحديثة، كان أفضل بكثير مما توقعت.
اليوم 2: رفع المعايير
استناداً إلى عمل اليوم الأول، تم إتمام منطق الأعمال بسرعة. لكن بالنسبة للـ SDK، فإنه لا يزال غير كافٍ. ها هي المهام لليوم الثاني:
- إضافة اختبارات الوحدة.
- فرض تنسيق الشيفرة البرمجية.
- التحقق من توافق إصدار بايثون.
- إضافة التكامل المستمر.
- نشر SDK.
اختبارات الوحدة
اختبارات الوحدة أنقذتنا عدة مرات، لذا لن أتخطاها. ها هي الاعتبارات الشائعة عند كتابة اختبارات الوحدة:
- كيفية تنظيم وتشغيل الاختبارات؟
- كيفية التحقق من النتيجة؟
- كيفية تشغيل الاختبارات غير المتزامنة؟ (يبدو الأمر بديهياً، لكنه يسبب أحياناً مشاكل في بعض اللغات.)
- كيفية محاكاة الاعتمادات؟ (لا تدخل في هذا الموضوع حتى يكون لا غنى عنه، لأنه يمكن أن يؤدي إلى حفر الأرانب).
- كيفية توليد تقارير تغطية الكود؟
مع هذه الأسئلة في الاعتبار، وجدت أن الوحدة الافتراضية unittest
قصيرة في بعض الحالات. لذا اخترت pytest كإطار اختبار. يدعم الاختبارات غير المتزامنة ويبدو ناضجًا بما يكفي.
كشف الرحلة بعض المفاهيم الجديدة المثيرة مثل fixture
بالنسبة لي. يمكن أن يستفيد هذا أيضًا من طريقة التفكير عند كتابة الشيفرة البرمجية بلغات أخرى.
تنسيق الشيفرة البرمجية
لكل لغة أنماط تنسيق شيفراتها البرمجية الخاصة. بالنسبة لي، فإن التنسيق المتسق يمكن أن يجعلني سعيداً ومرتاحاً؛ كما أنه مفيد للمراجعة والتعاون.
بدلاً من تصفح الجدل حول