خان المُبرمجين (علي فاضل)
543 subscribers
93 photos
9 videos
116 links
قناة أنشر فيها ما أتعلمه خلال عملي على مشاريعي الخاصة 👀
Download Telegram
بسم الله الرحمن الرحيم،

بدأت من فترة بسيطة نشر بعض الأمور المتعلقة بالتقنية وما أتعلمه خلال عملي على مشاريعي الخاصة على منصات قبيلة و LinkedIn، ثم قررت إنشاء هذه القناة لنشر المحتوى نفسه لعله يُفيد عددا أكبر من الناس.

الله المستعان وعليه التكلان، بسم الله نبدأ 🚀
3
من أسبوع أُطلق الإصدار 3.4 من لغة Ruby، وقررت أبدأ نشر مجموعة من المنشورات عن اللغة بشكل عام وإطار العمل Ruby on Rails، مش هدفي أقنعك تستخدم Ruby أو Rails، ولكن هدفي أعرّفك بلغة وإطار عمل مُلهمين ومفيدين بشكل كبير 😎

اللي شدني في آخر تحديث بشكل أساسي أمرين:

في Ruby ممكن تكتب التالي:

squares = [1, 2, 3].map { |element| element * element }


ببساطة الكود يقوم بتربيع كل قيمة من قيَم المصفوفة، في هذه الحالة تقدر تستغني عن اسم المُتغيّر element وتكتب الكود كالتالي:

squares = [1, 2, 3].map { _1 * _1 }


طبعا زي ما انت متوقع، 1_ الموجودة بين الأقواس تُعبّر عن أول عنصر من عناصر الحَلقة، وممكن تستخدم 2_ و 3_ وهكذا، ولكن استخدام أكثر من 1_ مش لطيف في الكود.

في الإصدار الجديد ممكن تكتب it مكان 1_ واللي شكلها ألطف بمراحل:

squares = [1, 2, 3].map { it * it }


هذا الشيء الأول، الثاني هو تحسينات على YJIT واللي هو عبارة عن just in time compiler للغة Ruby مكتوب بلغة Rust واللي ممكن يعطيك زيادة في السرعة تصل إلى 90% مقابل استهلاك إضافي للذاكرة يُقدّر بـ 15-20%. التحسينات تتضمن سرعة أكثر واستهلاك ذاكرة أقل حسب الـ benchmarks اللي ممكن تطّلع عليها من هنا:
https://speed.yjit.org

ومن الأشياء اللطيفة اللي كانت موجودة في الـ Release notes هي تحسينات على دالة Kernel#Float (نعم دالة مش Class 😁) بحيث اصبح بإمكانها استقبال الرقم على هيئة نص بدون كتابة الجزء العشري منه، فعلى سبيل المثال ممكن تكتب:

Float("1.0")


أو تكتب:

Float("1.")


والاثنين نفس النتيجة، الاهتمام بالتفاصيل لطيف أحيانًا 😂

أخيرًا، شو ممكن أعمل بلغة Ruby؟ ممكن تبني موقع زي باحث:
https://baheth.ieasybooks.com

وأكثر من ذلك بكثير زي ما حنشوف في باقي المنشورات مستقبلا ✌🏻

ولمن سيسأل لماذا اسمه YJIT، فهو اختصار لـ Yet Another Ruby JIT، السلام عليكم 👋🏻
1👍1
"بس هو شغّال على جهازي 🤔"

هذه من المشاكل اللي بتواجه الفِرق البرمجية في الشركات الصغيرة والكبيرة على حدٍّ سواء، وهي أن المشروع شغّال عندك ومش شغّال عند زميلك.

من سنة ونص تقريبًا تعرّفت على الـ DevContainers، وهو أمر لو تعلمون عظيم 🚀

أولا وقبل ما نتعرّف على الـ DevContainers، انت محتاج تفهم ولو شوي شو هو Docker، وهذا خارج نطاق هذا المنشور، ولكن ببساطة مُخِلَّه ممكن تعتبر Docker شيء يسمحلك بتشغيل نظام تشغيل مُصغّر داخل جهازك.

الـ DevContainer هي عبارة عن Docker image تستخدمها لتطوير مشاريعك على جهازك وتسمحلك بإعادة بنائها وتشغيلها على أكثر من جهاز، بحيث أن كل أعضاء الفريق يكون عندهم نفس بيئة التطوير، بنفس إصدار لغة البرمجة والخدمات الإضافية كقاعدة البيانات وإضافات وإعدادات المحرر.

