تطبيقات الهاتف وعبء تطويرها 😪
من الأشياء اللي كانت مطلوبة بكثرة من مستخدمي منصة باحث هي تطبيقات الهاتف للـ Android والـ iOS، وبما اني ما اشتغلت تطبيقات في حياتي إلا مشاريع الجامعة وما عندي ميزانية أجيب مطوّر يشتغلها وما عندي صديق يشتغل التطبيقات (وأنا كسول وما بدي أعمل APIs 😂) فكنت دائما أبتعد عن هذا الأمر.
مع بداية المنصة وفّرت PWA (زي ما هو الوضع في #قبيلة حاليا) ولكن المستخدم العادي ما بيعرف شو هو الـ PWA ولا كيف يثبته على الهاتف، وهذا من أكبر أسباب عدم انتشار الـ PWAs خارج نطاق المنتجات التقنية على حد علمي، وحتى المنتجات التقنية في الغالب تبدأ بـ PWA ثم تنتقل إلى تطبيق هاتف متكامل زي ما صار مع Linear مثلا.
إلى أن أتى الله بالفرَج على يد Rails 😎
تاريخيًّا، Rails فيها ميزة شغالة بشكل تلقائي اسمها Turbolinks، مهمتها انك بمجرد ما تكبس على رابط هي تجيب محتويات الصفحة اللي انت طلبتها وتستبدل الـ Body الخاص بالصفحة الحالية بالـ Body الجديد وتدمج الـ Head الحالي بالـ Head الجديد، فانت بتاخذ تأثير Single Page Application مجانا.
مع إطلاق الإصدار السابع من Rails، أُلغي الدعم عن Turbolinks في مقابل إصدار مكتبة Turbo واللي فيها نفس مميزات Turbolinks مع أشياء إضافية زي ميزة Prefetch بحيث ان المستخدم بمجرد ما يعمل Hover على رابط، Turbo بتعمله Prefetch ولما يضغط عليه، الصفحة بتتغير مباشرة بدون ما ينتظر، وهذا بيعطي إيحاء أن الموقع يستجيب بسرعة.
مكتبة Turbo كانت واحدة من 3 مكتبات أُطلقت تباعا مع الإصدار السابع من Rails وهي Turbo و Stimulus و Native. بطلة المنشور هي مكتبة Native واللي بناء على مميزات Turbo بتسمحلك تبني تطبيقات هجينة أو Hybrid بين الـ WebView والـ Native. بناء على مكتبة Native عملت تطبيقات باحث بأقل القليل من المعرفة في برمجتها واللي ممكن توصلها من هون:
- Android: https://bit.ly/baheth-google-play
- iOS: https://bit.ly/baheth-app-store
المميز إني مش محتاج أفتح APIs وكل التعديلات اللي بعملها على المنصة بتوصل للمستخدمين بدون ما أحتاج أرفع تحديث على المتاجر وقادر أدمج مميزات Native في التطبيقات زي الزر اللي بيفتح القائمة الجانبية أو أفتح نوافذ سفلية أو Bottom Sheets.
الزر على سبيل المثال هو Native ولكن بيفتح القائمة الموجودة في الـ WebView. طريقة الدمج بين المكونات الـ Native والـ WebView سهلة وما فيها تعقيدات كبيرة، ممكن تقرأ عنها من هون:
https://native.hotwired.dev/ios/bridge-components
بهذه الطريقة انت ممكن تطلع بتطبيق لشركتك أو مشروعك الشخصي بدون ما تتكلف تكاليف إضافية أو تجيب مطورين للهاتف ثم مع الوقت ممكن تتحول من الـ Hybrid إلى Native بالكامل، خصوصا وأن المكتبة نفسها تدعم الانتقال من الصفحات الـ Native إلى الـ WebView والعكس.
إذا حاب تشوف تطبيقات ثانية بتشتغل بنفس التقنية ممكن تشوف هذا الموقع:
https://turbonative.directory
والسلام عليكم 👋🏻
من الأشياء اللي كانت مطلوبة بكثرة من مستخدمي منصة باحث هي تطبيقات الهاتف للـ Android والـ iOS، وبما اني ما اشتغلت تطبيقات في حياتي إلا مشاريع الجامعة وما عندي ميزانية أجيب مطوّر يشتغلها وما عندي صديق يشتغل التطبيقات (وأنا كسول وما بدي أعمل APIs 😂) فكنت دائما أبتعد عن هذا الأمر.
مع بداية المنصة وفّرت PWA (زي ما هو الوضع في #قبيلة حاليا) ولكن المستخدم العادي ما بيعرف شو هو الـ PWA ولا كيف يثبته على الهاتف، وهذا من أكبر أسباب عدم انتشار الـ PWAs خارج نطاق المنتجات التقنية على حد علمي، وحتى المنتجات التقنية في الغالب تبدأ بـ PWA ثم تنتقل إلى تطبيق هاتف متكامل زي ما صار مع Linear مثلا.
إلى أن أتى الله بالفرَج على يد Rails 😎
تاريخيًّا، Rails فيها ميزة شغالة بشكل تلقائي اسمها Turbolinks، مهمتها انك بمجرد ما تكبس على رابط هي تجيب محتويات الصفحة اللي انت طلبتها وتستبدل الـ Body الخاص بالصفحة الحالية بالـ Body الجديد وتدمج الـ Head الحالي بالـ Head الجديد، فانت بتاخذ تأثير Single Page Application مجانا.
مع إطلاق الإصدار السابع من Rails، أُلغي الدعم عن Turbolinks في مقابل إصدار مكتبة Turbo واللي فيها نفس مميزات Turbolinks مع أشياء إضافية زي ميزة Prefetch بحيث ان المستخدم بمجرد ما يعمل Hover على رابط، Turbo بتعمله Prefetch ولما يضغط عليه، الصفحة بتتغير مباشرة بدون ما ينتظر، وهذا بيعطي إيحاء أن الموقع يستجيب بسرعة.
مكتبة Turbo كانت واحدة من 3 مكتبات أُطلقت تباعا مع الإصدار السابع من Rails وهي Turbo و Stimulus و Native. بطلة المنشور هي مكتبة Native واللي بناء على مميزات Turbo بتسمحلك تبني تطبيقات هجينة أو Hybrid بين الـ WebView والـ Native. بناء على مكتبة Native عملت تطبيقات باحث بأقل القليل من المعرفة في برمجتها واللي ممكن توصلها من هون:
- Android: https://bit.ly/baheth-google-play
- iOS: https://bit.ly/baheth-app-store
المميز إني مش محتاج أفتح APIs وكل التعديلات اللي بعملها على المنصة بتوصل للمستخدمين بدون ما أحتاج أرفع تحديث على المتاجر وقادر أدمج مميزات Native في التطبيقات زي الزر اللي بيفتح القائمة الجانبية أو أفتح نوافذ سفلية أو Bottom Sheets.
الزر على سبيل المثال هو Native ولكن بيفتح القائمة الموجودة في الـ WebView. طريقة الدمج بين المكونات الـ Native والـ WebView سهلة وما فيها تعقيدات كبيرة، ممكن تقرأ عنها من هون:
https://native.hotwired.dev/ios/bridge-components
بهذه الطريقة انت ممكن تطلع بتطبيق لشركتك أو مشروعك الشخصي بدون ما تتكلف تكاليف إضافية أو تجيب مطورين للهاتف ثم مع الوقت ممكن تتحول من الـ Hybrid إلى Native بالكامل، خصوصا وأن المكتبة نفسها تدعم الانتقال من الصفحات الـ Native إلى الـ WebView والعكس.
إذا حاب تشوف تطبيقات ثانية بتشتغل بنفس التقنية ممكن تشوف هذا الموقع:
https://turbonative.directory
والسلام عليكم 👋🏻
❤5
لا تضع افتراضات غير مدروسة وإلا ستندم 🙂
كان هذا شعار أحد الليالي وأنا في إجازة من العمل مع عدم وجود اتصالٍ جيدٍ بالانترنت 😂
يوجد مكتبة باسم Notable لإطار عمل Ruby on Rails مهمتها حفظ ومتابعة الأخطاء التي قد تحدث أثناء استخدام الموقع أو في الـ Background Jobs من خلال تخزين الخطأ وكل المعلومات المتعلقة به في قاعدة البيانات بشكل تلقائي، كل ما عليك فعله هو تثبيت المكتبة وإنشاء الجداول الخاصة بها في قاعدة البيانات.
بتاريخ 7 من شهر 4 سنة 2024 أضفت ميزة تسجيل الدخول باستخدام حساب Google لمنصة باحث، وكان هذا إنجازا بالنسبة لي لأنها المرة الأولى التي أعمل على شيء من هذا النوع في موقع من المواقع التي أبرمجها. إنتهيت من الميزة الجديدة وأعلنت عنها في مواقع التواصل الاجتماعي المرتبطة بمنصة باحث وانتهى الأمر.
بعد ذلك بخمسة أيام، تحديدا بتاريخ 12 من شهر 4 سنة 2024، وبكل براءة، دخلت على لوحة متابعة قاعدة البيانات الخاصة بمنصة باحث من باب الاطلاع على حجمها والتأكد من أن قاعدة البيانات في حالة جيدة، وكانت المفاجأة! حجم قاعدة البيانات تجاوز الـ 100GB على الرغم من أنها كانت أقل من 10GB قبل أيام قليلة.
المشكلة أن حجم قاعدة البيانات كان يزداد والمساحة التخزينية المتوفرة على الخادم تقل، وكنت أخشى أن لا أتمكن من الدخول عليه من خلال SSH بسبب الخطأ المشهور "No space left on device" 🥲 فكنت أفكر ما الذي حدث وأحاول تصفح باقي لوحات المتابعة في المنصة باتصال انترنت بطيئ، ولكن بدون أي تطوّر.
ثم قررت الهدوووء والبدء بالبديهيات، كم عدد الصفوف في كل جدول من جداول قاعدة البيانات؟ وكانت المفاجأة أن الصفوف في جدول مكتبة Notable تجاوزت عشرات الملايين، ويزداد بسرعة كبيرة جدا!
فتحت الـ Logs الخاصة بالمنصة ووجدت خطأً متكررا بكثرة وهو أن أحد المستخدمين يحاول تسجيل حساب جديد ولكن بدون تحديد الاسم الأول والاسم الأخير (وهي حقول مطلوبة) مما يتسبب في إضافة صف إلى جدول مكتبة Notable على أنه خطأ.
المشكلة الآن كيف يحدث هذا الخطأ؟ الـ Model الخاصة بالمستخدمين في المنصة بها خطوة للتحقق من وجود الحقول المطلوبة ويتم التعامل مع عدم وجودها بشكل صحيح من خلال الـ Controller، فمن أين يأتي هذا الخطأ؟ وكان رد الفعل الطبيعي هو مراجعة التعديلات الخاصة بميزة تسجيل الدخول باستخدام حساب Google 😁
عند تسجيل الدخول باستخدام OmniAuth، يُعطيك الـ Provider (في حالتنا Google) بيانات المستخدم التي طلبتها كالاسم الأول والأخير والبريد الالكتروني. كنت أستخدم هذه البيانات لإنشاء حساب المستخدم وتسجيل دخوله بشكل تلقائي في منصة باحث، وكنت "أفترض" أن الاسم الأول والأخير دائما موجودين في البيانات، وهنا كان الخطأ!
الاسم الأول والاسم الأخير قد تكون قيمتهم nil أو غير مُعرّفة، مما يسبب خطأً في إنشاء حساب المستخدم، ممكن يُرجع خطأً إلى الـ Provider (في حالتنا Google)، والـ Provider يحاول إعادة إرسال نفس الطلب مرة ثانية لباحث فيحدث نفس الخطأ، وهكذا دواليك في حلقة لا تنتهي، وملايين الأخطاء المتكررة دون توقف 😎
الحل السريع كان وضع قيمة افتراضية لحقول الاسم الأول والاسم الأخير بدلا من استخدام البيانات مباشرة من خلال OmniAuth، وحُلّت المشكلة ولله الحمد.
نظّفت قاعدة البيانات بعد ذلك وعادت إلى حجمها الطبيعي وتعلمت أن لا أفترض أي افتراضات غير مدروسة مرة أخرى...
والسلام عليكم 👋🏻
كان هذا شعار أحد الليالي وأنا في إجازة من العمل مع عدم وجود اتصالٍ جيدٍ بالانترنت 😂
يوجد مكتبة باسم Notable لإطار عمل Ruby on Rails مهمتها حفظ ومتابعة الأخطاء التي قد تحدث أثناء استخدام الموقع أو في الـ Background Jobs من خلال تخزين الخطأ وكل المعلومات المتعلقة به في قاعدة البيانات بشكل تلقائي، كل ما عليك فعله هو تثبيت المكتبة وإنشاء الجداول الخاصة بها في قاعدة البيانات.
بتاريخ 7 من شهر 4 سنة 2024 أضفت ميزة تسجيل الدخول باستخدام حساب Google لمنصة باحث، وكان هذا إنجازا بالنسبة لي لأنها المرة الأولى التي أعمل على شيء من هذا النوع في موقع من المواقع التي أبرمجها. إنتهيت من الميزة الجديدة وأعلنت عنها في مواقع التواصل الاجتماعي المرتبطة بمنصة باحث وانتهى الأمر.
بعد ذلك بخمسة أيام، تحديدا بتاريخ 12 من شهر 4 سنة 2024، وبكل براءة، دخلت على لوحة متابعة قاعدة البيانات الخاصة بمنصة باحث من باب الاطلاع على حجمها والتأكد من أن قاعدة البيانات في حالة جيدة، وكانت المفاجأة! حجم قاعدة البيانات تجاوز الـ 100GB على الرغم من أنها كانت أقل من 10GB قبل أيام قليلة.
المشكلة أن حجم قاعدة البيانات كان يزداد والمساحة التخزينية المتوفرة على الخادم تقل، وكنت أخشى أن لا أتمكن من الدخول عليه من خلال SSH بسبب الخطأ المشهور "No space left on device" 🥲 فكنت أفكر ما الذي حدث وأحاول تصفح باقي لوحات المتابعة في المنصة باتصال انترنت بطيئ، ولكن بدون أي تطوّر.
ثم قررت الهدوووء والبدء بالبديهيات، كم عدد الصفوف في كل جدول من جداول قاعدة البيانات؟ وكانت المفاجأة أن الصفوف في جدول مكتبة Notable تجاوزت عشرات الملايين، ويزداد بسرعة كبيرة جدا!
فتحت الـ Logs الخاصة بالمنصة ووجدت خطأً متكررا بكثرة وهو أن أحد المستخدمين يحاول تسجيل حساب جديد ولكن بدون تحديد الاسم الأول والاسم الأخير (وهي حقول مطلوبة) مما يتسبب في إضافة صف إلى جدول مكتبة Notable على أنه خطأ.
المشكلة الآن كيف يحدث هذا الخطأ؟ الـ Model الخاصة بالمستخدمين في المنصة بها خطوة للتحقق من وجود الحقول المطلوبة ويتم التعامل مع عدم وجودها بشكل صحيح من خلال الـ Controller، فمن أين يأتي هذا الخطأ؟ وكان رد الفعل الطبيعي هو مراجعة التعديلات الخاصة بميزة تسجيل الدخول باستخدام حساب Google 😁
عند تسجيل الدخول باستخدام OmniAuth، يُعطيك الـ Provider (في حالتنا Google) بيانات المستخدم التي طلبتها كالاسم الأول والأخير والبريد الالكتروني. كنت أستخدم هذه البيانات لإنشاء حساب المستخدم وتسجيل دخوله بشكل تلقائي في منصة باحث، وكنت "أفترض" أن الاسم الأول والأخير دائما موجودين في البيانات، وهنا كان الخطأ!
الاسم الأول والاسم الأخير قد تكون قيمتهم nil أو غير مُعرّفة، مما يسبب خطأً في إنشاء حساب المستخدم، ممكن يُرجع خطأً إلى الـ Provider (في حالتنا Google)، والـ Provider يحاول إعادة إرسال نفس الطلب مرة ثانية لباحث فيحدث نفس الخطأ، وهكذا دواليك في حلقة لا تنتهي، وملايين الأخطاء المتكررة دون توقف 😎
الحل السريع كان وضع قيمة افتراضية لحقول الاسم الأول والاسم الأخير بدلا من استخدام البيانات مباشرة من خلال OmniAuth، وحُلّت المشكلة ولله الحمد.
نظّفت قاعدة البيانات بعد ذلك وعادت إلى حجمها الطبيعي وتعلمت أن لا أفترض أي افتراضات غير مدروسة مرة أخرى...
والسلام عليكم 👋🏻
❤4
هل أنت بحاجة لاستخدام Managed services من الـ Cloud providers لمشروعك الجانبي أو شركتك الناشئة؟ 🤔
للتوضيح، قصدي بالـ Managed services أشياء مثل Auto-scaling في EC2 أو S3 لحفظ البيانات أو غيرها من الخدمات "السحابية" اللي كل الناس تتجه لها أول ما تحكيلها بدي أعمل مشروع جانبي أو شركة ناشئة بمنتج SaaS بسيط، والسبب من وجهة نظري يعود لعاملين:
- سهولة استخدام هذه الخدمات "في البداية"
- الخوف من المجهول إذا ما استخدمتها
عن نفسي، قبل سنتين إلى 3 سنوات، كانت كل مشاريعي موجودة في مكان واحد وهو Heroku، أيام ما كان يقدم حصة مجانية للمستخدمين، وكانت التجربة سهلة لأبعد الحدود، زي كإنك بتستخدم مستودع Git، مجرد ما تعمل عليه Push بكون موقعك جاهز للاستخدام خلال دقائق، التجربة لا مثيل لها في ذلك الوقت (شايفكم جماعة Vercel و Fly.io والشله 😁)
بعد ما صار Heroku مدفوع، استمريت في استخدامه لأشهر معدودة ثم قررت الانتقال لشيئ خارج Heroku والسبب كان بسيط، انا بدفع 15$ شهريا عشان اخذ 512MB ذاكرة و 512MB مساحة تخزين "للتطبيق فقط مش للملفات" و 2 workers، بأقل من هذا المبلغ ممكن تجيب 8GB ذاكرة و 80GB مساحة تخزين و 4 vCPUs من Hetzner على سبيل المثال.
ولكن واجهتني العوامل اللي ذكرتها في أول المنشور، Heroku كان سهل جدا، أنا مجرد بعمل Push وهو يهتم بباقي الأمور، فما كان عندي الخبرة الكافية للانتقال لشيئ أنا أعمله Manage بإيدي، وكنت خايف ما أعرف أستمر في متابعة المشاريع وتطويرها.
إلى أن لقيت خدمة https://hatchbox.io (وهذا إعلان غير مدفوع، للأسف 😂) وهي عبارة عن خدمة تعطيها مستودع Git الخاص بمشروعك المكتوب بـ Ruby on Rails وتختار الـ Cloud Provider اللي انت بتستخدمه زي Linode أو VULTR وهي تحجز الخادم وتعملك Deployment للمشروع تبعك والخدمات الإضافية اللي انت محتاجها زي قاعدة البيانات مثلا، فيك تعتبرها زي Heroku ولكن على أي خادم وبسعر 10$ بالشهر لكل خادم.
في البداية كان العرض ممتاز، انا بدفع على الخادم 5$ وبدفع 10$ لـ HatchBox وباخذ مواصفات أحسن من Heroku بنفس السعر، ولكن بعد فترة اضطريت أضيف خادمين إضافيين، فصرت أدفع 30$ تكاليف HatchBox، ونفسهم أو أكثر منهم بشوي تكاليف الخوادم، فحسيت اني لازم أتعلم كيف أستخدم هالخوادم مع نفسي وأطلع من HatchBox، خصوصا واني واجهت مشاكل خلال استخدام HatchBox وكنت بحلها واستفدت من التواصل مع الدعم الفني تبعهم.
في نفس هذه الفترة، الناس في 37Signals قررو الخروج من الـ Cloud كله وكتأثير جانبي، طلعولنا المكتبة الرهيبة بطلة هذا المنشور وهي Kamal، واللي ممكن تقرأ عنها وتشوف الـ Demo تبعها من هون:
https://kamal-deploy.org
كمال ببساطة بتحكيلك انت أكتب Dockerfile للمشروع تبعك، وعطيني وصول SSH على الخادم تبعك، وأنا بهتم بالباقي، بداية من بناء الـ Docker image وصولا إلى تشغيل الـ Containers الخاصة بالمشروع والخدمات الجانبية زي قاعدة البيانات وتجهيز الـ Reverse proxy وشهادات الـ SSL وكل هذه الأمور.
وفعلا بدأت الإنتقال من HatchBox إلى كمال، وكان الأمر سلس وسهل "لما فهمت كيف Docker بيشتغل"، والحمدلله نقلت كل مشاريعي على خوادم أنا بديرها وبدير كل خدماتها الجانبية من قواعد بيانات وتخزين ملفات.
قللت التكاليف ومواصفات خوادم أفضل وتعلمت أشياء ما كنت بفكر إني أتعلمها، وكالعادة العصافير تزقزق والسلام عليكم 👋🏻
ملاحظة: المنشور القادم تكملة لهذا المنشور 😎
للتوضيح، قصدي بالـ Managed services أشياء مثل Auto-scaling في EC2 أو S3 لحفظ البيانات أو غيرها من الخدمات "السحابية" اللي كل الناس تتجه لها أول ما تحكيلها بدي أعمل مشروع جانبي أو شركة ناشئة بمنتج SaaS بسيط، والسبب من وجهة نظري يعود لعاملين:
- سهولة استخدام هذه الخدمات "في البداية"
- الخوف من المجهول إذا ما استخدمتها
عن نفسي، قبل سنتين إلى 3 سنوات، كانت كل مشاريعي موجودة في مكان واحد وهو Heroku، أيام ما كان يقدم حصة مجانية للمستخدمين، وكانت التجربة سهلة لأبعد الحدود، زي كإنك بتستخدم مستودع Git، مجرد ما تعمل عليه Push بكون موقعك جاهز للاستخدام خلال دقائق، التجربة لا مثيل لها في ذلك الوقت (شايفكم جماعة Vercel و Fly.io والشله 😁)
بعد ما صار Heroku مدفوع، استمريت في استخدامه لأشهر معدودة ثم قررت الانتقال لشيئ خارج Heroku والسبب كان بسيط، انا بدفع 15$ شهريا عشان اخذ 512MB ذاكرة و 512MB مساحة تخزين "للتطبيق فقط مش للملفات" و 2 workers، بأقل من هذا المبلغ ممكن تجيب 8GB ذاكرة و 80GB مساحة تخزين و 4 vCPUs من Hetzner على سبيل المثال.
ولكن واجهتني العوامل اللي ذكرتها في أول المنشور، Heroku كان سهل جدا، أنا مجرد بعمل Push وهو يهتم بباقي الأمور، فما كان عندي الخبرة الكافية للانتقال لشيئ أنا أعمله Manage بإيدي، وكنت خايف ما أعرف أستمر في متابعة المشاريع وتطويرها.
إلى أن لقيت خدمة https://hatchbox.io (وهذا إعلان غير مدفوع، للأسف 😂) وهي عبارة عن خدمة تعطيها مستودع Git الخاص بمشروعك المكتوب بـ Ruby on Rails وتختار الـ Cloud Provider اللي انت بتستخدمه زي Linode أو VULTR وهي تحجز الخادم وتعملك Deployment للمشروع تبعك والخدمات الإضافية اللي انت محتاجها زي قاعدة البيانات مثلا، فيك تعتبرها زي Heroku ولكن على أي خادم وبسعر 10$ بالشهر لكل خادم.
في البداية كان العرض ممتاز، انا بدفع على الخادم 5$ وبدفع 10$ لـ HatchBox وباخذ مواصفات أحسن من Heroku بنفس السعر، ولكن بعد فترة اضطريت أضيف خادمين إضافيين، فصرت أدفع 30$ تكاليف HatchBox، ونفسهم أو أكثر منهم بشوي تكاليف الخوادم، فحسيت اني لازم أتعلم كيف أستخدم هالخوادم مع نفسي وأطلع من HatchBox، خصوصا واني واجهت مشاكل خلال استخدام HatchBox وكنت بحلها واستفدت من التواصل مع الدعم الفني تبعهم.
في نفس هذه الفترة، الناس في 37Signals قررو الخروج من الـ Cloud كله وكتأثير جانبي، طلعولنا المكتبة الرهيبة بطلة هذا المنشور وهي Kamal، واللي ممكن تقرأ عنها وتشوف الـ Demo تبعها من هون:
https://kamal-deploy.org
كمال ببساطة بتحكيلك انت أكتب Dockerfile للمشروع تبعك، وعطيني وصول SSH على الخادم تبعك، وأنا بهتم بالباقي، بداية من بناء الـ Docker image وصولا إلى تشغيل الـ Containers الخاصة بالمشروع والخدمات الجانبية زي قاعدة البيانات وتجهيز الـ Reverse proxy وشهادات الـ SSL وكل هذه الأمور.
وفعلا بدأت الإنتقال من HatchBox إلى كمال، وكان الأمر سلس وسهل "لما فهمت كيف Docker بيشتغل"، والحمدلله نقلت كل مشاريعي على خوادم أنا بديرها وبدير كل خدماتها الجانبية من قواعد بيانات وتخزين ملفات.
قللت التكاليف ومواصفات خوادم أفضل وتعلمت أشياء ما كنت بفكر إني أتعلمها، وكالعادة العصافير تزقزق والسلام عليكم 👋🏻
ملاحظة: المنشور القادم تكملة لهذا المنشور 😎
❤4👍1
تعقيبًا على منشور البارحة
ماذا استفدت خلال وبعد التحوّل من Heroku (وأشباهه) إلى إدارة الخوادم بشكل يدوي؟
🔸 أولا التكاليف | حاليا منصة باحث (ومشاريع غيرها كثير) موجودة على نفس الخادم بالمواصفات التالية:
- معالجات بعدد 16 (vCPU)
- ذاكرة بحجم 128GB
- مساحة تخزينية بحجم 2TB
هذه المواصفات لو بدك تجيبها من مكان زي Fly.io رح تدفع 1000$ شهري تقريبا، في المقابل انت ممكن تجيبها من Hetzner بحدود 100$ (الحسابات مش دقيقة 100% ولكن تقريبيًّا).
🔸 ثانيا التعلّم | خلال هذه التجربة تعلّمت أمور كثيرة جدا، منها:
- إدارة الخوادم (ولو بشكل بسيط)
- تعلّمت Docker وكيف بيشتغل واستخداماته
- كتابة Scripts بتحكي مع الخادم وبتنقل البيانات عليه
- تجهيز لوحات متابعة لموقعك وإضافاته زي قاعدة البيانات
- فهم أكبر لإدارة موارد الخوادم
- كل ما يتعلق بالـ Domains وشهادات SSL
وغيرها من الأمور اللي انت في البداية مارح تعرف تعملها وتضطر تتعلمها وممكن تعطلك فترة بسيطة، ثم تجد أنها سهلة ورح تضيف لخبرتك الشيء الكثير.
🔸 ثالثا الإبداع (ما عرفت ألاقي تعبير أخف 😂) | وجود مثل هذه المواصفات متاحة لك في أي وقت يسمح لك بإطلاق العنان لخيالك، فانت ممكن تحط بيانات ضخمة على الذاكرة أو تخزن ملفات بالآلاف أو تعمل مشروع سريع وتحطه على الخادم بدون ما تفكر مرتين قبل ما تبدأ تنفذ الفكرة وتخاف من توابعها من ناحية "وين رح أرفعها؟".
🔸 رابعًا الحرية | على الخادم الخاص بك ممكن ترفع أي مشروع بأي لغة وبأي تقنية انت بدك تستخدمها، في المقابل بعض الـ PaaS بتدعم أشياء محدودة وما بتقدر تطلع عنها، وأحيانا تكون محكوم حتى بإصدار اللغة اللي ممكن تستخدمه أو إطار العمل. هذا الأمر أبدا مش موجود لما تكون انت مدير نفسك 😎
طيب هل دائما لازم أروح لإدارة الخوادم بشكل يدوي وما أستخدم PaaS أو خدمات Managed من AWS مثلا أو غيره؟ الجواب لا بكل تأكيد، ولكن هدف منشوري السابق وهذا المنشور توضيح أن الناس أصبح في عقلها الباطن أنك يا مبرمج "لا يجب" عليك أن تلمس الخادم، صندوق أسود ومش من واجبنا نفهم شو اللي صاير فيه.
هذه النظرة هي اللي تغيرت عندي وبحاول أغيرها عند الناس من خلال مشاركة مثل هذه التجربة.
أخيرًا، شو أخبار الـ Performance؟
المثال العملي اللي عندي هو منصة باحث واللي بجيها متوسط 155 طلب في الدقيقة على الصفحة الأهم والأثقل وهي صفحة عرض المواد (الدروس والمحاضرات). بدون حساب باقي الصفحات، الـ P99 لهذه الصفحة هو 200ms، والمتوسط 35ms، مع العلم أن المنصة لا تستخدم أي Caching تقريبًا.
في بعض أوقات الذروة يصل عدد الطلبات إلى 1000 طلب في الدقيقة، وأرقام زمن الاستجابة تقريبا لا ترتفع عن الأرقام المذكورة.
بعرف أن عدد الطلبات قليل مقارنة بمواقع ومنصات ثانية، ولكن الأرقام المذكورة هي الطبيعي لأي مشروع جانبي أو شركة ناشئة، ولا داعي لدفع تكاليف أكثر بكثير فقط لأنه "من الممكن" وصول الطلبات لمئات الآلاف في لحظة من لحظات المستقبل البعيد 😁
والسلام عليكم 👋🏻
ماذا استفدت خلال وبعد التحوّل من Heroku (وأشباهه) إلى إدارة الخوادم بشكل يدوي؟
🔸 أولا التكاليف | حاليا منصة باحث (ومشاريع غيرها كثير) موجودة على نفس الخادم بالمواصفات التالية:
- معالجات بعدد 16 (vCPU)
- ذاكرة بحجم 128GB
- مساحة تخزينية بحجم 2TB
هذه المواصفات لو بدك تجيبها من مكان زي Fly.io رح تدفع 1000$ شهري تقريبا، في المقابل انت ممكن تجيبها من Hetzner بحدود 100$ (الحسابات مش دقيقة 100% ولكن تقريبيًّا).
🔸 ثانيا التعلّم | خلال هذه التجربة تعلّمت أمور كثيرة جدا، منها:
- إدارة الخوادم (ولو بشكل بسيط)
- تعلّمت Docker وكيف بيشتغل واستخداماته
- كتابة Scripts بتحكي مع الخادم وبتنقل البيانات عليه
- تجهيز لوحات متابعة لموقعك وإضافاته زي قاعدة البيانات
- فهم أكبر لإدارة موارد الخوادم
- كل ما يتعلق بالـ Domains وشهادات SSL
وغيرها من الأمور اللي انت في البداية مارح تعرف تعملها وتضطر تتعلمها وممكن تعطلك فترة بسيطة، ثم تجد أنها سهلة ورح تضيف لخبرتك الشيء الكثير.
🔸 ثالثا الإبداع (ما عرفت ألاقي تعبير أخف 😂) | وجود مثل هذه المواصفات متاحة لك في أي وقت يسمح لك بإطلاق العنان لخيالك، فانت ممكن تحط بيانات ضخمة على الذاكرة أو تخزن ملفات بالآلاف أو تعمل مشروع سريع وتحطه على الخادم بدون ما تفكر مرتين قبل ما تبدأ تنفذ الفكرة وتخاف من توابعها من ناحية "وين رح أرفعها؟".
🔸 رابعًا الحرية | على الخادم الخاص بك ممكن ترفع أي مشروع بأي لغة وبأي تقنية انت بدك تستخدمها، في المقابل بعض الـ PaaS بتدعم أشياء محدودة وما بتقدر تطلع عنها، وأحيانا تكون محكوم حتى بإصدار اللغة اللي ممكن تستخدمه أو إطار العمل. هذا الأمر أبدا مش موجود لما تكون انت مدير نفسك 😎
طيب هل دائما لازم أروح لإدارة الخوادم بشكل يدوي وما أستخدم PaaS أو خدمات Managed من AWS مثلا أو غيره؟ الجواب لا بكل تأكيد، ولكن هدف منشوري السابق وهذا المنشور توضيح أن الناس أصبح في عقلها الباطن أنك يا مبرمج "لا يجب" عليك أن تلمس الخادم، صندوق أسود ومش من واجبنا نفهم شو اللي صاير فيه.
هذه النظرة هي اللي تغيرت عندي وبحاول أغيرها عند الناس من خلال مشاركة مثل هذه التجربة.
أخيرًا، شو أخبار الـ Performance؟
المثال العملي اللي عندي هو منصة باحث واللي بجيها متوسط 155 طلب في الدقيقة على الصفحة الأهم والأثقل وهي صفحة عرض المواد (الدروس والمحاضرات). بدون حساب باقي الصفحات، الـ P99 لهذه الصفحة هو 200ms، والمتوسط 35ms، مع العلم أن المنصة لا تستخدم أي Caching تقريبًا.
في بعض أوقات الذروة يصل عدد الطلبات إلى 1000 طلب في الدقيقة، وأرقام زمن الاستجابة تقريبا لا ترتفع عن الأرقام المذكورة.
بعرف أن عدد الطلبات قليل مقارنة بمواقع ومنصات ثانية، ولكن الأرقام المذكورة هي الطبيعي لأي مشروع جانبي أو شركة ناشئة، ولا داعي لدفع تكاليف أكثر بكثير فقط لأنه "من الممكن" وصول الطلبات لمئات الآلاف في لحظة من لحظات المستقبل البعيد 😁
والسلام عليكم 👋🏻
❤4
خان المُبرمجين (علي فاضل)
Photo
حطيت صورة لـ Graph زمن الاستجابة في منشور سابق
وسأل أحد الأصدقاء هل هذه الميزة من Ruby on Rails؟ والجواب نعم ولا 😁
إطار عمل Rails معروف باهتمامه بفكرة الـ Convention over Configuration أو "الاعتماد على الاصطلاحات بدلا من الإعدادات"، وهذا أمرٌ لو تعلمون عظيم.
الصورة من المنشور السابق أو الصوَر في هذا المنشور مصدرها مكتبتين لإطار عمل Rails، الأولى اسمها
- المكتبتين إعدادهم سهل جدا، مجرد تثبيت للاعتمادية في ملف
- تشغيل الـ Generators الخاصة بكل مكتبة كالتالي:
- إضافة الـ Routes الخاصة بكل مكتبة في ملف
وهكذا انت عندك لوحات متابعة لموقعك تقدر تشوف منها عدد الطلبات وسرعتها والأخطاء اللي بتصير سواءً كان على مستوى الموقع أو صفحات محددة.
الفرق بين المكتبين:
- الأولى تستخدم Redis لتخزين البيانات، بينما الثانية تستخدم قاعدة بياناتك بغض النظر شو كانت
- الأولى صعب تخزن فيها بيانات أكثر من 4 ساعات لأنها تعرض البيانات دفعة واحدة، الثانية ممكن تخزن فيها بيانات أسابيع وأشهر
- الأولى إذا نزّلت 3 اعتماديات إضافية، ممكن تتحصل على بيانات استهلاك المعالج والذاكرة والمساحة التخزينية على الخادم، الثانية لا
الاعتماديات الإضافية الخاصة بالنقطة الأخيرة للمكتبة الأولى:
لاحظ أن كل هذا بدون إعدادات كثيرة وكله Self-Hosted بدون ما تدفع تكاليف زيادة، الكثير من مكتبات Rails تتبع نفس النمط، مجرد تثبيت للمكتبة و Generators والباقي مجرد فائدة ومتعة للمُطوّر 😎
والسلام عليكم 👋🏻
ملاحظة: الصور من منصة باحث، ولمن سيسأل عن فرق عدد الطلبات بين المكتبين فالسبب أن المكتبة الثانية بقدر ألغي منها تتبع طلبات معينة زي طلبات الـ Health check، بينما الأولى ما بقدر، للأسف.
وسأل أحد الأصدقاء هل هذه الميزة من Ruby on Rails؟ والجواب نعم ولا 😁
إطار عمل Rails معروف باهتمامه بفكرة الـ Convention over Configuration أو "الاعتماد على الاصطلاحات بدلا من الإعدادات"، وهذا أمرٌ لو تعلمون عظيم.
الصورة من المنشور السابق أو الصوَر في هذا المنشور مصدرها مكتبتين لإطار عمل Rails، الأولى اسمها
rails_performance والثانية اسمها ActiveInsights وأمنيتي انهم يصيرو مكتبة واحدة 😂- المكتبتين إعدادهم سهل جدا، مجرد تثبيت للاعتمادية في ملف
Gemfile (شبيه بملف package.json لجماعة JS 😛) كالتالي:gem 'rails_performance'
gem 'activeinsights'
- تشغيل الـ Generators الخاصة بكل مكتبة كالتالي:
rails generate rails_performance:install
rails active_analytics:install:migrations
- إضافة الـ Routes الخاصة بكل مكتبة في ملف
routes.rb كالتالي:mount RailsPerformance::Engine, at: 'rails/performance'
mount ActiveAnalytics::Engine, at: 'rails/activeinsights'
وهكذا انت عندك لوحات متابعة لموقعك تقدر تشوف منها عدد الطلبات وسرعتها والأخطاء اللي بتصير سواءً كان على مستوى الموقع أو صفحات محددة.
الفرق بين المكتبين:
- الأولى تستخدم Redis لتخزين البيانات، بينما الثانية تستخدم قاعدة بياناتك بغض النظر شو كانت
- الأولى صعب تخزن فيها بيانات أكثر من 4 ساعات لأنها تعرض البيانات دفعة واحدة، الثانية ممكن تخزن فيها بيانات أسابيع وأشهر
- الأولى إذا نزّلت 3 اعتماديات إضافية، ممكن تتحصل على بيانات استهلاك المعالج والذاكرة والمساحة التخزينية على الخادم، الثانية لا
الاعتماديات الإضافية الخاصة بالنقطة الأخيرة للمكتبة الأولى:
gem "sys-filesystem"
gem "sys-cpu"
gem "get_process_mem"
لاحظ أن كل هذا بدون إعدادات كثيرة وكله Self-Hosted بدون ما تدفع تكاليف زيادة، الكثير من مكتبات Rails تتبع نفس النمط، مجرد تثبيت للمكتبة و Generators والباقي مجرد فائدة ومتعة للمُطوّر 😎
والسلام عليكم 👋🏻
ملاحظة: الصور من منصة باحث، ولمن سيسأل عن فرق عدد الطلبات بين المكتبين فالسبب أن المكتبة الثانية بقدر ألغي منها تتبع طلبات معينة زي طلبات الـ Health check، بينما الأولى ما بقدر، للأسف.
❤3
منشور خفيف لطيف لهذا اليوم المبارك 🕌
دائما كنت أنسى أضيف بعض الملفات لملف
إلى أن وجدت هذا الموقع:
https://www.toptal.com/developers/gitignore
انت بتحكيله شو التقنيات اللي بتستخدمها، مثلا Ruby و Rails على نظام تشغيل Mac، وهو بيعملك ملف
والسلام عليكم 👋🏻
دائما كنت أنسى أضيف بعض الملفات لملف
gitignore في المشاريع اللي بشتغلها، ومن أشهر هذه الملفات ملف DS_Store على نظام تشغيل Mac، وأحيانا لما تكثر هذه الملفات في مستودع Git الخاص بالمشروع بكون حذفها وتنظيف المستودع منها مرهق (مش مستحيل).إلى أن وجدت هذا الموقع:
https://www.toptal.com/developers/gitignore
انت بتحكيله شو التقنيات اللي بتستخدمها، مثلا Ruby و Rails على نظام تشغيل Mac، وهو بيعملك ملف
gitignore فيه كل ما يتعلق بهذه التقنيات جاهز للاستخدام، بدون ما تنسى شيء.والسلام عليكم 👋🏻
❤3
السلام عليكم ورحمة الله وبركاته،
إخواني المتصدرين وصناع المحتوى واللي الناس تتابع منصاتكم وحساباتكم، هذه نصيحة أنا شخصيا أواجهها لما أقرأ منشوراتكم وقد أقع في نفس المشاكل فنبهوني.
- الاستخدام المفرط للهجة العامية في المنشورات مضر غير نافع، لا ضير من استخدام العامية بجانب الفصحى، ولكن خلينا نحاول نرتقي بطريقة كتابتنا.
- الأخطاء الإملائية وعدم تنسيق المنشور شيء سيء مش جيد، حاول تنسق منشورك وتهتم فيه، مثلا ما يكون في مسافات كثيرة متتابعة بدون داعي.
- إذا في مصطلح عربي بديل عن الانجليزي حاول تستخدمه وتتبعه بالمصطلح الانجليزي، بعرف المجال التقني صعب فيه هذا الأمر ولكن حاول.
بحب أقرأ منشوراتكم ولكن داخلي هذا الأمر من فترة وحبيت أحكيه لعلنا نرتقي بالمحتوى أكثر، وما ننسى ان ما نكتب اليوم هو بيانات تدريب النماذج غدا، شئنا أم أبينا 😁
ملاحظة: نماذج مثل ChatGPT و Claude بتساعد كثير في مراجعة المحتوى قبل نشره.
إخواني المتصدرين وصناع المحتوى واللي الناس تتابع منصاتكم وحساباتكم، هذه نصيحة أنا شخصيا أواجهها لما أقرأ منشوراتكم وقد أقع في نفس المشاكل فنبهوني.
- الاستخدام المفرط للهجة العامية في المنشورات مضر غير نافع، لا ضير من استخدام العامية بجانب الفصحى، ولكن خلينا نحاول نرتقي بطريقة كتابتنا.
- الأخطاء الإملائية وعدم تنسيق المنشور شيء سيء مش جيد، حاول تنسق منشورك وتهتم فيه، مثلا ما يكون في مسافات كثيرة متتابعة بدون داعي.
- إذا في مصطلح عربي بديل عن الانجليزي حاول تستخدمه وتتبعه بالمصطلح الانجليزي، بعرف المجال التقني صعب فيه هذا الأمر ولكن حاول.
بحب أقرأ منشوراتكم ولكن داخلي هذا الأمر من فترة وحبيت أحكيه لعلنا نرتقي بالمحتوى أكثر، وما ننسى ان ما نكتب اليوم هو بيانات تدريب النماذج غدا، شئنا أم أبينا 😁
ملاحظة: نماذج مثل ChatGPT و Claude بتساعد كثير في مراجعة المحتوى قبل نشره.
❤7👍1
هل أنت بحاجة Redis ومثيلاتها لأمور مثل الـ Caching والـ Background Jobs في عصر الـ NVMe؟ 🤔
بدايةً، Redis مقاطعة، ولها بدائل كثيرة مثل valkey وهي متوافقة مع Redis بداية من الإصدار 7.2، ولكن ذكرتها لشهرتها ومعرفت الناس بها.
مع الإصدار السابع والثامن لإطار عمل Ruby on Rails، أعلن DHH عن مجموعة مكتبات تحت مسمى Solid وهي:
- SolidCache
- SolidQueue
- SolidCable
الأولى من اسمها مخصصة للـ Caching وهي بديلة لأشياء مثل Redis و Memcached والثانية مخصصة للـ Background Jobs وهي بديلة لأشياء مثل Sidekiq والثالثة والأخيرة مخصصة للـ WebSockets وهي بديلة لأشياء مثل CableReady.
طيب ما المميز في هذه المجموعة من المكتبات؟ اسمها حلو مثلا؟
حقيقة المميز فيها هو اعتمادها على قاعدة البيانات مثل SQLite أو PostgreSQL بدلا من الذاكرة، على عكس كل المكتبات الثانية، فكل من Redis و Memcached و Sidekiq و CableReady تعمل على ذاكرة الخادم بدلا من المساحة التخزينية اللي تستخدمها قاعدة البيانات بشكل أساسي، وكلهم معتمدين على Redis كمكان لتخزين بياناتهم (تحديدا Sidekiq و CableReady).
فكرة مجموعة مكتبات Solid أصبحت ممكنة في عصر المساحات التخزينية المعتمدة على الـ NVMe. كمثال، شركة 37Signals بدأت في استخدام SolidCache في منتجها Basecamp من سنة ونص تقريبا. المُلاحظ كان أن سرعة القراءة من SolidCache كانت أبطأ من Redis بنسبة 40%، ولكن مساحة الـ Cache أصبحت أكبر بـ 6 مرات (10TB!)، وسعرها أرخص بنسبة 80%.
بالمُحصّلة، زمن الاستجابة في Basecamp نزل من 375ms للـ p95 إلى 225ms.
ممكن تقرأ عن تجربتهم من هنا:
https://dev.37signals.com/solid-cache
مثال آخر هو مكتبة SolidQueue، حاليا 37Signals تستخدمها في منتجهم Hey.com وقادرين على معالجة أكثر من 20 مليون Background Job في اليوم، كله بدون استخدام الذاكرة والاعتماد المباشر على قاعدة البيانات.
طيب ليش بحكيلك هالكلام؟ عشان أبهرك مثلا؟
صراحة نعم حاب أبهرك، مع الإصدار الثامن من Ruby on Rails انت فقط محتاج قاعدة بيانات SQLite موجودة على المساحة التخزينية للخادم لدعم الـ Caching والـ Background Jobs والـ WebSockets، بتكلفة قليلة وبدون أي اعتماديات إضافية مثل Redis.
أكيد أُطر عمل ثانية رح تبدأ تتبع نفس النهج مستقبلا، والجميل أن شركة مثل 37Signals تستخدم هذه المكتبات لدعم منتجات حقيقية لها مئات الآلاف (إن لم يكن ملايين) المستخدمين.
والسلام عليكم 👋🏻
بدايةً، Redis مقاطعة، ولها بدائل كثيرة مثل valkey وهي متوافقة مع Redis بداية من الإصدار 7.2، ولكن ذكرتها لشهرتها ومعرفت الناس بها.
مع الإصدار السابع والثامن لإطار عمل Ruby on Rails، أعلن DHH عن مجموعة مكتبات تحت مسمى Solid وهي:
- SolidCache
- SolidQueue
- SolidCable
الأولى من اسمها مخصصة للـ Caching وهي بديلة لأشياء مثل Redis و Memcached والثانية مخصصة للـ Background Jobs وهي بديلة لأشياء مثل Sidekiq والثالثة والأخيرة مخصصة للـ WebSockets وهي بديلة لأشياء مثل CableReady.
طيب ما المميز في هذه المجموعة من المكتبات؟ اسمها حلو مثلا؟
حقيقة المميز فيها هو اعتمادها على قاعدة البيانات مثل SQLite أو PostgreSQL بدلا من الذاكرة، على عكس كل المكتبات الثانية، فكل من Redis و Memcached و Sidekiq و CableReady تعمل على ذاكرة الخادم بدلا من المساحة التخزينية اللي تستخدمها قاعدة البيانات بشكل أساسي، وكلهم معتمدين على Redis كمكان لتخزين بياناتهم (تحديدا Sidekiq و CableReady).
فكرة مجموعة مكتبات Solid أصبحت ممكنة في عصر المساحات التخزينية المعتمدة على الـ NVMe. كمثال، شركة 37Signals بدأت في استخدام SolidCache في منتجها Basecamp من سنة ونص تقريبا. المُلاحظ كان أن سرعة القراءة من SolidCache كانت أبطأ من Redis بنسبة 40%، ولكن مساحة الـ Cache أصبحت أكبر بـ 6 مرات (10TB!)، وسعرها أرخص بنسبة 80%.
بالمُحصّلة، زمن الاستجابة في Basecamp نزل من 375ms للـ p95 إلى 225ms.
ممكن تقرأ عن تجربتهم من هنا:
https://dev.37signals.com/solid-cache
مثال آخر هو مكتبة SolidQueue، حاليا 37Signals تستخدمها في منتجهم Hey.com وقادرين على معالجة أكثر من 20 مليون Background Job في اليوم، كله بدون استخدام الذاكرة والاعتماد المباشر على قاعدة البيانات.
طيب ليش بحكيلك هالكلام؟ عشان أبهرك مثلا؟
صراحة نعم حاب أبهرك، مع الإصدار الثامن من Ruby on Rails انت فقط محتاج قاعدة بيانات SQLite موجودة على المساحة التخزينية للخادم لدعم الـ Caching والـ Background Jobs والـ WebSockets، بتكلفة قليلة وبدون أي اعتماديات إضافية مثل Redis.
أكيد أُطر عمل ثانية رح تبدأ تتبع نفس النهج مستقبلا، والجميل أن شركة مثل 37Signals تستخدم هذه المكتبات لدعم منتجات حقيقية لها مئات الآلاف (إن لم يكن ملايين) المستخدمين.
والسلام عليكم 👋🏻
❤4👍1
#تجارب_فاشلة
لسهولة بدأ مشاريع جديدة وتجربة أفكار مختلفة في Ruby on Rails، وجدت أن عندي مشاريع كثيرة وكل فترة بحتاج أبدأ شيء جديد ولكن يستهلك مني وقت في إعداد المشروع من ناحية تثبيت الاعتماديات المطلوبة وتجهيزها بشكل كامل على المشروع.
فقررت في منتصف الليل اني أعمل مكتبة بمجرد ما أضيفها على مشروع Rails الجديد وأشغّل أمر مثل:
يكون عندي المشروع جاهز من ناحية الاعتماديات وتجهيزها في المشروع، وحتى تحديث إصدارات الاعتماديات ممكن يتم مرة واحدة داخل المكتبة الجديدة وبشكل مباشر تنتقل هذه التحديثات لمشاريعي كلها، الفكرة من بعيد ممتازة.
فعلا، عملت المكتبة وسميتها
https://github.com/AliOsm/permadeps
وكنت مبسوط عليها وبدأت أستخدمها في أكثر من مشروع، ولكن بدأت تظهر المشاكل:
🔸 في Rails (وغيرها) ممكن تحدد هل الاعتمادية هي اعتمادية للتطوير فقط (Development Dependency) أو اعتمادية تحتاجها حتى في الـ Production؟ وهذا الأمر كان غير ممكن في حالة
🔸 يوجد مكتبتان أساسيتان لكتابة الاختبارات في Rails وهي مكتبة
🔸 لما عملت
🔸 أخيرا، بعض الاعتماديات مثل
بعد هذه التجربة الفاشلة والمشاكل اللي واجهتها، قررت إيقاف مكتبة
من خلال Rails Templates بتقدر تعمل Setup للكثير من الاعتماديات وإضافة ملفات للمشروع من بدايته وتجهيزه بالطريقة اللي بدك ياها بمجرد إضافة خيار واحد إلى أمر إنشاء المشروع في Rails، فبدل ما تكتب:
ممكن تكتب:
إذا كان الـ Template موجود على الجهاز، أو:
إذا كان الـ Template موجود على رابط.
ممكن تقرأ أكثر عن Rails Templates من هنا:
https://guides.rubyonrails.org/rails_application_templates.html
والسلام عليكم 👋🏻
لسهولة بدأ مشاريع جديدة وتجربة أفكار مختلفة في Ruby on Rails، وجدت أن عندي مشاريع كثيرة وكل فترة بحتاج أبدأ شيء جديد ولكن يستهلك مني وقت في إعداد المشروع من ناحية تثبيت الاعتماديات المطلوبة وتجهيزها بشكل كامل على المشروع.
فقررت في منتصف الليل اني أعمل مكتبة بمجرد ما أضيفها على مشروع Rails الجديد وأشغّل أمر مثل:
rails g package:install
يكون عندي المشروع جاهز من ناحية الاعتماديات وتجهيزها في المشروع، وحتى تحديث إصدارات الاعتماديات ممكن يتم مرة واحدة داخل المكتبة الجديدة وبشكل مباشر تنتقل هذه التحديثات لمشاريعي كلها، الفكرة من بعيد ممتازة.
فعلا، عملت المكتبة وسميتها
permadeps (اخصارًا لـ Permanent Dependencies أو الاعتماديات الدائمة) وهذا مستودعها على GitHub:https://github.com/AliOsm/permadeps
وكنت مبسوط عليها وبدأت أستخدمها في أكثر من مشروع، ولكن بدأت تظهر المشاكل:
🔸 في Rails (وغيرها) ممكن تحدد هل الاعتمادية هي اعتمادية للتطوير فقط (Development Dependency) أو اعتمادية تحتاجها حتى في الـ Production؟ وهذا الأمر كان غير ممكن في حالة
permadeps، فكنت مضطر أستخدم كل الاعتماديات في الـ Production واللي هو أمر مش مؤثر بكثرة، مجرد استهلاك إضافي للذاكرة (بحدود 15MB).🔸 يوجد مكتبتان أساسيتان لكتابة الاختبارات في Rails وهي مكتبة
minitest ومكتبة RSpec. بعض مشاريعي كانت تستخدم الأولى والبعض الآخر يستخدم الثانية. فاضطريت أحط الإثنين كاعتماديات في permadeps واللي هو أمر مش لطيف، ولكن ممكن التغاضي عنه، وله نفس مساوئ النقطة السابقة.🔸 لما عملت
permadeps كنت أستخدم Frontend Stack يعتمد على الاعدادات الإفتراضية من Rails واللي بتستخدم ERb، بعد فترة قررت الانتقال إلى Phlex. مبدئيًّا ممكن تحكي الأمور سهلة بس عدّل الاعتماديات في permadeps ولكن بهذه الطريقة أنا محتاج أعدل كل المشاريع عشان تستخدم Phlex واللي هو أمر مرهق وغير ضروري في حالات كثيرة.🔸 أخيرا، بعض الاعتماديات مثل
PgHero وهي عبارة عن لوحة متابعة لقاعدة بيانات PostgreSQL أستخدمها مع المشاريع اللي بتستخدم قاعدة بيانات PostgreSQL فقط، ولكن حتى في المشاريع اللي بتستخدم SQLite مثلا كنت مضطر أنزلها لأنها من اعتماديات permadeps.بعد هذه التجربة الفاشلة والمشاكل اللي واجهتها، قررت إيقاف مكتبة
permadeps والاعتماد على شيء مختلف وهو Rails Templates.من خلال Rails Templates بتقدر تعمل Setup للكثير من الاعتماديات وإضافة ملفات للمشروع من بدايته وتجهيزه بالطريقة اللي بدك ياها بمجرد إضافة خيار واحد إلى أمر إنشاء المشروع في Rails، فبدل ما تكتب:
rails new blog
ممكن تكتب:
rails new blog -m ~/template.rb
إذا كان الـ Template موجود على الجهاز، أو:
rails new blog -m URL
إذا كان الـ Template موجود على رابط.
ممكن تقرأ أكثر عن Rails Templates من هنا:
https://guides.rubyonrails.org/rails_application_templates.html
والسلام عليكم 👋🏻
❤1
خان المُبرمجين (علي فاضل)
Photo
18 حرفا من الممكن أن تغير أداء تطبيقك!
كنت أتحدث مع صديقي وزميلي في العمل البارحة، وكان يشرح لي مشكلة حدثت مع صديقه في أحد مشاريعه وكيف كان يساعده من خلال استخدام JMeter لضغط خادم التطبيق واختباره. فقلت له: "يجب أن نجرّب الأمر نفسه على باحث"، وفعلًا بدأنا في ذلك ولكن كانت النتائج سيئة جدًا؛ الخادم لا يستطيع معالجة أكثر من ألفيْ طلب على الصفحة الرئيسية خلال دقيقة!
ذهبت إلى المنزل ودخلت في دوّامة البحث عن السبب، فأنا متأكد أن باحث كان يستطيع معالجة طلبات أكثر من ذلك في السابق. ففتحت الخادم من خلال SSH وشغّلت أداة
فأول ما خطر لي التأكد من قيمة أحد إعدادات Ruby on Rails وهو
رفعت الـ
بالقيمة القديمة كان باحث يُعالج كحد أقصى ألف طلب في الدقيقة، بمتوسط زمن استجابة 723ms، على أثقل صفحات الموقع وهي صفحة عرض المواد والتي تتعامل مع قاعدة البيانات بكثرة. بينما باستخدام القيمة الجديدة فباحث يستطيع معالجة أكثر من 7,500 طلب في الدقيقة، بمتوسط زمن استجابة 375ms، كما هو موضّح في الصورتين.
هذه الأرقام مع الأخذ بعين الاعتبار أن خادم باحث يحتوي على المنصة وقاعدة البيانات ومحرك البحث وكل ما يتعلق بباحث.
لا أدري كيف ومتى تغيّرت إعدادات باحث وأُزيل منها الـ
ولمن يسأل ما هي الـ 18 حرفًا، فهي:
أما
والسلام عليكم 👋🏻
ملاحظة: الصور من موقع https://loader.io وهذه روابط الاختبارات لمن يريد الاطلاع عليها:
- https://loader.io/reports/914e27236aa9ebdccd62072177a1ace0/results/34ad9ac42d59999073b8ef629f66890c
- https://loader.io/reports/914e27236aa9ebdccd62072177a1ace0/results/b8ca0bb6532dc1f351027bebfc94ce3f
كنت أتحدث مع صديقي وزميلي في العمل البارحة، وكان يشرح لي مشكلة حدثت مع صديقه في أحد مشاريعه وكيف كان يساعده من خلال استخدام JMeter لضغط خادم التطبيق واختباره. فقلت له: "يجب أن نجرّب الأمر نفسه على باحث"، وفعلًا بدأنا في ذلك ولكن كانت النتائج سيئة جدًا؛ الخادم لا يستطيع معالجة أكثر من ألفيْ طلب على الصفحة الرئيسية خلال دقيقة!
ذهبت إلى المنزل ودخلت في دوّامة البحث عن السبب، فأنا متأكد أن باحث كان يستطيع معالجة طلبات أكثر من ذلك في السابق. ففتحت الخادم من خلال SSH وشغّلت أداة
htop وبدأت الاختبار مرة ثانية مع مراقبة النتائج من htop، وكانت المفاجأة أن باحث لا يستهلك معالج الخادم بالكامل، وإنما يستهلك ما يقارب 10% منه فقط!فأول ما خطر لي التأكد من قيمة أحد إعدادات Ruby on Rails وهو
WEB_CONCURRENCY، وكانت المفاجأة الثانية أن هذا الإعداد قد اختفى من مستودع باحث وبشكل تلقائي Rails تستخدم 1 كقيمة لهذا الإعداد في حال عدم تحديده من قبل المطوّر!رفعت الـ
WEB_CONCURRENCY من 1 إلى 8 وأعدت الاختبار على صفحات مختلفة من باحث، واختلفت النتائج تمامًا.بالقيمة القديمة كان باحث يُعالج كحد أقصى ألف طلب في الدقيقة، بمتوسط زمن استجابة 723ms، على أثقل صفحات الموقع وهي صفحة عرض المواد والتي تتعامل مع قاعدة البيانات بكثرة. بينما باستخدام القيمة الجديدة فباحث يستطيع معالجة أكثر من 7,500 طلب في الدقيقة، بمتوسط زمن استجابة 375ms، كما هو موضّح في الصورتين.
هذه الأرقام مع الأخذ بعين الاعتبار أن خادم باحث يحتوي على المنصة وقاعدة البيانات ومحرك البحث وكل ما يتعلق بباحث.
لا أدري كيف ومتى تغيّرت إعدادات باحث وأُزيل منها الـ
WEB_CONCURRENCY، ولكن الحمد لله أننا وجدنا المشكلة 😁ولمن يسأل ما هي الـ 18 حرفًا، فهي:
WEB_CONCURRENCY: 8
أما
WEB_CONCURRENCY فهو إعداد مهم في تطبيقات Rails يحدد عدد عمليات Puma (خادم الويب الافتراضي لـ Rails) التي يمكن تشغيلها بالتوازي. يتحكم هذا الإعداد في عدد العمليات التي يمكن لخادم Puma إنشاؤها لمعالجة الطلبات الواردة. زيادة قيمة WEB_CONCURRENCY تسمح للتطبيق بمعالجة المزيد من الطلبات في وقت واحد، مما يحسن الأداء العام وقدرة التحمل للتطبيق. ومع ذلك، من المهم موازنة هذه القيمة مع موارد الخادم المتاحة كالذاكرة والمعالج.والسلام عليكم 👋🏻
ملاحظة: الصور من موقع https://loader.io وهذه روابط الاختبارات لمن يريد الاطلاع عليها:
- https://loader.io/reports/914e27236aa9ebdccd62072177a1ace0/results/34ad9ac42d59999073b8ef629f66890c
- https://loader.io/reports/914e27236aa9ebdccd62072177a1ace0/results/b8ca0bb6532dc1f351027bebfc94ce3f
❤3
خان المُبرمجين (علي فاضل)
Photo
إعادة فتح الـ Classes في Ruby 🤔
من الأشياء اللطيفة في لغة Ruby واللي بتفتح المجال للكثير من الأمور هي إمكانية إعادة فتح الـ Classes وإضافة أشياء جديدة لها مثل الدوال.
على سبيل المثال، الـ Class الخاص بالـ Strings ما فيه دالة
هذا الأمر واللي يسمى بمُصطلح يصعب علي تعريبه "Monkey Patching"، مستخدم بكثرة في مكان زي Rails لتوفير تحسينات كثيرة للمطوّر، من أبسطها على سبيل المثال إضافة دالة
ممكن تشوف كيف الإضافة صارت من هنا:
https://github.com/rails/rails/blob/v8.0.1/activesupport/lib/active_support/core_ext/string/inquiry.rb
وتشوف كيف الـ StringInquirer Class بيشتغل من هنا:
https://github.com/rails/rails/blob/v8.0.1/activesupport/lib/active_support/string_inquirer.rb
وهو يستخدم ميزة الـ
https://t.me/programmerskhan/17
أخيرا، بالرغم من أن إعادة فتح الـ Classes (أو الـ Monkey Patching) يوفر مرونة كبيرة لإضافة وتعديل اللغة ومكتباتها، إلا أن لها بعض العيوب اللي لازم تاخذها بعين الاعتبار.
من أبرز هذه العيوب هو إمكانية التسبب في تعارض مع الكود الحالي أو المكتبات الثانية إذا تم تعديل السلوك الافتراضي بطريقة غير متوقعة. بالإضافة إلى أنه قد يؤدي إلى صعوبة في تتبع الأخطاء أو فهم الكود، لذلك من الأفضل استخدام هذه الميزة بحذر والتأكد من توثيق أي تغييرات يتم إجراؤها لتجنب المشاكل في المستقبل.
والسلام عليكم 👋🏻
من الأشياء اللطيفة في لغة Ruby واللي بتفتح المجال للكثير من الأمور هي إمكانية إعادة فتح الـ Classes وإضافة أشياء جديدة لها مثل الدوال.
على سبيل المثال، الـ Class الخاص بالـ Strings ما فيه دالة
?palindrome في لغة Ruby، ولكن في الصورة الأولى أعدت فتح الـ Class (رغم انه Class جاي من اللغة نفسها) وأضفت له الدالة الجديدة واستطعت استخدامها على كائن جديد من نوع String.هذا الأمر واللي يسمى بمُصطلح يصعب علي تعريبه "Monkey Patching"، مستخدم بكثرة في مكان زي Rails لتوفير تحسينات كثيرة للمطوّر، من أبسطها على سبيل المثال إضافة دالة
inquiry للـ String Class واللي إذا طبقتها على نص مثلا "production" بتعطيك كائن جديد من نوع StringInquirer واللي ممكن تسأله عن قيمته النصية بشكل مباشر زي ماهو موضح في الصورة الثانية بدلا من مقارنة نص بنص.ممكن تشوف كيف الإضافة صارت من هنا:
https://github.com/rails/rails/blob/v8.0.1/activesupport/lib/active_support/core_ext/string/inquiry.rb
وتشوف كيف الـ StringInquirer Class بيشتغل من هنا:
https://github.com/rails/rails/blob/v8.0.1/activesupport/lib/active_support/string_inquirer.rb
وهو يستخدم ميزة الـ
method_missing اللي حكيت عنها في منشور سابق واللي ممكن تقرأه من هنا:https://t.me/programmerskhan/17
أخيرا، بالرغم من أن إعادة فتح الـ Classes (أو الـ Monkey Patching) يوفر مرونة كبيرة لإضافة وتعديل اللغة ومكتباتها، إلا أن لها بعض العيوب اللي لازم تاخذها بعين الاعتبار.
من أبرز هذه العيوب هو إمكانية التسبب في تعارض مع الكود الحالي أو المكتبات الثانية إذا تم تعديل السلوك الافتراضي بطريقة غير متوقعة. بالإضافة إلى أنه قد يؤدي إلى صعوبة في تتبع الأخطاء أو فهم الكود، لذلك من الأفضل استخدام هذه الميزة بحذر والتأكد من توثيق أي تغييرات يتم إجراؤها لتجنب المشاكل في المستقبل.
والسلام عليكم 👋🏻
❤1👍1
خان المُبرمجين (علي فاضل)
Photo
من مشاكل التخزين المؤقت (أو الـ Caching) 😁
منصة باحث تسمحلك بالبحث في تفريغات دروس ومحاضرات المشايخ، وخلال مشاهدة الدروس والمحاضرات بتقدر تقرأ التفريغ وتتابعه، ممكن تعرف عن المنصة أكثر من خلال هذا المقطع:
https://youtu.be/vl90LkLgfE4
من المميزات اللي حبيت أضيفها للمنصة ميزة الإشارات المرجعية (Bookmarks)، بمعنى وانت بتحضر الدرس أو المحاضرة ممكن تحط إشارة مرجعية على مكان معين في الدرس وترجعله مستقبلا.
تطبيق الميزة كان سهل من ناحية قاعدة البيانات والـ Backend، ولكن لما وصلت لمرحلة تعديل واجهة المستخدم كانت المفاجأة، صفحة عرض المادة في عليها تخزين مؤقت (مارح أحكي Caching في المنشور 🙂).
المفتاح أو الـ Key للتخزين المؤقت كان المادة نفسها، فهيك الناس كلها، بعد أول مرة تنعرض فيها الصفحة لأي مستخدم، بيطلعلها نفس الصفحة كل مرة، مما يعني أنك لو مستخدم وحطيت إشارة مرجعية، إذا عملت تحديث مارح تطلعلك في الواجهة لأن الصفحة مُخزّنة مسبقًا (ولكن التعديل تم على قاعدة البيانات).
أول شيء ممكن يخطر في بالك هو إضافة المستخدم لمفتاح التخزين المؤقت بحيث تكون المادة بالإضافة للمستخدم مفتاح فريد يضمن ظهور التعديلات على واجهة المستخدم. ولكن كمية البيانات اللي ممكن تتخزن في الذاكرة كبيرة جدا حسب عدد مستخدمي تطبيقك (عدد الصفحات المُخزّنة = عدد المواد * عدد المستخدمين)، فهذا الحل غير مُجدي.
الحل الثاني واللي طبقته وقتها هو تخزين الجزء الأكبر من الصفحة بحيث ما ينعمله Rendering، ولكن في بداية الصفحة وضعت عنصر HTML مخفي ووضعت فيه أرقام الإشارات المرجعية الخاصة بالمستخدم للمادة الحالية، ثم من خلال JavaScript أُغيّر واجهة المستخدم بحيث تظهر العناصر بالشكل المطلوب وتستخدم الروابط الصحيحة لإضافة وحذف الإشارات المرجعية.
بهذه الطريقة التخزين المؤقت شغّال والمستخدم قادر يشوف إشاراته المرجعية والعصافير تزقزق والسماء صافية والسلام عليكم 👋🏻
ملاحظة: بعد فترة أزلت التخزين المؤقت كله من باحث 😂 ولكن نفس الكود لساته موجود.
منصة باحث تسمحلك بالبحث في تفريغات دروس ومحاضرات المشايخ، وخلال مشاهدة الدروس والمحاضرات بتقدر تقرأ التفريغ وتتابعه، ممكن تعرف عن المنصة أكثر من خلال هذا المقطع:
https://youtu.be/vl90LkLgfE4
من المميزات اللي حبيت أضيفها للمنصة ميزة الإشارات المرجعية (Bookmarks)، بمعنى وانت بتحضر الدرس أو المحاضرة ممكن تحط إشارة مرجعية على مكان معين في الدرس وترجعله مستقبلا.
تطبيق الميزة كان سهل من ناحية قاعدة البيانات والـ Backend، ولكن لما وصلت لمرحلة تعديل واجهة المستخدم كانت المفاجأة، صفحة عرض المادة في عليها تخزين مؤقت (مارح أحكي Caching في المنشور 🙂).
المفتاح أو الـ Key للتخزين المؤقت كان المادة نفسها، فهيك الناس كلها، بعد أول مرة تنعرض فيها الصفحة لأي مستخدم، بيطلعلها نفس الصفحة كل مرة، مما يعني أنك لو مستخدم وحطيت إشارة مرجعية، إذا عملت تحديث مارح تطلعلك في الواجهة لأن الصفحة مُخزّنة مسبقًا (ولكن التعديل تم على قاعدة البيانات).
أول شيء ممكن يخطر في بالك هو إضافة المستخدم لمفتاح التخزين المؤقت بحيث تكون المادة بالإضافة للمستخدم مفتاح فريد يضمن ظهور التعديلات على واجهة المستخدم. ولكن كمية البيانات اللي ممكن تتخزن في الذاكرة كبيرة جدا حسب عدد مستخدمي تطبيقك (عدد الصفحات المُخزّنة = عدد المواد * عدد المستخدمين)، فهذا الحل غير مُجدي.
الحل الثاني واللي طبقته وقتها هو تخزين الجزء الأكبر من الصفحة بحيث ما ينعمله Rendering، ولكن في بداية الصفحة وضعت عنصر HTML مخفي ووضعت فيه أرقام الإشارات المرجعية الخاصة بالمستخدم للمادة الحالية، ثم من خلال JavaScript أُغيّر واجهة المستخدم بحيث تظهر العناصر بالشكل المطلوب وتستخدم الروابط الصحيحة لإضافة وحذف الإشارات المرجعية.
بهذه الطريقة التخزين المؤقت شغّال والمستخدم قادر يشوف إشاراته المرجعية والعصافير تزقزق والسماء صافية والسلام عليكم 👋🏻
ملاحظة: بعد فترة أزلت التخزين المؤقت كله من باحث 😂 ولكن نفس الكود لساته موجود.
❤1👍1🔥1