للبدء في استخدام الـ DevContainers، تأكد أن عندك Docker على جهازك ثم افتح محرر VSCode وتأكد أن إضافة Dev Containers موجودة عندك، بعد ذلك محتاج تعمل مجلد باسم devcontainer. داخل مشروعك، هذا المجلد سيحتوي على كل ما يتعلق بالـ DevContainer في مشروعك.

داخل المجلد ممكن تعمل أكثر من ملف ومجلد لأكثر من وظيفة، ولكن الملفات الأساسية بالنسبة لي في أي مشروع هي 4:

- devcontainer.json
- docker-compose.yml
- Dockerfile
- setup.sh

الأول يحتوي على إعدادات بيئة التطوير الخاصة بك وهذا مثال عليه:
https://github.com/ieasybooks/tafrigh/blob/main/.devcontainer/devcontainer.json

وهي بيئة تطوير برنامج تفريغ، ببساطة الملف يقوم بتجهيز بيئة العمل ببرمجية FFmpeg، محرر vim، لغة البرمجة Python إصدار 3.12 و Zsh مع إضافة OhMyZsh. هذا فيما يتعلق ببيئة التطوير من ناحية البرمجيات، من ناحية إضافات المحرر فالـ DevContainer تقوم بتثبيت 8 إضافات منها GitBlame وبعض الإضافات الخاصة بلغة Python.

في نفس هذا الملف devcontainer.json يتم استدعاء ملف docker-compose.yml لبناء الـ Docker image وملف setup.sh.

داخل docker-compose.yml ممكن تعريف الإضافات اللي محتاجها في مشروعك زي قاعدة البيانات ومحرك البحث، وهذا الملف مثال عليه:
https://github.com/AliOsm/wisal/blob/main/.devcontainer/docker-compose.yml
وهو يقوم بتجهيز محرك البحث MeiliSearch وكذلك Redis.

أما ملف setup.sh مهمته تشغيل بعض الأوامر بعد الانتهاء من تجهيز بيئة العمل بالكامل، على سبيل المثال تشغيل أمر yarn install لتثبيت المكتبات الخاص بتطوير المشروع، وهذا مثال عليه:
https://github.com/ieasybooks/tafrigh/blob/main/.devcontainer/setup.sh

أخيرا ملف Dockerfile ويتم استدعاءه من ملف docker-compose.yml وداخله يتم تحديد الـ Docker image الأساسية المُراد استخدامها في التطوير مع إمكانية تخصيصها بأريحية أكبر، وهذا مثال عليه:
https://github.com/AliOsm/wisal/blob/main/.devcontainer/Dockerfile

وفيه يتم تحديد ghcr.io/rails/devcontainer/images/ruby:3.3.6 كـ Docker image أساسية، وتثبيت برمجية RustyWind الخاصة بمكتبة TailwindCSS.

بعد تجهيز DevContainer لمشروعك، ممكن كل عضو في الفريق يبنيها عنده بدون مشاكل، وممكن تشغيل المشروع على GitHub Codespaces على المتصفح كذلك من أي جهاز.

أخيرا، DevContainers مش لازم تستخدم مع VSCode فقط، ممكن تستخدمها مع محررات أخرى، ويوجد بدائل لها مثل موقع GitPod وبرنامج Flox.

والسلام عليكم 👋🏻
4👨‍💻1
من مميزات منصة باحث أنها تسمحلك بالبحث بالمعنى في الأحاديث النبوية والمكتبة الشاملة. البحث بالمعنى أو Semantic Search يعطيك الإمكانية للبحث من خلال طرح الأسئلة أو الأفكار العامة بدلا من كتابة النص كما هو في الحديث أو الكتاب. على سبيل المثال، ممكن تكتب "هل يجوز زيارة القبور؟" والنتائج من المفترض أن تحتوي على الأحاديث اللي فيها جواب سؤالك. أو ممكن تبحث عن "من هو الصحابي الذي تعلم لغة اليهود؟" والنتائج من المفترض أن يظهر فيها صفحات من كتب المكتبة الشاملة تحمل جواب لسؤالك. شرح أكثر عن المنصة في هذا المقطع:
https://youtu.be/vl90LkLgfE4

طيب، أين تقع المشكلة؟ المشكلة أن المكتبة الشاملة فيها أكثر من 8 آلاف كتاب وأكثر من 3 آلاف مؤلّف، وانت محتاج تعطي للمستخدم طريقة لتحديد نطاق البحث داخل الكتب والمؤلفين، وهذا يتضمن إما: 1) إظهار قائمة منسدلة Dropdown فيها كل أسماء الكتب أو المؤلفين والمستخدم يبحث ويختار نطاق البحث اللي محتاجه، أو 2) ممكن تعمل مربع للإدخال ويكون عليه خاصية تكملة تلقائية Autocomplete بدلا من إظهار كل أسماء الكتب والمؤلفين في الصفحة.

الطريقة الأولى أسهل من ناحية التنفيذ، الصفحة من البداية تأتي من الخادم فيها كل الكتب والمستخدم يختار والحياة لطيفة، ولكنها أسوأ من ناحية زمن الاستجابة (وهذه الطريقة كانت مُتبعة في منصة باحث م أسبوع). الطريقة الثانية أفضل من ناحية زمن الاستجابة، ولكن محتاجه شغل أكثر، وانا عندي "بعض" من الكسل 😂

#الجزء_الأول

أكمل من هنا 😁
2
من كم يوم خطرلي أستخدم ميزة من مميزات إطار عمل Ruby on Rails لإيجاد حل وسط بين الطريقتين وهي ميزة Lazy Turbo Frames واللي ممكن تقرأ عنها أكثر من هذا الرابط:
https://turbo.hotwired.dev/reference/frames

الميزة مش اختراع من Rails ولكن تطبيقها في Rails حسيته مباشر وبدون تعقيدات. كل الفكرة انك تعمل Route انت بدك تجيب المحتوى تبعه بعد ما الصفحة تظهر للمستخدم، وتعمل turbo_frame_tag داخل الصفحة تحكيله لما الصفحة تنتهي من التحميل وتظهر للمستخدم، انت جيب محتواك من هذا الـ Route واعرضه براحتك، الكود حرفيا سطر:

turbo_frame_tag('shamela-search-filters', lazy: true, src: shamela_filters_path)


ببساطة هذا السطر لما الصفحة تنتهي من التحميل بيبعث طلب للـ Route اللي اسمه shamela_filters_path وبيجيب المحتوى وبيعرضه.

هذا التعديل البسيط نزّل زمن الاستجابة للصفحة الرئيسية للمنصة من متوسط 150ms إلى متوسط 20ms زي ماهو موضّح في الصورة.

بهذه الطريقة المستخدم عنده كل أسماء الكتب والمؤلفين، وانا ما اضطريت أعدّل كود كثير، وزمن الاستجابة نزل، والعصافير تزقزق والحمدلله والسلام عليكم 👋🏻

#الجزء_الثاني

الجزء الأول من هنا 😁
3
تجربتي مع pgvector و ChromaDB 🥲

لتمكين البحث بالمعنى Semantic search في منصة باحث، كنت أبحث عن Vector DB تخدم هذا الهدف على مجموعات ضخمة من الـ Vectors.

بحكم استخدامي لـ PostgreSQL في باحث، فكان الخيار الأول هو pgvector واللي بتستخدم HNSW index واللي هو عبارة عن Index تقريبي أو Approximate لإيجاد الـ Vectors القريبة أثناء البحث بشكل سريع، ولكن التجربة من ناحية الاستخدام ما كانت ألطف شيء، والنتائج ما كانت جيدة مقارنة بالبحث الغير تقريبي اللي كنت كتبته يدويا لاختبار الفكرة قبل تطبيقها على المنصة.

فبدأت رحلة البحث عن Vector DB تحقق الشروط التالية:
- سهلة الاستخدام، يُفضّل تكون مجرد Docker container
- ممكن تتعامل مع عدد كبير من الـ Vectors
- تدعم الفرز أو Filters

ووقتها لقِلّة الخبرة، تحمست لـ ChromaDB وقررت استخدامها.

تجربة الاستخدام سلسة، خصوصا مع وجود مكتبة Ruby غير رسمية خاصة بها، والنتائج جيدة ومش بعيدة عن البحث الغير تقريبي (ممكن كان عندي مشكلة خلال استخدامي لـ pgvector وظلمتها بالنسبة للنتائج 🤔)، وخلال عملي كتبت مكتبة Rails منبية على مكتبة Ruby بحيث تسهل الاستخدام:
https://github.com/AliOsm/chromable

وفعلا، حطيت ChromaDB على باحث ودخّلت فيها أكثر من 330 ألف حديث (حاليا الأحاديث في المنصة أقل) وكانت تعمل بشكل جيد، مع بطئ في عملية الفرز أحيانا.

بعد فترة، قررت إضافة البحث بالمعنى في المكتبة الشاملة على منصة باحث، والخطة كانت واضحة، فقط حط البيانات في PostgreSQL ومكتبة chromable المفروض تنقلهم إلى ChromaDB والأمور سهلة.

فعلا بدأت العملية واستغرقت وقت طويل بسبب استخدام GPU واحد لتحويل المكتبة الشاملة إلى Embeddings، ولما انتهت العملية كانت المفاجأة 🎉

البحث والفرز باستخدام ChromaDB بطيئ لأبعد الحدود وأحيانا يُعطي Timeouts. عشان تكون في الصورة، الـ Index الخاص بالمكتبة الشاملة كان فيه أكثر من 11 مليون Vector، وهو رقم يُعتبر كبير لما نحكي عن Vector DBs.

من وقت إضافة هذه الميزة إلى المنصة من 8 شهور، والوضع كان سيئ من ناحية زمن الاستجابة، وحاولت حلّه بأكثر من طريقة وتواصلت مع فريق ChromaDB على Discord ولكن بدون حل مُجدي.

حاليا بختبر بقاعدة بيانات ثانية للـ Vectors وهي Qdrant ويبدو أنها أفضل وتدعم أمور أكثر زي الـ Multiple vectors لكل مستند أو Document ودعم ColBERT vectors والـ Sparse vectors والـ Fusion وكذلك الـ API الخاص بالبحث مرن جدا.

أحد الخيارات المطروحة كان قاعدة بيانات Vespa ولكن بعد القراءة عنها وجدت انها معقدة أكثر من اللازم بالنسبة للحالة الخاصة بمنصة باحث، فاستثنيتها.

إذا خطر ببالك سؤال شو يعني HNSW أو ColBERT أو Sparse أو Fusion أو ليش في أكثر من Vector لكل مستند، وغيرها من الأسئلة، فممكن تبحث عن الجواب، أو تنتظر المنشورات المستقبلية 😁

أما شو هي منصة باحث، فممكن تعرف من هون:
https://youtu.be/vl90LkLgfE4

وإذا كان عندك تجربة سيئة/جيدة مع قاعدة بيانات من القواعد المذكورة ياريت تشاركها 👀

والسلام عليكم 👋🏻
3
كيف تبدأ المشاريع مفتوحة المصدر ؟.؟

بدايةً أنا مش التنين المُجنّح صاحب المشاريع مفتوحة المصدر كثيرة النجوم والمستخدمين، وإنما أدّعي إنشائي لبعض المشاريع مفتوحة المصدر، عشان نكون على بيّنة 👀

طُرق بداية المشاريع مفتوحة المصدر كثيرة، قد تكون مُجرّد فكرة خطرت لك أو مشروع داخلي في شركة ما تم نشره للناس أو غيرها، ولكن من الطُّرق المُلهمة بالنسبة لي هي استخراج المشروع مفتوح المصدر من مشروع أساسي أكبر منه، ومن أكثر الناس تطبيقًا لهذا المبدأ هم الناس في 37Signals واللي هما أصحاب basecamp و hey.com وبشتغل معهم DHH اللي عامل Ruby on Rails (ذكرنا Rails في المنشور كالعادة 😂)

هذا الأمر حدث معي 4 مرات في آخر سنتين، 3 منهم مُتعلّقين بمنصة باحث وهما اللي ممكن أذكرهم كأمثلة:

* تفريغ

فكرة منصة باحث في الأساس هي تفريغ الدروس الشرعية إلى نصوص وتمكين المستخدمين من البحث داخلها والوصول إلى المعلومات بسرعة، وزي ما هو متوقع، محتاجين أداة لتحويل هذه الدروس من صوت إلى نص، وهنا تأتي مهمة تفريغ. تفريغ كان عبارة عن Script كبداية، ثم تحوّل إلى مكتبة مكتوبة بلغة Python تم تنزيلها أكثر من 40 ألف مرة وفَرّغت أكثر من 150 ألف ساعة وبُنِيت عليها مشاريع أخرى.

الرابط: https://github.com/ieasybooks/tafrigh

* Chromable

هذه ذكرتها في منشوري السابق، ولكن سريعًا، Chromable كانت مجرد module يُساعد في ربط قاعدة البيانات الأساسية بقاعدة بيانات الـ Vectors لتمكين البحث بالمعنى في باحث، ثم أتت الفكرة لتحويلها إلى مكتبة وفتح مصدرها من باب الفائدة وتقليل الكود الموجود داخل المشروع. المكتبة عبارة عن ملف واحد فيه تقريبا 125 سطر كود، ولكن سهّل استخدامي الشخصي لها وساعد "القليل" من الناس 😁

ملاحظة: إذا قرأت منشوري السابق فانت عارف انك مش لازم تستخدمها 😂

الرابط: https://github.com/AliOsm/chromable

* PhlexIcons

تُكتب الواجهات في Rails بتنسيق ERb أو Embedded Ruby. على سبيل المثال، بهذه الطريقة ممكن تلف حَلقة لعرض عناوين المقالات:

<%= @posts.each do |post| %>
<h1><%= post.title %></h1>
<% end %>


وبعد سنوات من العناء مع هذا التنسيق، اكتشفت وجود مكتبة اسمها Phlex، هي شيئ شبيه بـ JSX ولكن لـ Ruby، بحيث تقدر تكتب HTML باستخدام Ruby وتبني من خلالها Components ويتم تحويل اللي كتبته خلال التشغيل إلى HTML. المكتبة لطيفة ولكن واجهتني مشكلة وهي تحويل أيقونات SVG من HTML إلى Phlex لإضافتها داخل الموقع.

في البداية كنت أحوّل الأيقونات وأضعها داخل باحث، ثم ظهرت فكرة إنشاء مكتبة أيقونات خاصة بـ Phlex تضم داخلها أشهر مكتبات الأيقونات جاهزة للإستخدام. والحمدلله حاليا PhlexIcons تحوي داخلها 7 مكتبات للأيقونات بمجموع يتجاوز الـ 12 ألف أيقونة ولها موقع لعرض الأيقونات والبحث فيها ونسخ الكود لاستخدامه بسهولة داخل مشروعك.

الرابط: https://github.com/AliOsm/phlex-icons

هل هدف المنشور أحكيلكم عن مشاريعي اللي بستخدمها لحالي؟ أكيد لا، ولكن الهدف هو توضيح فكرة أن المشاريع مفتوحة المصدر قد تكون مجرد أثر جانبي لمشروعك الأساسي اللي انت بتشتغل عليه ومهتم فيه وهو مغلق المصدر، فحاول تشتغل على مشروعك الخاص ولو كان مغلق المصدر لأسباب مختلفة، مع الوقت ستجد أن المشروع بدأ يُنتج مشاريع مفتوحة المصدر في مجالات مختلفة.

وإن كنت ستسأل ما هي منصة باحث، فممكن تعرف من هنا:
https://youtu.be/vl90LkLgfE4

والسلام عليكم 👋🏻
5👍1
كيف نقيس أداء النظام باستخدام الـ Percentiles؟ 🤔

كثير ما نسمع عن p50 و p90 و p95 و p99 في سياق قياس أداء الأنظمة، ولكن شو يعني هذا الكلام وليش بنستخدمه؟

أولا خلينا نفهم شو هو الـ Percentile: ببساطة، الـ Percentile هو قيمة تخبرك أن نسبة معينة من البيانات أقل من أو تساوي قيمة معينة. على سبيل المثال، إذا كان p90 يساوي 100 فهذا يعني أن 90% من البيانات أقل من أو تساوي هذه القيمة و 10٪ أكبر من أو هذه القيمة.

طيب، ليش بنستخدم الـ Percentiles بدل المتوسط؟ 🤨

تخيل معي التالي: عندك نظام وبدك تقيس زمن الاستجابة فيه، وعندك 100 طلب وصلو للنظام:
- 90 طلب استغرقوا 100ms
- 9 طلبات استغرقوا 200ms
- طلب واحد استغرق 10 ثواني (أو 10000ms)

المتوسط في هذه الحالة: ((90 * 100) + (9 * 200) + (1 * 10000)) / 100 = 290ms

هل هذا الرقم يعكس واقع النظام؟ أكيد لا! لأن المتوسط يتأثر بشكل كبير بالقيم المُتطرّفة أو الـ Outliers، وفي حالتنا 99% من المستخدمين ما شافوا هذا الزمن أصلا 😅

هون بتيجي أهمية الـ Percentiles وفي حالة النظام السابق هي كالتالي:

- p50 (في الغالب هو نفسه الوسيط أو Median): 100ms
يعني أن 50% من الطلبات كانت أسرع من أو تساوي 100ms و50% كانت أبطأ.

- p90: 200ms
يعني أن 90% من الطلبات كانت أسرع من أو تساوي 200ms و10% فقط كانت أبطأ.

- p99: 10000ms
يشير إلى أسوأ 1% من الطلبات، والتي كانت بطيئة للغاية.

هذه الأرقام تعطيك صورة أوضح عن أداء النظام، وتقدر تحدد وين المشكلة بالضبط حسب نوعية الطلبات في كل شريحة من شرائح الـ Percentile.

طيب، كيف نحسب الـ Percentiles في SQL على جدول كبير؟ 🤓

في PostgreSQL عندك دالة جاهزة اسمها percentile_cont، استخدامها سهل:

SELECT
percentile_cont(0.5) WITHIN GROUP (ORDER BY response_time) as p50,
percentile_cont(0.9) WITHIN GROUP (ORDER BY response_time) as p90,
percentile_cont(0.95) WITHIN GROUP (ORDER BY response_time) as p95,
percentile_cont(0.99) WITHIN GROUP (ORDER BY response_time) as p99
FROM requests;


ولكن المشكلة أن هذه الدالة بتحتاج تقرأ كل البيانات وترتبهم، وهذا مش عملي على الجداول الكبيرة.

الحل؟ استخدام تقريب أو Approximation مع دالة percentile_disc:

SELECT
percentile_disc(0.5) WITHIN GROUP (ORDER BY response_time) as p50,
percentile_disc(0.9) WITHIN GROUP (ORDER BY response_time) as p90,
percentile_disc(0.95) WITHIN GROUP (ORDER BY response_time) as p95,
percentile_disc(0.99) WITHIN GROUP (ORDER BY response_time) as p99
FROM (
SELECT response_time
FROM requests
TABLESAMPLE SYSTEM(1)
) as sample;


هذا الكود بياخذ عينة عشوائية 1% من البيانات وبحسب عليها الـ Percentiles. النتيجة مش دقيقة 100% ولكنها كافية في معظم الحالات إذا كان الجدول كبير والبيانات متجانسة.

متى نستخدم كل Percentile؟
- p50 يعطيك الصورة العامة للأنظمة في الوضع الطبيعي
- p90 و p95 يساعدان في تحديد المشاكل المحتملة قبل أن تتأثر الغالبية العظمى من المستخدمين
- p99 لضمان تجربة جيدة حتى للمستخدمين في الحالات الشاذة داخل نظامك

نصيحة: لا تكتفي بمراقبة المتوسط، استخدم الـ Percentiles لفهم أعمق لأداء نظامك 🎯

والسلام عليكم 👋🏻
2
من فترة بسيطة تعرّفت على موقع Anna's Archive، وهذا رابطه:
https://annas-archive.li

الموقع عليه ملايين الكتب والأوراق العلمية وممكن تنزلها بصِيغ PDF أو EPUB، وخلال تجربتي وجدت عليه أحدث الإصدارات من كتب مختلفة (في مجال التقنية على الأقل).

أنا هنا لا أناقش حِل أو حُرمانية استخدام الموقع، فهذه كل إنسان يستفتي فيها عالم يثق فيه وفي علمه، ولكن استخدامي الشخصي للموقع حاليا هو التعرّف على محتويات الكتاب بشكل أفضل قبل شراءه، وهذا ما تفعله عند زيارة المكتبات بشكل عام.

كمشتري من أي مكتبة، لك إمكانية تصفح محتويات الكتاب قبل شراءه منها، وهذا يختلف عن العينة أو الـ Sample اللي توفره مواقع زي أمازون، فهي تتيح مقدمة صغيرة من الكتاب والفهرس في غالب الأحيان.

والسلام عليكم 👋🏻
3
علامات التعجب والاستفهام في نهاية دوال لغة Ruby 🤔❗️

من الأمور المميزة في لغة Ruby هو إمكانية إنهاء أسماء الدوال بعلامة التعجّب (!) أو علامة الاستفهام (؟)، هذه الميزة مش لتزيين الدوال أكيد، ولكن لها دلالات مهمة تساعد المبرمجين على فهم سلوك الدالة بشكل أفضل.

🔹 الدوال المنتهية بعلامة الاستفهام (؟) عادةً ما تُستخدم مع الدوال اللي بترجّع قيمة منطقية (true/false)، على سبيل المثال:

10.odd? # => false
"hello".include?("h") # => true


هذه التسمية بتخلي الكود أكثر قابلية للقراءة، فلما تشوف الدالة تنتهي بعلامة استفهام بتعرف مباشرة أنك تتعامل مع قيَم منطقية.

🔸 الدوال المنتهية بعلامة التعجّب (!) تُستخدم غالباً للإشارة إلى أن الدالة قد تكون "خطرة" أو أنها تُعدّل الكائن الأصلي، على سبيل المثال:

string = "hello"
string.upcase # => "HELLO" (لم يتغيّر المُتغَيّر)
string.upcase! # => "HELLO" (تغيّر المُتغَيّر)


الفرق هنا أن upcase مع علامة التعجّب تُعدّل الكائن الأصلي، بينما upcase بدون علامة التعجّب تُرجع نسخة جديدة دون تعديل الأصل.

💡 لماذا هذا مفيد؟
- وضوح الكود: بتقدر تفهم سلوك الدالة من اسمها مباشرة
- الأمان: بتقدر توصّل رسائل للمبرمجين خلال كتابتهم للكود أن الدالة قد تُغير حالة الكائن مثلا
- اتساق التصميم: كل مكتبات اللغة تتبع نفس الأسلوب وهذا يُعطيك أريحية في قراءة الكود وفهمه بشكل أكبر

🔍 ملاحظة مهمة: هذه الاصطلاحات مش إجبارية في Ruby، بس هي ممارسات جيدة متفق عليها في المجتمع بشكل عام، واستخدامها بالطريقة الصحيحة يجعل الكود أكثر وضوحاً وسهولة في التتبّع.

هل مر عليك ميزة شبيهة في لغات ثانية ؟.؟ وهل استخدمت هذه الميزة في Ruby من قبل؟

والسلام عليكم 👋🏻
👍21
ميزة method_missing في Ruby من الميزات اللي بتخليك تحب اللغة أكثر 🤩

تخيّل معي الموقف التالي: عندك object أو كائن ما وحاولت تستدعي دالة غير موجودة عليه، شو بصير؟ في معظم لغات البرمجة رح تشوف error يقولك إنه الـدالة مش موجودة أو MethodNotFound.

في Ruby الموضوع مختلف، لما تستدعي دالة غير موجودة على كائن معيّن، Ruby بتدور على دالة اسمها method_missing على نفس الـكائن، وإذا لقتها بتستدعيها وبتمرر معها اسم الدالة اللي حاولت تستدعيها والـ arguments اللي مررتها.

مثال بسيط:

class User
def method_missing(method_name, *args)
puts "You called #{method_name} with #{args}"
end
end

user = User.new
user.hello("world") # => You called hello with ["world"]


هذه الميزة بتفتح مجال واسع لما يسمّى metaprogramming. على سبيل المثال، إطار العمل Rails يستخدم هذه الميزة في ActiveRecord ORM أو Object Relational Mapper لتمكين البحث في قاعدة البيانات باستخدام أسماء الأعمدة بشكل مباشر. لنفترض أن عندك جدول users فيه عمود name، فممكن تكتب التالي:

User.find_by_name("أحمد") # => يبحث عن المستخدم اللي اسمه أحمد


الدالة اللي اسمها find_by_name مش موجودة أصلا! ولكن Rails يستخدم method_missing لتحليل اسم الدالة وتحويله إلى query على قاعدة البيانات 🪄

تعرّفت على هذه الميزة لأول مرة من خلال كتاب Metaprogramming Ruby للكاتب Paolo Perrotta، وهو من أفضل الكتب اللي قرأتها عن Ruby. الكتاب بشرح كيف Ruby تعمل من الداخل وكيف تقدر تستغل مميزاتها بأفضل طريقة.

نصيحتي لأي شخص مهتم بـ Ruby: اقرأ هذا الكتاب، رح يغيّر نظرتك للغة وطريقة كتابتك للكود 📚

هل مر عليك ميزة شبيهة في لغات ثانية ؟.؟ وهل استخدمت هذه الميزة في Ruby من قبل؟ شاركنا تجربتك 👇

والسلام عليكم 👋🏻
3👍2
كيف تستفيد من Google Colab بعيدًا عن الذكاء الاصطناعي وهمومه 🤔😂

من الاختراعات الجميلة اللي عملتها البشرية هو Google Colab، مفيد جدا في تجربة أفكار مختلفة بشكل سريع وخصوصا لما تحتاج معالج رسومي أو GPU بذاكرة عالية شويتين زي A100 أو T4 مثلا.

ولكن في آخر سنتين بدأت أستخدمه استخدام مختلف قليلا من خلال توفير واجهة للناس لاستخدام بعض المكتبات اللي بعملها أو مشاريع ثانية مفيدة ولكن ما لها واجهة سهلة للاستخدام إلا من خلال الكود أو CLI، بحيث ما أضطر أعمل موقع مثلا وأحطه على خادم وتكاليف ومتابعة وفي نفس الوقت أوصّل الفائدة للمستخدمين.

هذا الأمر عملته إلى الآن مع مكتبتين: تفريغ وتحويل (أنا في الأسماء مُبدِع إبداع رهيب)

تفريغ مهمتها تحويل المواد المرئية والمسموعة إلى نصوص من خلال الذكاء الاصطناعي باستخدام نماذج Whisper أو الـ APIs الخاصة بـ wit.ai.

تفريغ مكتوبة بـ Python وممكن استخدامها من خلال الكود أو CLI، ولكن المستخدم العادي لا يعرف يكتب كود ولا يعرف يستخدم CLI، وأنا ما عندي القدرة على إنشاء SaaS ومتابعتها لتوفير هذه الخدمة للناس.

فكان الحل إنشاء Google Colab Notebook لها واجهة تقبل من المستخدم رابط مادة من YouTube وبعض الإعدادات وتقوم بتحميل المادة وتفريغها وتنزيل المخرجات على جهاز المستخدم مباشرةً.

ممكن تشوف الـ Notebook وكيفية استخدامها من الرابطين التاليين:
- https://tafrigh.ieasybooks.com
- https://youtu.be/qFsUwp5iomU

نفس الفكرة طبَّقتها مع تحويل وهي أداة مهمتها تحويل الكتب من صيغة PDF إلى TXT/DOCX باستخدام Google Drive APIs، ونفس الأمر تكرر، تحويل مكتوبة بـ Python وممكن تستخدمها من خلال الكود أو الـ CLI، ولكن المستخدم العادي...

فكان الحل...

وممكن تشوف الـ...:
- https://tahweel.ieasybooks.com
- https://youtu.be/MsLRFT50pNo

هل هذه الطريقة ناجحة؟ إلى الآن تفريغ تم تنزيلها أكثر من 40 ألف مرة وتحويل أكثر من 12 ألف مرة، وهذا يعطينا تلميح أن الناس قادرة تستخدم الـ Notebooks لما يكون لها واجهة مع وجود شرح بسيط لطريقة الاستخدام.

الخطوة القادمة بإذن الله هي إنشاء Notebooks أو "كُنَّاشات" أكثر لإتمام مهام مختلفة وهذا ما سيتم في هذا المستودع بإذن الله:
https://github.com/ieasybooks/kunnashat

والكُنَّاشة من تعاريفها "الأوراقُ تُجْعَلُ كالدَّفْتَر تُقيَّدُ فيها الفوائدُ والشوارد" حسب موقع المعاني 😁

فمن الكُنَّاشات اللي بفكر أعملها:
- تقطيع لتقطيع المواد المرئية والمسموعة
- تفريق لإزالة الموسيقى عن الصوت
- تنقية لإزالة السكتات من الصوت
- تلخيص لتلخيص النصوص
- تعتيم لتعتيم الوجوه والمشاهد غير الشرعية في المواد
- شعر لإنشاء الشعر العربي
- تشكيل لتشكيل النصوص العربية

كل هذه ممكن تكون مكتبات يُنشأ لها كُنَّاشات أو مجرد كُنَّاشات مبعثرة يستفيد منها الناس.

إذا حاب تساهم ممكن تفتح PR على المستودع وسأكون أكثر من سعيد لمراجعتها، أو ممكن تشاركنا أفكار أخرى لكُنَّاشات يمكن إضافتها.

والسلام عليكم 👋🏻
👍3❤‍🔥111
تطبيقات الهاتف وعبء تطويرها 😪

من الأشياء اللي كانت مطلوبة بكثرة من مستخدمي منصة باحث هي تطبيقات الهاتف للـ 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