<?xml version="1.0"?>
<rss version="2.0"><channel><title>&#x627;&#x644;&#x628;&#x631;&#x645;&#x62C;&#x629;: &#x645;&#x642;&#x627;&#x644;&#x627;&#x62A; &#x639;&#x627;&#x645;&#x629; &#x62D;&#x648;&#x644; &#x627;&#x644;&#x628;&#x631;&#x645;&#x62C;&#x629;</title><link>https://academy.hsoub.com/programming/general/page/9/?d=2</link><description>&#x627;&#x644;&#x628;&#x631;&#x645;&#x62C;&#x629;: &#x645;&#x642;&#x627;&#x644;&#x627;&#x62A; &#x639;&#x627;&#x645;&#x629; &#x62D;&#x648;&#x644; &#x627;&#x644;&#x628;&#x631;&#x645;&#x62C;&#x629;</description><language>ar</language><item><title>&#x62C;&#x639;&#x644; &#x62A;&#x637;&#x628;&#x64A;&#x642; &#x627;&#x644;&#x648;&#x64A;&#x628; &#x627;&#x644;&#x62A;&#x642;&#x62F;&#x645;&#x64A; PWA &#x64A;&#x628;&#x62F;&#x648; &#x643;&#x62A;&#x637;&#x628;&#x64A;&#x642; &#x623;&#x633;&#x627;&#x633;&#x64A; &#x641;&#x64A; &#x646;&#x638;&#x627;&#x645; &#x627;&#x644;&#x62A;&#x634;&#x63A;&#x64A;&#x644;</title><link>https://academy.hsoub.com/programming/general/%D8%AC%D8%B9%D9%84-%D8%AA%D8%B7%D8%A8%D9%8A%D9%82-%D8%A7%D9%84%D9%88%D9%8A%D8%A8-%D8%A7%D9%84%D8%AA%D9%82%D8%AF%D9%85%D9%8A-pwa-%D9%8A%D8%A8%D8%AF%D9%88-%D9%83%D8%AA%D8%B7%D8%A8%D9%8A%D9%82-%D8%A3%D8%B3%D8%A7%D8%B3%D9%8A-%D9%81%D9%8A-%D9%86%D8%B8%D8%A7%D9%85-%D8%A7%D9%84%D8%AA%D8%B4%D8%BA%D9%8A%D9%84-r1528/</link><description><![CDATA[
<p><img src="https://academy.hsoub.com/uploads/monthly_2022_04/625e5029a73d4_----PWA---.png.e7701e27bc47487ffc9fc73c9231d258.png" /></p>

<p>
	لفظ مصطلح <a href="https://academy.hsoub.com/programming/general/%D9%85%D8%AF%D8%AE%D9%84-%D8%A5%D9%84%D9%89-%D8%AA%D8%B7%D8%A8%D9%8A%D9%82%D8%A7%D8%AA-%D8%A7%D9%84%D9%88%D9%8A%D8%A8-%D8%A7%D9%84%D8%AA%D9%82%D8%AF%D9%85%D9%8A%D8%A9-pwa-r832/" rel="">تطبيق الويب التقدمي progressive web application</a> -ويختصر إلى PWA- يُعَد إشاعة مدوِّية، فمن المراهن أن تطبيقات الويب التقدمية مجرد مواقع ويب، إذ يُقِر <a href="https://docs.microsoft.com/en-us/microsoft-edge/progressive-web-apps-chromium/#progressive-web-apps-on-windows:~:text=PWAs%20are%20just%20websites" rel="external nofollow">توثيق PWA</a> في Microsoft بهذا، و<a href="https://web.dev/" rel="external nofollow">موقع web.dev</a> يتفق مع هذا الإعتبار، وحتى مرشّحَي PWA فرانسيس بيريمان Frances Berriman وأليكس راسل Alex Russell <a href="https://infrequently.org/2015/06/progressive-apps-escaping-tabs-without-losing-our-soul/#post-2263:~:text=they%E2%80%99re%20just%20websites" rel="external nofollow">يقولا ذلك</a> أيضًا.
</p>

<p>
	أجل، تطبيقات الويب التقدمية PWAs هي مجرد مواقع ويب، لكنها في الوقت نفسه أكثر من ذلك بكثير، إذا طوِّر تطبيق PWA على أكمل وجه، فلن يبدو وكأنه موقع ويب، بل سيبدو كتطبيق حقيقي real app، لكن ماذا يعني أنْ يبدو موقع الويب كتطبيق حقيقي؟
</p>

<p>
	للإجابة على ذلك، دعنا نأخذ تطبيق Apple Podcasts كمثال، يتوفر هذا التطبيق على نظام macOS لبيئة سطح المكتب وعلى نظام iOS (ونظام iPadOS) لبيئة الهاتف المحمول، فيُعد تطبيق Podcasts أحد تطبيقات الوسائط، لكن زبدة الأفكار التي سنوضحها من خلاله في هذا المقال تنطبق أيضًا على أنواع أخرى من التطبيقات.
</p>

<p style="text-align: center;">
	<a class="ipsAttachLink ipsAttachLink_image" data-fileid="96561" href="https://academy.hsoub.com/uploads/monthly_2022_04/01apple_podcasts.png.c0fbbe3d852179914e4bd17295c5ca5b.png" rel=""><img alt="01apple_podcasts.png" class="ipsImage ipsImage_thumbnailed" data-fileid="96561" data-unique="794aqplj8" src="https://academy.hsoub.com/uploads/monthly_2022_04/01apple_podcasts.thumb.png.5220924e0fd5a2f2cd00bc6ff4574fd5.png" style="width: 600px; height: auto;"></a>
</p>

<p style="text-align: center;">
	تطبيق Apple Podcasts على iPhone وmacOS (<a href="https://support.apple.com/en-us/HT201859" rel="external nofollow">المصدر</a>)
</p>

<p>
	تحذير: يوجد لكل ميزة من ميزات التطبيق المدرجة في الأسفل (على أنظمة iOS وAndroid وسطح المكتب) فقرة <strong>كيف تفعل هذا في الويب</strong>، يمكنك قرائتها لمزيد من التفاصيل حول تطبيق الميزة في مواقعك.
</p>

<p>
	يرجى ملاحظة أن المتصفحات على أنظمة التشغيل المختلفة لا تدعم كلها جميع المميزات المدرجة هنا؛ لذا تأكد من مراجعة ملاحظات التوافقية بدقة ضمن المقالات المرتبطة.
</p>

<h2>
	إمكانية التشغيل دون اتصال بالشبكة
</h2>

<p>
	إذا راجعت النظر في بعض التطبيقات الخاصة بأنظمة التشغيل الأساسية سواء على هاتفك المحمول أو حاسوبك المكتبي، ستلاحظ أنك لا تحصل على أي محتوى أبدًا دون اتصال بالشبكة، لكن في تطبيق Podcasts، حتى لو كنت غير متصل بالشبكة، فهناك دائمًا محتوى يمكنك مشاهدته في التطبيق.
</p>

<p>
	لا يعرض قسم <strong>أفضل المصوَّرات</strong> top charts أي محتوى، ويعرض بدلاً من ذلك رسالة "لا يمكن الاتصال الآن" مقترنة بزر إعادة المحاولة. قد لا تكون هذه أفضل تجربة استخدام، ولكن يمكنك على الأقل قراءة شيء على الشاشة.
</p>

<p style="text-align: center;">
	<a class="ipsAttachLink ipsAttachLink_image" data-fileid="96562" href="https://academy.hsoub.com/uploads/monthly_2022_04/02podcasts_without_network_connection.png.d21e80d809277b77822cff1ac9875546.png" rel=""><img alt="02podcasts_without_network_connection.png" class="ipsImage ipsImage_thumbnailed" data-fileid="96562" data-unique="sl5fm4c9n" src="https://academy.hsoub.com/uploads/monthly_2022_04/02podcasts_without_network_connection.png.d21e80d809277b77822cff1ac9875546.png" style="width: 700px; height: auto;"></a>
</p>

<p style="text-align: center;">
	تطبيق Podcasts دون اتصال بالشبكة.
</p>

<p>
	يتبع تطبيق Podcasts نموذج معماري يسمى هيكل التطبيق app shell model، كل المحتوى الثابت اللازم لعرض التطبيق الأساسي يخزّن مؤقتًا محليًا، بما في ذلك الصور المزخرفة مثل أيقونات القائمة اليسرى وأيقونات واجهة المستخدم الأساسية للمشغِّل. لا يُحمَّل المحتوى الديناميكي (مثل بيانات <strong>أفضل المصوَّرات</strong>) إلا عند الطلب، مع توفُّر محتوى احتياطي مخزن مؤقتًا محليًا في حالة فشل التحميل.
</p>

<p>
	يمكنك قراءة المقال <a href="https://developers.google.com/web/fundamentals/architecture/app-shell" rel="external nofollow">The App Shell Model</a> لمعرفة كيفية تطبيق هذا النموذج المعماري على تطبيق الويب الخاص بك.
</p>

<h2>
	المحتوى متاح والوسائط قابلة للتشغيل دون اتصال
</h2>

<p>
	لا يزال بإمكانك الانتقال إلى قسم <strong>التنزيلات</strong> والاستمتاع بحلقات البث الصوتي podcasts المحملة الجاهزة للتشغيل والمعروضة مع جميع بياناتها الوصفية مثل الصور والأوصاف وذلك أثناء عدم الاتصال بالشبكة، عبر الواجهة المسحوبة على اليسار.
</p>

<p style="text-align: center;">
	<a class="ipsAttachLink ipsAttachLink_image" data-fileid="96563" href="https://academy.hsoub.com/uploads/monthly_2022_04/03downloaded_podcasts_playable_offline.png.2014d280a871c6f56a43d7ed70967be5.png" rel=""><img alt="03downloaded_podcasts_playable_offline.png" class="ipsImage ipsImage_thumbnailed" data-fileid="96563" data-unique="sinzjo61s" src="https://academy.hsoub.com/uploads/monthly_2022_04/03downloaded_podcasts_playable_offline.png.2014d280a871c6f56a43d7ed70967be5.png" style="width: 700px; height: auto;"></a>
</p>

<p style="text-align: center;">
	يمكن تشغيل حلقات البث الصوتي المحملة حتى دون اتصال بالشبكة.
</p>

<p>
	يمكن تقديم محتوى الوسائط المحملة مسبقًا من ذاكرة التخزين المؤقت cache، مثلًا باستخدام استراتيجية تخديم مقاطع الصوت والفيديو المخزنة مؤقتًا serve cached audio and video والتي تقدمها مكتبة Workbox. يمكن دائمًا تخزين المحتويات الأخرى في ذاكرة التخزين المؤقت أو في قاعدة البيانات المفهرسة IndexedDB.
</p>

<p>
	إذا كان لديك بيانات يجب تخزينها تخزينًا دائمًا دون التعرض لاحتمال زوالها عند انخفاض حجم الذاكرة المتاح؛ فيمكنك استخدام الواجهة البرمجية <a href="https://developer.mozilla.org/en-US/docs/Web/API/StorageManager/persist" rel="external nofollow">Persistent Storage <abbr title="Application Programming Interface | واجهة برمجية">API</abbr></a> (التخزين الثابت) التي تعمل في الخلفية.
</p>

<h2>
	خلفية تنزيل استباقية
</h2>

<p>
	عندما تعاود الاتصال بالشبكة، يمكنك بالطبع البحث عن محتوى معين في التطبيق، مثلا تستعلم عن "HTTP 203" في خانة البحث، وبعد أن تظهر النتيجة، إذا اشتركت في أحد سلاسل حلقات "HTTP 203"، فإن أحدث حلقة من تلك السلسلة ستُنزّل مباشرة دون إذنك.
</p>

<p style="text-align: center;">
	<a class="ipsAttachLink ipsAttachLink_image" data-fileid="96564" href="https://academy.hsoub.com/uploads/monthly_2022_04/04latest_episode_downloaded.png.d91330365c33f9fe119533ef7f4e8723.png" rel=""><img alt="04latest_episode_downloaded.png" class="ipsImage ipsImage_thumbnailed" data-fileid="96564" data-unique="3r3cr0f3d" src="https://academy.hsoub.com/uploads/monthly_2022_04/04latest_episode_downloaded.thumb.png.7a619ad2f207d4275043e2bbd26dd516.png" style="width: 700px; height: auto;"></a>
</p>

<p style="text-align: center;">
	بعد الاشتراك في سلسلة حلقات بث ما، تُنزّل أحدث حلقة منها مباشرة.
</p>

<p>
	تنزيل أحد حلقات بث ما قد يستغرق وقتًا طويلًا، لذا تتيح لك الواجهة البرمجية fetch التي تعمل في الخلفية <a href="https://academy.hsoub.com/programming/javascript/%D8%A7%D9%84%D9%88%D8%A7%D8%AC%D9%87%D8%A9-%D8%A7%D9%84%D8%A8%D8%B1%D9%85%D8%AC%D9%8A%D8%A9-fetch-%D9%81%D9%8A-javascript-r739/" rel="">Background Fetch <abbr title="Application Programming Interface | واجهة برمجية">API</abbr></a> تفويض عمليات التنزيل إلى المتصفح الذي يعتني بها في الخلفية، وفي نظام Android، يمكن للمتصفح بدوره تفويض مهمة التنزيل هذه إلى نظام التشغيل، بالتالي لا يلزم إبقاء المتصفح مُشغّلًا، وبمجرد اكتمال التنزيل، يتم إيقاظ عامل خدمة تطبيقك <a href="https://academy.hsoub.com/programming/general/%D9%85%D9%81%D9%87%D9%88%D9%85-service-worker-%D9%88%D8%AA%D8%A3%D8%AB%D9%8A%D8%B1%D9%87-%D9%81%D9%8A-%D8%A3%D8%AF%D8%A7%D8%A1-%D9%88%D8%A8%D9%86%D9%8A%D8%A9-%D9%85%D9%88%D8%A7%D9%82%D8%B9-%D9%88%D8%AA%D8%B7%D8%A8%D9%8A%D9%82%D8%A7%D8%AA-%D8%A7%D9%84%D9%88%D9%8A%D8%A8-r833/" rel="">service worker</a> وبذلك يمكنك تحديد ماذا تفعل في الاستجابة.
</p>

<h2>
	المشاركة والتفاعل مع التطبيقات الأخرى
</h2>

<p>
	يتكامل تطبيق Podcasts بشكل طبيعي مع التطبيقات الأخرى، مثلًا عندما تنقر بزر الفأرة الأيمن فوق حلقة تعجبك؛ يمكنك مشاركتها مع تطبيقات أخرى على جهازك، مثل تطبيق الرسائل، كما إن تطبيق Podcasts يتكامل بشكل طبيعي مع حافظة النظام clipboard، إذ يمكنك النقر بزر الفأرة الأيمن فوق أي حلقة ونسخ رابطها إلى الحافظة.
</p>

<p style="text-align: center;">
	<img alt="05sharing_podcasts_episode_to_messages.png" class="ipsImage ipsImage_thumbnailed" data-fileid="96565" data-unique="29gxhc8g9" src="https://academy.hsoub.com/uploads/monthly_2022_04/05sharing_podcasts_episode_to_messages.png.f4f4d4465b63bac98fa35b03caa50c2b.png" style="width: 550px; height: auto;"></p>

<p style="text-align: center;">
	مشاركة حلقة بث على تطبيق الرسائل.
</p>

<p>
	كيف تفعل هذا في الويب؟ تتيح الواجهتان البرمجيتان Web Share وWeb Share Target (مشاركة وُجْهِة الويب) لتطبيقك مشاركة واستقبال النصوص والملفات والروابط من وإلى التطبيقات الأخرى على جهاز المستخدم.
</p>

<p>
	صحيح أنه لا يمكن لتطبيق ويب حتى اللحظة إضافة عناصر قائمة جديد إلى قائمة زر الفأرة الأيمن المضمنة في نظام التشغيل، إلا أن هناك عدة طرق أخرى للمشاركة من وإلى التطبيقات الأخرى على الجهاز، فباستخدام الواجهة البرمجية Clipboard غير المتزامنة يمكنك برمجيًا قراءة وكتابة النصوص والصور (صور PNG) إلى حافظة النظام.
</p>

<p>
	ويمكنك في نظام Android استخدام الواجهة البرمجية Contact Picker <abbr title="Application Programming Interface | واجهة برمجية">API</abbr> التي تعمل في الخلفية لاختيار جهات اتصال معينة كمدخلات لأحد التطبيقات.
</p>

<p>
	إذا كانت أحد وظائف برنامجك تحتاج تشغيل أحد الخيارين: تطبيق خاص بنظام التشغيل الأساسي أو تطبيق PWA، وقتها يمكنك استخدام الواجهة البرمجية get installed related apps (جلب التطبيقات المثبتة المشابهة) للتحقق ما إذا كان تطبيق النظام الأساسي مثبتًا على حاسوب المستخدم أم لا، إذا كان مثبتًا بالفعل؛ فإنك لا تحتاج أن تعرض للمستخدم خيار تشغيل PWA من الأساس.
</p>

<h2>
	تحديث التطبيق في الخلفية
</h2>

<p>
	يمكنك إعداد التطبيق لتنزيل حلقات بث جديدة تلقائيًا عبر إعدادات تطبيق Podcasts، بهذا أنت لست مضطرًا حتى للتفكير في المستجدات، فالمحتوى المحدث سيكون دائمًا موجودًا لديك.
</p>

<p style="text-align: center;">
	<a class="ipsAttachLink ipsAttachLink_image" data-fileid="96566" href="https://academy.hsoub.com/uploads/monthly_2022_04/06podcasts_configuration.png.e2556cb9b42833d5b1e74be43545ebe5.png" rel=""><img alt="06podcasts_configuration.png" class="ipsImage ipsImage_thumbnailed" data-fileid="96566" data-unique="okly290zt" src="https://academy.hsoub.com/uploads/monthly_2022_04/06podcasts_configuration.png.e2556cb9b42833d5b1e74be43545ebe5.png" style="width: 450px; height: auto;"></a>
</p>

<p style="text-align: center;">
	إعداد Podcasts لمراقبة حلقات البث الجديدة كل ساعة.
</p>

<p>
	كيف تفعل هذا في الويب؟ تتيح واجهة المزامنة الدورية التي تعمل في الخلفية Periodic Background Sync <abbr title="Application Programming Interface | واجهة برمجية">API</abbr> لتطبيقك بتحديث محتواه بانتظام في الخلفية دون الحاجة إلى أن يكون مشغَّلًا. هذا يعني أن المحتوى الجديد متاح استباقيًا، بالتالي يمكن لمستخدمي تطبيقك الغوص فيه مباشرة متى شاؤوا.
</p>

<h2>
	الحالة متزامنة عبر السحابة
</h2>

<p>
	يتم مزامنة اشتراكاتك عبر جميع أجهزتك في ذات الوقت وفي عالم سلس، فلا داعي للقلق بشأن مزامنة اشتراكاتك في حلقات البث يدويًا. وبالمثل، لا داعي للخوف من أن تُستهلك ذاكرة هاتفك المحمول بسبب حلقات البث التي استمعت إليها على سطح المكتب والعكس، إذ تُزامن حالة تشغيل كل حلقة وتُحذف حلقات البث المستَمع إليها تلقائيًا.
</p>

<p style="text-align: center;">
	<a class="ipsAttachLink ipsAttachLink_image" data-fileid="96567" href="https://academy.hsoub.com/uploads/monthly_2022_04/07state_synchronized_over_cloud.png.569eefe477da04487eef9d636bb2e3a9.png" rel=""><img alt="07state_synchronized_over_cloud.png" class="ipsImage ipsImage_thumbnailed" data-fileid="96567" data-unique="nft7bapbg" src="https://academy.hsoub.com/uploads/monthly_2022_04/07state_synchronized_over_cloud.png.569eefe477da04487eef9d636bb2e3a9.png" style="width: 450px; height: auto;"></a>
</p>

<p style="text-align: center;">
	الحالة متزامنة عبر التخزين السحابي.
</p>

<p>
	يمكنك تفويض مهمة مزامنة حالة بيانات التطبيق إلى الواجهة البرمجية Background Sync <abbr title="Application Programming Interface | واجهة برمجية">API</abbr> التي تعمل في الخلفية. لا يجب أن تتم مزامنة المستخدم مباشرة عندما يفتح التطبيق للمرة الأولى، بل تمامًا في نهاية زيارته، وحتى ربما يُستحسن أن تتم مزامنته عندما يغلق التطبيق أو ينتهي من استخدامه للمرة الثانية.
</p>

<h2>
	التحكم في التطبيق عبر أزرار الجهاز
</h2>

<p>
	عندما تكون مشغولاً بتطبيق آخر، مثلًا قراءة صفحة أخبار في متصفح Chrome، لا يزال بإمكانك التحكم في تطبيق Podcasts باستخدام مفاتيح الوسائط في حاسوبك المحمول؛ فلست مضطرًا للانتقال إلى التطبيق فقط من أجل تمرير حلقة البث للأمام أو للخلف.
</p>

<p style="text-align: center;">
	<a class="ipsAttachLink ipsAttachLink_image" data-fileid="96568" href="https://academy.hsoub.com/uploads/monthly_2022_04/625e503421633_08media_keys_controls_podcasts.png.78d20968ae9173dcc557f3de64627087.png" rel=""><img alt="08media_keys_controls_ podcasts.png" class="ipsImage ipsImage_thumbnailed" data-fileid="96568" data-unique="vdh5k0fdz" src="https://academy.hsoub.com/uploads/monthly_2022_04/625e503421633_08media_keys_controls_podcasts.png.78d20968ae9173dcc557f3de64627087.png" style="width: 580px; height: auto;"></a>
</p>

<p style="text-align: center;">
	التحكم بتطبيق Podcasts عبر مفاتيح الوسائط (<a href="https://support.apple.com/guide/macbook-pro/magic-keyboard-apdd0116a6a2/mac" rel="external nofollow">المصدر</a>).
</p>

<p>
	تدعم الواجهة البرمجية media session (جلسة الوسائط) التي تعمل في الخلفية Media Session <abbr title="Application Programming Interface | واجهة برمجية">API</abbr> أزرار الوسائط في الجهاز، بهذا يمكن للمستخدمين الاستفادة من أزرار وسائط الأجهزة ضمن لوحات المفاتيح أو سماعات الرأس أو حتى أزرار وسائط البرامج في ساعاتهم الذكية، للتحكم في تطبيق الويب.
</p>

<h2>
	تعدد المهام واختصارات التطبيق
</h2>

<p>
	يمكنك دائمًا القيام بمهام متعددة والعودة إلى Podcasts من أي تطبيق كنت فيه بدون مشاكل، ويوجد للتطبيق اختصار مميز وواضح يمكنك وضعه على سطح المكتب أو شريط تطبيقاتك dock لتشغله مباشرة عندما ترغب باستخدامه.
</p>

<p style="text-align: center;">
	<a class="ipsAttachLink ipsAttachLink_image" data-fileid="96569" href="https://academy.hsoub.com/uploads/monthly_2022_04/09multitasking_back_to_podcasts.png.2284b1938773c94d950f8f6eed1156cb.png" rel=""><img alt="09multitasking_back_to_podcasts.png" class="ipsImage ipsImage_thumbnailed" data-fileid="96569" data-unique="zuh3fgnf8" src="https://academy.hsoub.com/uploads/monthly_2022_04/09multitasking_back_to_podcasts.thumb.png.6420c6efa6fde3108063c61fec85fc30.png" style="width: 650px; height: auto;"></a>
</p>

<p style="text-align: center;">
	تنفيذ مهام متعددة والرجوع لتطبيق Podcasts.
</p>

<p>
	يمكن تثبيت تطبيقات الويب التقدمية على كلًا من سطح المكتب وشاشة الهاتف المحمول الرئيسية أو قائمة البدء start menu أو شريط dock، ويمكن أن يحدث التثبيت بناءً على طلب مسبق من المستخدم، أو يتحكم مطور التطبيق فيه بالكامل. يغطي مقال <a href="https://academy.hsoub.com/programming/general/%D8%AA%D8%AD%D8%AF%D9%8A%D8%AF-%D8%A7%D8%B3%D8%AA%D8%B1%D8%A7%D8%AA%D9%8A%D8%AC%D9%8A%D8%A9-%D8%AA%D8%AB%D8%A8%D9%8A%D8%AA-%D8%AA%D8%B7%D8%A8%D9%8A%D9%82-%D8%A7%D9%84%D9%88%D9%8A%D8%A8-%D8%A7%D9%84%D8%AA%D9%82%D8%AF%D9%85%D9%8A-pwa-r1490/" rel="">ما الذي يلزم التطبيق ليكون قابلًا للتثبيت؟</a> كل ما تحتاج إلى معرفته بهذا الخصوص. عند القيام بمهام متعددة، تبدو تطبيقات الويب التقدمية مستقلة عن المتصفح.
</p>

<h2>
	إدراج إجراءات التطبيق الشائعة ضمن قائمة مختصرة
</h2>

<p>
	يمكن تنفيذ إجراءات التطبيق الأكثر شيوعًا (اختصارات التطبيق) مثل <strong>البحث</strong> عن محتوى جديد و<strong>مراقبة حلقات البث الجديدة</strong>؛ مباشرة من قائمة اختصار التطبيق في شريط dock، كما يمكنك فتح التطبيق تلقائيًا عند تسجيل الدخول للنظام وذلك عبر قائمة <strong>خيارات</strong>.
</p>

<p style="text-align: center;">
	<a class="ipsAttachLink ipsAttachLink_image" data-fileid="96570" href="https://academy.hsoub.com/uploads/monthly_2022_04/10quick_actions__from__icon.png.48dd544aa474f847063dc8c4ed41bf00.png" rel=""><img alt="10quick_actions__from__icon.png" class="ipsImage ipsImage_thumbnailed" data-fileid="96570" data-unique="llntoa102" src="https://academy.hsoub.com/uploads/monthly_2022_04/10quick_actions__from__icon.thumb.png.205270cdc3a170fae5deebc80d29f0c0.png" style="width: 300px; height: auto;"></a>
</p>

<p style="text-align: center;">
	الإجراءات السريعة متاحة مباشرة من أيقونة التطبيق.
</p>

<p>
	قد تتساءل، كيف يمكن فعل ذلك مع تطبيق ويب؟ يمكنك من خلال تحديد اختصارات التطبيق في ملف بيان موارد تطبيق الويب التقدمي manifest تسجيل مسارات سريعة للمهام الشائعة الممكن للمستخدمين الوصول إليها مباشرة من أيقونة التطبيق.
</p>

<p>
	في أنظمة التشغيل مثل macOS، يمكن للمستخدمين أيضًا النقر بزر الفأرة الأيمن فوق أيقونة التطبيق وتعيين التطبيق <a href="https://github.com/MicrosoftEdge/MSEdgeExplainers/blob/main/RunOnLogin/Explainer.md" rel="external nofollow">ليعمل فور تسجيل الدخول للنظام</a> run on login.
</p>

<h2>
	التصرف كتطبيق افتراضي
</h2>

<p>
	يمكن أن تتكامل تطبيقات iOS المختلفة مع تطبيق Podcasts وحتى مواقع الويب و تطبيقات البريد الإلكتروني، وذلك من خلال البروتوكول <code>podcasts://‎</code>، فإذا كنت في المتصفح وتوجهت لرابط مثل
</p>

<pre class="ipsCode prettyprint lang-css prettyprinted" id="ips_uid_7215_32" style="">
<span class="pln">podcasts</span><span class="pun">:</span><span class="com">//podcasts.apple.com/podcast/the-css-podcast/id1042283903</span></pre>

<p>
	فستُنقل مباشرة إلى تطبيق Podcasts ويمكننك المتابعة معه بشكل طبيعي، تشترك بحلقات بث جديدة أو تستمع لحلقات سابقة.
</p>

<p style="text-align: center;">
	<a class="ipsAttachLink ipsAttachLink_image" data-fileid="96571" href="https://academy.hsoub.com/uploads/monthly_2022_04/11podcasts_opened_from_browser.png.43c8bcf23067850e1887e2a505a47612.png" rel=""><img alt="11podcasts_opened_from_browser.png" class="ipsImage ipsImage_thumbnailed" data-fileid="96571" data-unique="lkgj65q6o" src="https://academy.hsoub.com/uploads/monthly_2022_04/11podcasts_opened_from_browser.png.43c8bcf23067850e1887e2a505a47612.png" style="width: 700px; height: auto;"></a>
</p>

<p style="text-align: center;">
	فتح تطبيق Podcasts مباشرة من خلال المتصفح.
</p>

<p>
	كيف يعمل هذا الويب؟ لا يمكن معالجة بروتوكولات مخصصة من الروابط حتى اللحظة، لكن هناك عمل مستمر لاقتراح <a href="https://github.com/MicrosoftEdge/MSEdgeExplainers/blob/main/URLProtocolHandler/explainer.md" rel="external nofollow">معالجة بروتوكول URL</a> لتطبيقات الويب التقدمية. حاليًا تُعد الدالة <code><a href="https://developer.mozilla.org/docs/Web/API/Navigator/registerProtocolHandler" rel="external nofollow">registerProtocolHandler</a></code> مع البادئة <code>web+‎</code> الخيار الأمثل لفعل ذلك.
</p>

<h2>
	تكامل نظام الملفات المحلي
</h2>

<p>
	قد لا تلمَح مباشرة أن تطبيق Podcasts يتكامل بشكل طبيعي مع نظام الملفات المحلي. يَحفظ تطبيق Podcasts بياناته في المسار التالي على حاسوبك:
</p>

<pre class="ipsCode prettyprint lang-css prettyprinted" id="ips_uid_7215_36" style="">
<span class="pun">~</span><span class="str">/Library/</span><span class="typ">Group</span><span class="pln"> </span><span class="typ">Containers</span><span class="pun">/</span><span class="lit">243LU875E5</span><span class="pun">.</span><span class="pln">groups</span><span class="pun">.</span><span class="pln">com</span><span class="pun">.</span><span class="pln">apple</span><span class="pun">.</span><span class="pln">podcasts</span></pre>

<p>
	وتمثِّل ملفات التخزين المؤقت cache قسم التنزيلات أو المحتوى المتاح بلا اتصال، وذلك في المسار التالي:
</p>

<pre class="ipsCode prettyprint lang-css prettyprinted" id="ips_uid_7215_38" style="">
<span class="pun">~</span><span class="str">/Library/</span><span class="typ">Group</span><span class="pln"> </span><span class="typ">Containers</span><span class="pun">/</span><span class="lit">243LU875E5</span><span class="pun">.</span><span class="pln">groups</span><span class="pun">.</span><span class="pln">com</span><span class="pun">.</span><span class="pln">apple</span><span class="pun">.</span><span class="pln">podcasts</span><span class="pun">/</span><span class="typ">Library</span><span class="pun">/</span><span class="typ">Cache</span></pre>

<p style="text-align: center;">
	<a class="ipsAttachLink ipsAttachLink_image" data-fileid="96572" href="https://academy.hsoub.com/uploads/monthly_2022_04/12episodes_in_system_app_folder.png.da47e3126b847d7b977b8770b16226b9.png" rel=""><img alt="12episodes_in_system_app_folder.png" class="ipsImage ipsImage_thumbnailed" data-fileid="96572" data-unique="2aoxabl36" src="https://academy.hsoub.com/uploads/monthly_2022_04/12episodes_in_system_app_folder.png.da47e3126b847d7b977b8770b16226b9.png" style="width: 700px; height: auto;"></a>
</p>

<p style="text-align: center;">
	حلقات البث مخزنة في مجلد خاص بالتطبيق في نظام.
</p>

<p>
	في الويب، تمكِّن الواجهة البرمجية File System Access (الوصول إلى ملفات النظام) المطورين من الوصول إلى نظام الملفات المحلي للجهاز. يمكنك استخدام هذه الواجهة مباشرة أو عبر مكتبة browser-fs-access التي توفر للمتصفحات وصولًا احتياطيًا لملفات النظام.
</p>

<p>
	لأسباب تتعلق بالأمان لا يمكن الوصول لمجلدات النظام عبر الويب.
</p>

<h2>
	شكل المنصة ومظهرها
</h2>

<p>
	هناك شيء جلي وواضح بالنسبة لتطبيقات iOS الشبيهة بتطبيق Podcasts، وهو أنه لا يمكن تحديد العناوين labels ونوع الخط فيها هو نفس نوع خط نظام الجهاز، كما يؤخَذ اختيارك لتعيين مظهر التطبيق (الوضع الليلي والنهاري) بعين الاعتبار.
</p>

<p style="text-align: center;">
	<a class="ipsAttachLink ipsAttachLink_image" data-fileid="96573" href="https://academy.hsoub.com/uploads/monthly_2022_04/13podcasts_supports_dark_mode.png.83ec323e79f318fc4a10e641cb677641.png" rel=""><img alt="13podcasts_supports_dark_mode.png" class="ipsImage ipsImage_thumbnailed" data-fileid="96573" data-unique="kfsmr2jsa" src="https://academy.hsoub.com/uploads/monthly_2022_04/13podcasts_supports_dark_mode.png.83ec323e79f318fc4a10e641cb677641.png" style="width: 600px; height: auto;"></a>
</p>

<p style="text-align: center;">
	تطبيق Podcasts يدعم الوضعين المضيء والمظلم.
</p>

<p style="text-align: center;">
	<a class="ipsAttachLink ipsAttachLink_image" data-fileid="96574" href="https://academy.hsoub.com/uploads/monthly_2022_04/14podcasts_uses_default_system_font.png.bcbffba14e0c9f984e83080a9ff58b5d.png" rel=""><img alt="14podcasts_uses_default_system_font.png" class="ipsImage ipsImage_thumbnailed" data-fileid="96574" data-unique="iku4v1d14" src="https://academy.hsoub.com/uploads/monthly_2022_04/14podcasts_uses_default_system_font.png.bcbffba14e0c9f984e83080a9ff58b5d.png" style="width: 600px; height: auto;"></a>
</p>

<p style="text-align: center;">
	يستخدم التطبيق نوع الخط الافتراضي للنظام.
</p>

<p>
	في الويب، يمكنك حماية عناصر واجهة المستخدم من التحديد عن طريق الخطأ بالاستفادة من خاصية <code>user-select</code> في css بالقيمة <code>none</code>، لكن مع ذلك، تأكد من عدم إساءة استخدام هذه الخاصية وجعل <em>محتوى</em> التطبيق غير قابلة للتحديد، إذ يجب استخدام هذه الخاصية فقط لعناصر واجهة المستخدم مثل نصوص الأزرار وما شابه.
</p>

<p>
	تمكنك القيمة <code><a href="https://wiki.hsoub.com/CSS/font-family#system-ui" rel="external">system-ui</a></code> للخاصية <code><a href="https://wiki.hsoub.com/CSS/font-family" rel="external">font-family</a></code> من استخدام خط واجهة المستخدم الافتراضي للنظام في تطبيقك.
</p>

<p>
	أخيرًا يمكن أن يُعرض تطبيقك بمظهر المستخدم المفضل من خلال الاعتناء بخيار <code><a href="https://web.dev/prefers-color-scheme/" rel="external nofollow">prefers-color-scheme</a></code> (نظام الألوان المفضل) للمستخدم مع مفتاح اختياري <a href="https://academy.hsoub.com/programming/html/%D8%AA%D8%B5%D9%85%D9%8A%D9%85-%D9%85%D9%81%D8%A7%D8%AA%D9%8A%D8%AD-%D8%AA%D8%A8%D8%AF%D9%8A%D9%84-toggle-switches-%D9%88%D8%A5%D9%86%D8%B4%D8%A7%D8%A4%D9%87%D8%A7-r765/" rel="">لتبديل المظهر من مضيء إلى مظلم</a>.
</p>

<p>
	الشيء الآخر الذي يجب اتخاذ قرار بشأنه هو ما يجب على المتصفح فعله عند اقتراب الوصول إلى نهاية شريط التمرير، مثلًا تنفيذ <em>سحب للتحديث</em>، وذلك ممكن عبر خاصية <code>overscroll-behavior</code>.
</p>

<h2>
	شريط عنوان مخصص
</h2>

<p>
	ستلاحظ بالنظر إلى نافذة تطبيق Podcasts أن تجربة تصميم التطبيق شبيهة بتجربة نافذة متصفح Safari، إذ لا يحتوي Podcasts على شريط عنوان كلاسيكي متكامل ولا شريط أدوات، وإنما لديه تجربة مخصصة تبدو كشريط جانبي مثبت في نافذة المشغل الرئيسية.
</p>

<p style="text-align: center;">
	<a class="ipsAttachLink ipsAttachLink_image" data-fileid="96575" href="https://academy.hsoub.com/uploads/monthly_2022_04/15safari_titlebar.png.6c1746adb4c44ea2d47e9249f3611987.png" rel=""><img alt="15safari_titlebar.png" class="ipsImage ipsImage_thumbnailed" data-fileid="96575" data-unique="g3idd80yk" src="https://academy.hsoub.com/uploads/monthly_2022_04/15safari_titlebar.png.6c1746adb4c44ea2d47e9249f3611987.png" style="width: 700px; height: auto;"></a>
</p>

<p style="text-align: center;">
	<a class="ipsAttachLink ipsAttachLink_image" data-fileid="96576" href="https://academy.hsoub.com/uploads/monthly_2022_04/16podcasts_titlebar.png.12973a138483c62c14ac32bcdcee9f13.png" rel=""><img alt="16podcasts_titlebar.png" class="ipsImage ipsImage_thumbnailed" data-fileid="96576" data-unique="rrdzoabru" src="https://academy.hsoub.com/uploads/monthly_2022_04/16podcasts_titlebar.png.12973a138483c62c14ac32bcdcee9f13.png" style="width: 700px; height: auto;"></a>
</p>

<p>
	أشرطة العنوان المخصصة لكلًا من Safari و Podcasts.
</p>

<p>
	في الويب، يمكنك ضبط خاصيتَي <code><a href="https://wiki.hsoub.com/CSS/display" rel="external">display</a></code> و <code><a href="https://academy.hsoub.com/programming/general/%D8%B4%D8%B1%D8%AD-%D9%85%D9%84%D9%81-%D8%A7%D9%84%D8%A8%D9%8A%D8%A7%D9%86-manifest-%D9%84%D8%AA%D8%B7%D8%A8%D9%8A%D9%82-%D8%A7%D9%84%D9%88%D9%8A%D8%A8-%D8%A7%D9%84%D8%AA%D9%82%D8%AF%D9%85%D9%8A-pwa-r1385/" rel="">theme-color</a></code> في ملف بيان تطبيق الويب لتحديد شكل وأسلوب عرض نافذة تطبيقك وتحديد أيٍ من عناصر تحكم المتصفح الافتراضية يجب أن يظهر.
</p>

<h2>
	حركات سلِسة
</h2>

<p>
	الحركات داخل Podcasts سريعة وسلسة، مثلًا عندما تفتح واجهة ملاحظات حلقة البث المسحوبة على اليمين؛ فإنها تنزلق بانسيابية، وعندما تحذف حلقة من تنزيلاتك، فإن الحلقات المتبقية تطفو لأعلى وتستغل مساحة الشاشة المتحررة من الحلقة المحذوفة.
</p>

<p style="text-align: center;">
	<a class="ipsAttachLink ipsAttachLink_image" data-fileid="96577" href="https://academy.hsoub.com/uploads/monthly_2022_04/17snappy_podcasts_drawer_opening.png.cb8f63fcf46f59fb28ebd6aed52b28df.png" rel=""><img alt="17snappy_podcasts_drawer_opening.png" class="ipsImage ipsImage_thumbnailed" data-fileid="96577" data-unique="4ls0n351l" src="https://academy.hsoub.com/uploads/monthly_2022_04/17snappy_podcasts_drawer_opening.png.cb8f63fcf46f59fb28ebd6aed52b28df.png" style="width: 700px; height: auto;"></a>
</p>

<p style="text-align: center;">
	الحركات داخل Podcasts مثل الفتح السلس للواجهة المسحوبة.
</p>

<p>
	يمكنك بالتأكيد إدخال الحركات في تطبيقات الويب إذا كنت تأخذ بعين الاعتبار عددًا من النصائح الموضحة في مقال <a href="https://academy.hsoub.com/design/general/%D8%A7%D9%84%D8%AD%D8%B1%D9%83%D8%A7%D8%AA-%D9%81%D9%8A-%D8%AA%D8%B5%D9%85%D9%8A%D9%85-%D8%A7%D9%84%D9%88%D9%8A%D8%A8-%D9%84%D9%85%D8%A7%D8%B0%D8%A7-%D9%86%D8%B3%D8%AA%D8%AE%D8%AF%D9%85%D9%87%D8%A7-%D9%88%D9%85%D8%AA%D9%89%D8%9F-r473/" rel="">الحركات في تصميم الويب: لماذا نستخدمها ومتى؟</a>، كما ستجد بعضًا من المصادر الملهمة لإنشاء الحركات في مقال <a href="https://academy.hsoub.com/programming/css/%D9%85%D8%AF%D8%AE%D9%84-%D8%A5%D9%84%D9%89-%D8%A7%D9%84%D8%AD%D8%B1%D9%83%D8%A7%D8%AA-%D9%85%D9%81%D9%87%D9%88%D9%85-%D8%A7%D9%84%D8%AD%D8%B1%D9%83%D8%A9-r677/" rel="">مدخل إلى الحركات</a>.
</p>

<p>
	يمكن تحسين حركات التمرير الشائعة في المحتوى المقسم إلى صفحات مرقمة paginated أو في الوسائط متكررة العرض carousels؛ باستخدام ميزة تمرير css السلس CSS Scroll Snap، أو يمكنك استخدام الواجهة البرمجية Web Animations لتحكم كامل فيها.
</p>

<h2>
	ظهور المحتوى خارج التطبيق
</h2>

<p>
	يمكن لتطبيق Podcasts على iOS عرض المحتوى في أماكن أخرى غير التطبيق نفسه، مثلًا في عرض ودجات النظام Widgets، أو في اقتراحات مُساعد Apple الشخصي Siri، فوجود عبارات استباقية تحث المستخدم على اتخاذ إجراء ما وتتطلب فقط نقرة للتفاعل معها يمكن أن يؤدي إلى زيادة معدل الاندماج بالتطبيق بشكل كبير.
</p>

<p style="text-align: center;">
	<a class="ipsAttachLink ipsAttachLink_image" data-fileid="96578" href="https://academy.hsoub.com/uploads/monthly_2022_04/18content_surfaced_outside_podcasts.png.18c1e9ac2f36a9aa37d98dc0bb34f1e8.png" rel=""><img alt="18content_surfaced_outside_podcasts.png" class="ipsImage ipsImage_thumbnailed" data-fileid="96578" data-unique="b01x21evm" src="https://academy.hsoub.com/uploads/monthly_2022_04/18content_surfaced_outside_podcasts.thumb.png.d50038945e777ccdbe6bbfaef46650ad.png"></a>
</p>

<p style="text-align: center;">
	ظهور محتوى التطبيق خارج تطبيق Podcasts الرئيسي.
</p>

<p>
	تسمح الواجهة البرمجية Content Indexing (فهرسة المحتوى) التي تعمل في الخلفية Content Indexing <abbr title="Application Programming Interface | واجهة برمجية">API</abbr> بإخبار المتصفح بمحتوى تطبيق الويب التقدمي المتاح دون اتصال، ما يتيح للمتصفح إظهار ذلك المحتوى خارج التطبيق الرئيسي.
</p>

<p>
	يمكنك مساعدة محركات البحث والمساعدين الافتراضيين مثل Google Assistant في تقديم ما يعرضه موقعك بشكل مثالي من خلال تحديد المحتوى المثير للاهتمام في تطبيقك باعتباره مناسب أن يُعاد كصوت يمكن التحدث به speakable، وأيضًا باستخدام البيانات المُهيكلية structured-data في موقعك.
</p>

<h2>
	وِدجت شاشة القفل للتحكم في وسائط التطبيق
</h2>

<p>
	يعرض Podcasts عند تشغيل حلقة بث، أداة تحكم رائعة في شاشة القفل تحتوي على بيانات وصفية مثل صورة الحلقة وعنوانها واسمها.
</p>

<p style="text-align: center;">
	<a class="ipsAttachLink ipsAttachLink_image" data-fileid="96579" href="https://academy.hsoub.com/uploads/monthly_2022_04/19lock_screen_controls_playing_media.png.e0541f40f2a2357568f378f76ba43943.png" rel=""><img alt="19lock_screen_controls_playing_media.png" class="ipsImage ipsImage_thumbnailed" data-fileid="96579" data-unique="w7ug36qwt" src="https://academy.hsoub.com/uploads/monthly_2022_04/19lock_screen_controls_playing_media.thumb.png.210eac7c348b2304b6fbe42069dd5533.png"></a>
</p>

<p style="text-align: center;">
	التحكم في الوسائط المشغلة في التطبيق من شاشة القفل.
</p>

<p>
	في الويب، تتيح لك الواجهة البرمجية Media Session <abbr title="Application Programming Interface | واجهة برمجية">API</abbr> التي تعمل في الخلفية تحديد البيانات الوصفية مثل صورة العنصر وعنوانه، وما إلى ذلك، لتُعرض بعد ذلك في شاشة القفل، أو شاشة الساعات الذكية، أو أدوات الوسائط في المتصفح.
</p>

<h2>
	دفع الإشعارات
</h2>

<p>
	أصبح طلب الحصول على الإشعارات في الويب أقل هذه الأيام، فالإشعارات الفورية إلى حد ما تعتبر مصدر إزعاج في الويب، لكن إذا استُخدمت بشكل صحيح، فيمكن أن تضيف قيمة كبيرة.
</p>

<p>
	مثلًا يمكن لتطبيق Podcasts إشعارك اختياريًا بحلقات البث الجديدة من السلاسل التي اشتركت فيها أو ينصحك بالمشاركة بسلاسل بث جديدة، أيضًا إشعارك بميزات التطبيق الجديدة.
</p>

<p style="text-align: center;">
	<a class="ipsAttachLink ipsAttachLink_image" data-fileid="96580" href="https://academy.hsoub.com/uploads/monthly_2022_04/20push_notifications_for_new_content.png.44ac4e86fd57f2665d3291881ca0e250.png" rel=""><img alt="20push_notifications_for_new_content.png" class="ipsImage ipsImage_thumbnailed" data-fileid="96580" data-unique="eoyw5tz5p" src="https://academy.hsoub.com/uploads/monthly_2022_04/20push_notifications_for_new_content.thumb.png.8b613a28ee87048f34f962152740a758.png"></a>
</p>

<p style="text-align: center;">
	إرسال التطبيقات إشعارات فورية لإبلاغ المستخدم بالمحتوى الجديد.
</p>

<p>
	يمكنك فعل ذلك في الويب عبر الواجهة البرمجية Push <abbr title="Application Programming Interface | واجهة برمجية">API</abbr> التي تعمل في الخلفية إذ تتيح لتطبيقك بتلقي الإشعارات حتى تتمكن من إشعار المستخدمين بالأحداث الملاحظة حول تطبيق الويب التقدمي، وبالنسبة للإشعارات التي يجب إطلاقها في وقت محدد مستقبلًا والتي لا تتطلب اتصالاً بالشبكة فيمكنك استخدام الواجهة البرمجية Notification Triggers <abbr title="Application Programming Interface | واجهة برمجية">API</abbr> (مُطْلِق الإشعارات) التي تعمل في الخلفية.
</p>

<h2>
	شارات أيقونة التطبيق
</h2>

<p>
	عندما تكون هناك حلقات بث جديدة متاحة في إحدى سلاسل البث التي اشتركت فيها، تظهر شارة على أيقونة Podcasts في الشاشة الرئيسية، ما يشجعك على فتح التطبيق بطريقة غير تطفلية لمشاهدة المستجدات.
</p>

<p style="text-align: center;">
	<a class="ipsAttachLink ipsAttachLink_image" data-fileid="96581" href="https://academy.hsoub.com/uploads/monthly_2022_04/21badges_inform_about_content.png.809c9a55b17b5541d56ea254464ae33f.png" rel=""><img alt="21badges_inform_about_content.png" class="ipsImage ipsImage_thumbnailed" data-fileid="96581" data-unique="gd81h8vhh" src="https://academy.hsoub.com/uploads/monthly_2022_04/21badges_inform_about_content.thumb.png.d689f052741885f448c690d46fcf3e5b.png"></a>
</p>

<p style="text-align: center;">
	تُعد الشارات طريقة ماكرة لشد المستخدم على فتح التطبيق.
</p>

<p>
	في الويب، يمكنك تعيين شارات أيقونة التطبيق باستخدام الواجهة البرمجية Badging <abbr title="Application Programming Interface | واجهة برمجية">API</abbr>، فهذا مفيد بشكل خاص عندما يكون لدى تطبيق الويب التقدمي مفهوم "غير مقروء" unread للعناصر الجديدة التي لم يفتحها المستخدم، أو بشكل عام عندما تحتاج وسيلة لاستدراج المستخدم إلى التطبيق بشكل غير ملحوظ.
</p>

<h2>
	أسبقية تشغيل الوسائط على إعدادات توفير الطاقة
</h2>

<p>
	قد تُطفَأ الشاشة في نُسخ سطح المكتب من Podcasts عند تشغيل الوسائط وترك التطبيق مشغل فترة طويلة دون تفاعل لكن لا يدخل النظام في وضع السكون sleep، كما يمكن لنُسخ الهواتف الذكية من Podcasts إبقاء الشاشة فعّالة اختياريًا، مثلًا لعرض كلمات المقطع المشغل أو تسميته التوضيحية.
</p>

<p style="text-align: center;">
	<a class="ipsAttachLink ipsAttachLink_image" data-fileid="96582" href="https://academy.hsoub.com/uploads/monthly_2022_04/22apps_keep_screen_awake.png.87929d0152d18f7d3c7706e8aad55c83.png" rel=""><img alt="22apps_keep_screen_awake.png" class="ipsImage ipsImage_thumbnailed" data-fileid="96582" data-unique="ncsryrgss" src="https://academy.hsoub.com/uploads/monthly_2022_04/22apps_keep_screen_awake.thumb.png.86eab330d5e8c3d7b5b63560420cf1f9.png" style="width: 600px; height: auto;"></a>
</p>

<p style="text-align: center;">
	تبقي التطبيقات الشاشة فعالة.
</p>

<p>
	في الويب، تتيح لك الواجهة البرمجية Screen Wake Lock <abbr title="Application Programming Interface | واجهة برمجية">API</abbr> (قفل إيقاظ الشاشة) التي تعمل في الخلفية إمكانية منع إيقاف تشغيل الشاشة لسبب ما، وبالنسبة للويب فإن تشغيل الوسائط يمنع نظام التشغيل تلقائيًا من الدخول في وضع السكون sleep.
</p>

<h2>
	استكشاف التطبيق في متجر التطبيقات
</h2>

<p>
	يعد تطبيق Podcasts جزءًا من تجربة سطح مكتب نظام macOS، لكن على نظام iOS فيجب تثبيته من متجر App Store. بالبحث السريع عن "podcast" أو "podcasts" أو"apple podcasts" فإن Podcasts يبرز فورًا في متجر التطبيقات.
</p>

<p style="text-align: center;">
	<a class="ipsAttachLink ipsAttachLink_image" data-fileid="96583" href="https://academy.hsoub.com/uploads/monthly_2022_04/23users_discover_apps_in_app_stores.png.608547d81a172e80238c6f7ad3477e1f.png" rel=""><img alt="23users_discover_apps_in_app_stores.png" class="ipsImage ipsImage_thumbnailed" data-fileid="96583" data-unique="qkx81qqoo" src="https://academy.hsoub.com/uploads/monthly_2022_04/23users_discover_apps_in_app_stores.thumb.png.5466eeb56dce278ae22f14813947ff99.png"></a>
</p>

<p style="text-align: center;">
	تعلَّم المستخدمون استكشاف التطبيقات في متاجر التطبيقات.
</p>

<p>
	لا تسمح Apple بنشر تطبيقات ويب تقدمية في متجر App Store، لكن في نظام Android يمكنك تغليف تطبيق الويب التفاعلي الخاص بك في فاعليِّة ويب موثوق Trusted Web Activity (حاوية container تجعله يتصرف كتطبيقات الهواتف المعيارية).
</p>

<p>
	يجعل سكربت <code><a href="https://github.com/GoogleChromeLabs/bubblewrap" rel="external nofollow">bubblewrap</a></code> عملية رفع تطبيق PWA على المتجر أمرًا يسيرًا عبر واجهة سطر الأوامر، وهو أيضًا من يُشغِّل داخليًا ميزة تصدير تطبيقات Android عبر الأداة <a href="https://github.com/pwa-builder/PWABuilder" rel="external nofollow">PWABuilder</a> أو باني تطبيق PWA، الممكن استخدامها لرفع التطبيقات على المتجر دون الاستعانة بسطر الأوامر.
</p>

<h2>
	الخلاصة
</h2>

<p>
	تطوّرت تطبيقات الويب التقدمية PWAs كثيرًا منذ ظهورها عام 2015، ويعمل فريق Chromium (المتصفح الحر الذي بني عليه متصفح كروم) الآن في سياق مشروع Fugu على سد النقص فيها.
</p>

<p>
	باتباعك على الأقل بعضًا من نصائح هذا المقال، يمكنك الاقتراب شيئًا فشيئًا من هيئة ومظهر يشبه التطبيق الأساسي المثبت في أي نظام تشغيل مما يُنْسِي مستخدميك أنهم يتعاملون مع موقع ويب، لأن معظمهم لا يهتم بصراحة بكيفية إنشاء تطبيقك (ولماذا يجب عليهم ذلك؟)، طالما هو يبدو كتطبيق حقيقي.
</p>

<p>
	ترجمة -وبتصرف- للمقال <a href="https://web.dev/app-like-pwas/" rel="external nofollow">Make your PWA feel more like an app</a> من موقع <a href="https://web.dev/" rel="external nofollow">web.dev</a>
</p>

<h2>
	اقرأ أيضًا
</h2>

<ul>
<li>
		<a href="https://academy.hsoub.com/programming/general/%D9%85%D8%A7-%D9%87%D9%8A-%D8%AA%D8%B7%D8%A8%D9%8A%D9%82%D8%A7%D8%AA-%D8%A7%D9%84%D9%88%D9%8A%D8%A8-%D8%A7%D9%84%D8%AA%D9%82%D8%AF%D9%85%D9%8A%D8%A9-pwa%D8%9F-r1480/" rel="">ما هي تطبيقات الويب التقدمية PWA؟</a>
	</li>
	<li>
		<a href="https://academy.hsoub.com/programming/general/%D9%85%D9%8A%D8%B2%D8%A7%D8%AA-%D8%AA%D8%B7%D8%A8%D9%8A%D9%82-%D8%A7%D9%84%D9%88%D9%8A%D8%A8-%D8%A7%D9%84%D8%AA%D9%82%D8%AF%D9%85%D9%8A-pwa-r1489/" rel="">ميزات تطبيق الويب التقدمي PWA</a>
	</li>
	<li>
		<a href="https://academy.hsoub.com/programming/general/%D9%86%D9%85%D8%A7%D8%B0%D8%AC-%D8%A7%D9%82%D8%AA%D8%B1%D8%A7%D8%AD%D8%A7%D8%AA-%D8%AA%D8%AB%D8%A8%D9%8A%D8%AA-%D8%AA%D8%B7%D8%A8%D9%8A%D9%82%D8%A7%D8%AA-%D8%A7%D9%84%D9%88%D9%8A%D8%A8-%D8%A7%D9%84%D8%AA%D9%82%D8%AF%D9%85%D9%8A%D8%A9-pwa-r1446/" rel="">نماذج اقتراحات تثبيت تطبيقات الويب التقدمية PWA</a>
	</li>
	<li>
		<a href="https://academy.hsoub.com/programming/javascript/%D8%AA%D9%88%D9%81%D9%8A%D8%B1-%D8%AA%D8%AC%D8%B1%D8%A8%D8%A9-%D8%AA%D8%AB%D8%A8%D9%8A%D8%AA-%D9%85%D8%AE%D8%B5%D8%B5%D8%A9-%D8%AF%D8%A7%D8%AE%D9%84-%D8%AA%D8%B7%D8%A8%D9%8A%D9%82-%D8%A7%D9%84%D9%88%D9%8A%D8%A8-%D8%A7%D9%84%D8%AA%D9%82%D8%AF%D9%85%D9%8A-pwa-r1445/" rel="">توفير تجربة تثبيت مخصصة داخل تطبيق الويب التقدمي PWA</a>
	</li>
	<li>
		النسخة العربية الكاملة من كتاب <a href="https://academy.hsoub.com/files/24-%D8%A3%D9%86%D8%B8%D9%85%D8%A9-%D8%A7%D9%84%D8%AA%D8%B4%D8%BA%D9%8A%D9%84-%D9%84%D9%84%D9%85%D8%A8%D8%B1%D9%85%D8%AC%D9%8A%D9%86/" rel="">أنظمة التشغيل للمبرمجين</a>
	</li>
</ul>
]]></description><guid isPermaLink="false">1528</guid><pubDate>Thu, 14 Apr 2022 15:00:00 +0000</pubDate></item><item><title>&#x645;&#x627; &#x647;&#x64A; &#x627;&#x644;&#x648;&#x627;&#x62C;&#x647;&#x629; &#x627;&#x644;&#x628;&#x631;&#x645;&#x62C;&#x64A;&#x629; &#x644;&#x644;&#x62A;&#x637;&#x628;&#x64A;&#x642;&#x627;&#x62A; API&#x61F;</title><link>https://academy.hsoub.com/programming/general/%D9%85%D8%A7-%D9%87%D9%8A-%D8%A7%D9%84%D9%88%D8%A7%D8%AC%D9%87%D8%A9-%D8%A7%D9%84%D8%A8%D8%B1%D9%85%D8%AC%D9%8A%D8%A9-%D9%84%D9%84%D8%AA%D8%B7%D8%A8%D9%8A%D9%82%D8%A7%D8%AA-api%D8%9F-r1512/</link><description><![CDATA[
<p><img src="https://academy.hsoub.com/uploads/monthly_2022_03/API.png.e61be5931cbe4e4eafe1b722daaaab83.png" /></p>
<p>
	للعديد من التطبيقات التي تشغلها على حاسوبك <a href="https://academy.hsoub.com/design/user-interface/%D8%A7%D9%84%D8%AF%D9%84%D9%8A%D9%84-%D8%A5%D9%84%D9%89-%D8%AA%D9%87%D9%8A%D8%A6%D8%A9-%D9%88%D8%A7%D8%AC%D9%87%D8%A9-%D8%A7%D9%84%D9%85%D8%B3%D8%AA%D8%AE%D8%AF%D9%85-ui-r652/" rel="">واجهة مستخدم</a>، تحتوي غالبًا على أزرار للنقر أو أيقونات للسحب أو حقول نصية للكتابة فيها، وتستخدم بعض التطبيقات الطرفية terminal (أو <a href="https://academy.hsoub.com/devops/servers/%D9%85%D8%A7-%D9%87%D9%88-%D8%B3%D8%B7%D8%B1-%D8%A7%D9%84%D8%A3%D9%88%D8%A7%D9%85%D8%B1-%D8%9F-r353/" rel="">سطر الأوامر</a>) واجهةً لها، حيث يكتب المستخدم الأوامر بدلاً من النقر فوق الأزرار أو سحب الأيقونات، وتخصَّص <a href="https://academy.hsoub.com/programming/general/%D9%85%D8%AF%D8%AE%D9%84-%D8%A5%D9%84%D9%89-%D8%A7%D9%84%D9%88%D8%A7%D8%AC%D9%87%D8%A7%D8%AA-%D8%A7%D9%84%D8%A8%D8%B1%D9%85%D8%AC%D9%8A%D8%A9-api-r1314/" rel="">الواجهة البرمجية للتطبيقات Application Programming Interface</a> -واختصارًا <abbr title="Application Programming Interface | واجهة برمجية"><abbr title="Application Programming Interface | واجهة برمجية">API</abbr></abbr>- للتطبيقات بدلًا من المستخدمين.
</p>

<p>
	تُوجَّه جميع أجهزة الحاسوب في النهاية للمستخدم، ولكن الواجهة البرمجية للتطبيقات تسهّل على المستخدمين كتابة تعليمات برمجية للتحكم بالتطبيق، وقد تكون الواجهة البرمجية للتطبيقات غير فعالة وغير مباشرة لاستخدام التطبيق بالنسبة للبشر، ولكنها طريقة مناسبة لأجهزة الحاسوب لإرسال الإشارات، والحصول على بيانات مفيدة من التطبيقات الأخرى، ويمكن الوصول إليها محليًا أو عبر شبكة -أكبرها <a href="https://academy.hsoub.com/devops/networking/%D9%85%D8%B9%D9%85%D8%A7%D8%B1%D9%8A%D8%A9-%D8%A7%D9%84%D8%B4%D8%A8%D9%83%D8%A9-%D8%A7%D9%84%D8%AD%D8%A7%D8%B3%D9%88%D8%A8%D9%8A%D8%A9-%D9%88%D8%B4%D8%A8%D9%83%D8%A9-%D8%A7%D9%84%D8%A5%D9%86%D8%AA%D8%B1%D9%86%D8%AA-network-architecture-r484/" rel="">الإنترنت</a>-، ويمكن تصميمها لتقبل مدخلات من عدة لغات برمجة وبروتوكولات، ويكثر استخدامها في تصميم ألعاب الفيديو وتعديلها، وتوسيع التطبيقات المعقدة، واستخراج البيانات data scraping والتفاعل معها.
</p>

<h2>
	البرمجة المبسطة باستخدام الواجهة البرمجية للتطبيقات <abbr title="Application Programming Interface | واجهة برمجية"><abbr title="Application Programming Interface | واجهة برمجية">API</abbr></abbr>
</h2>

<p>
	من ميزات الواجهة البرمجية للتطبيقات قدرتها على إخفاء متطلبات التعليمات البرمجية المعقدة عن المستخدم، فعلى سبيل المثال، هذا برنامج بسيط مكتوب بلغة C لطباعة جملة "Hello world" على الشاشة:
</p>

<pre class="ipsCode prettyprint lang-c prettyprinted" id="ips_uid_2144_10" style=""><span class="com">#include</span><span class="pln"> </span><span class="str">&lt;stdio.h&gt;</span><span class="pln">

</span><span class="typ">int</span><span class="pln"> main</span><span class="pun">(</span><span class="typ">int</span><span class="pln"> argc</span><span class="pun">,</span><span class="pln"> </span><span class="kwd">char</span><span class="pln"> </span><span class="pun">*</span><span class="pln">argv</span><span class="pun">[])</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
    </span><span class="typ">int</span><span class="pln"> i</span><span class="pun">;</span><span class="pln">
    </span><span class="kwd">for</span><span class="pun">(</span><span class="pln">i</span><span class="pun">=</span><span class="lit">1</span><span class="pun">;</span><span class="pln">i</span><span class="pun">&lt;</span><span class="pln">argc</span><span class="pun">;</span><span class="pln">i</span><span class="pun">++)</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
        printf</span><span class="pun">(</span><span class="str">"%s\n"</span><span class="pun">,</span><span class="pln">argv</span><span class="pun">[</span><span class="pln">i</span><span class="pun">]);</span><span class="pln">
    </span><span class="pun">}</span><span class="pln">
    </span><span class="kwd">return</span><span class="pln"> </span><span class="lit">0</span><span class="pun">;</span><span class="pln">
</span><span class="pun">}</span></pre>

<p>
	يمكن للواجهة البرمجية للتطبيقات المكتوبة لإخراج نفس النتيجة أي طباعة جملة "Hello world" أن تبسط التعليمات البرمجية تبسيطًا كبيرًا، وفيما يلي واجهة برمجية لتطبيقات وهميةً مثالًا على ذلك:
</p>

<pre class="ipsCode prettyprint lang-c prettyprinted" id="ips_uid_2144_12" style=""><span class="pln">cprint</span><span class="pun">(</span><span class="pln">hello_msg</span><span class="pun">)</span></pre>

<p>
	تعليمات إنشاء <abbr title="Application Programming Interface | واجهة برمجية"><abbr title="Application Programming Interface | واجهة برمجية">API</abbr></abbr> معقدةً عادةً، كما هو موضح في مثال <a href="https://www.lua.org/pil/26.1.html" rel="external nofollow">Lua</a>، لكن المستخدم النهائي ليس مضطرًا للتعامل مع ذلك، فالشيء الوحيد الذي سيراه هو لغة برمجة مبسطة تمكنه من الوصول إلى نتائج الحسابات المعقدة للغاية.
</p>

<h2>
	الاستعلامات المبسطة باستخدام الواجهة البرمجية للتطبيقات <abbr title="Application Programming Interface | واجهة برمجية"><abbr title="Application Programming Interface | واجهة برمجية">API</abbr></abbr>
</h2>

<p>
	يمكن من خلال الواجهة البرمجية للتطبيقات توفير تعليمات للمستخدمين النهائيين لتنفيذ إجراءات محددة أو استعلامات queries عن المعلومات، إذ تمكّن <a href="https://academy.hsoub.com/programming/general/%D9%85%D8%AF%D8%AE%D9%84-%D8%A5%D9%84%D9%89-%D8%A7%D9%84%D9%88%D8%A7%D8%AC%D9%87%D8%A7%D8%AA-%D8%A7%D9%84%D8%A8%D8%B1%D9%85%D8%AC%D9%8A%D8%A9-api-r1314/" rel="">الواجهة البرمجية <abbr title="Application Programming Interface | واجهة برمجية"><abbr title="Application Programming Interface | واجهة برمجية">API</abbr></abbr></a> المستخدمين من الاستفادة من ميزات البرنامج دون الحاجة لتعلم أوامر برمجية معقدة أو كشف بياناتهم الحساسة، فمثلًا إذا شغلت منتدى دعم أو خادم دردشة فقد ترغب في مشاركة عدد المستخدمين الآخرين -فكلما زاد عدد المستخدمين الموجودين زادت فرصة الحصول على إجابة لسؤال الدعم- لكنك لن تشارك أسماءهم أو أنشطتهم.
</p>

<p>
	ومن أمثلة ذلك إصدار <abbr title="Application Programming Interface | واجهة برمجية"><abbr title="Application Programming Interface | واجهة برمجية">API</abbr></abbr> الذي نُفذ بواسطة مضيف Git مفتوح المصدر GitLab، حيث يحتوي GitLab على واجهة برمجية للتطبيقات غنية بالميزات تساعد المطورين على تحديد أحدث إصدارات برامجهم، ويمكن للمبرمجين إنشاء إصدار من خلال واجهة الويب في GitLab، إلا أن العديد من المطورين يفضلون أتمتة العملية بحيث لا نحتاج للنقر يدويًا عبر شاشات الخيارات، ويتيح GitLab إرسال الأوامر عبر <a href="https://academy.hsoub.com/programming/general/%d9%85%d8%af%d8%ae%d9%84-%d8%a5%d9%84%d9%89-http-r73/" rel="">بروتوكول HTTP</a> باستخدام طريقة الإرسال POST، وهذا مثال عن ذلك:
</p>

<pre class="ipsCode prettyprint lang-c prettyprinted" id="ips_uid_2144_15" style=""><span class="pln">$ curl </span><span class="pun">--</span><span class="pln">header </span><span class="str">'Content-Type: application/json'</span><span class="pln"> \
</span><span class="pun">--</span><span class="pln">header </span><span class="str">"PRIVATE-TOKEN: example_token"</span><span class="pln"> \
  </span><span class="pun">--</span><span class="pln">data </span><span class="str">'{ "name": "Release", "tag_name": "2.4", "description": "Fixed Makefile.am" }'</span><span class="pln"> \
  </span><span class="pun">--</span><span class="pln">request POST https</span><span class="pun">:</span><span class="com">//gitlab.com/api/v4/projects/trashy%2Ftrashy</span></pre>

<p>
	للواجهة البرمجية للتطبيقات GitLab العديد من الميزات، منها الحصول على معلومات حول الوسوم والإصدارات وحذف الإصدارات وتحديثها وما إلى ذلك، ومن السهل على المطورين استخدامها ودمجها في عملياتهم الحالية، لأنها تستخدم طرائق إرسال HTTP القياسية.
</p>

<h2>
	مفتاح الواجهة البرمجية للتطبيقات <abbr title="Application Programming Interface | واجهة برمجية"><abbr title="Application Programming Interface | واجهة برمجية">API</abbr></abbr>
</h2>

<p>
	نلاحظ في مثال GitLab أن مفتاح الواجهة البرمجية للتطبيقات <abbr title="Application Programming Interface | واجهة برمجية"><abbr title="Application Programming Interface | واجهة برمجية">API</abbr></abbr> key كان مطلوبًا، ووظيفته هي نفس وظيفة اسم المستخدم وكلمة المرور في الواجهات التفاعلية، ولكن سيكون تقديم حقل اسم مستخدم وكلمة مرور -مثل الذي تراه عند تسجيل الدخول للتحقق من بريدك الإلكتروني- معقدًا؛ لأنه من المتوقع أن يكون الكيانان المتفاعلان من خلال الواجهة أجهزة حاسوب، لذا يُصدر للمبرمج مفتاح الواجهة البرمجية للتطبيقات يضمَّن في التعليمات البرمجية المكتوبة ليتمكن من التفاعل مع الواجهة.
</p>

<p>
	يختلف الحصول على المفتاح بناءً على كاتب الواجهة البرمجية للتطبيقات التي تريد استخدامها، فمثلًا توفر GitHub مفتاح واجهة برمجية للتطبيقات في لوحة إعدادات رموز الوصول Access Tokens، بينما تقدم خدمة Twitter -مغلق المصدر- المفاتيح من خلال نطاق فرعي subdomain للمطورين، وتعدّ مفاتيح الواجهة البرمجية للتطبيقات من أدوات المطور؛ لذا نادرًا ما تُصدر لكل مستخدم تلقائيًا، لكنها تحجَز للمستخدمين المتقدمين عند الطلب، ولها نفس مزايا اسم المستخدم وكلمة المرور، فهي تنظم الوصول إلى البيانات الحساسة، وتسمح الواجهة البرمجية للتطبيقات بالكشف عن المعلومات كشفًا انتقائيًا بناءً على الاستدعاءات التي تُوفر من خلالها، وهنا يمكن للمفتاح إجراء استثناءات أيضًا بناءً على احتواء طلب الاستدعاء على مفتاح صالح أم لا .
</p>

<h2>
	الفرق بين حزمة أدوات تطوير البرامج SDK والواجهات البرمجية للتطبيقات <abbr title="Application Programming Interface | واجهة برمجية"><abbr title="Application Programming Interface | واجهة برمجية">API</abbr></abbr>
</h2>

<p>
	تجرد الواجهة البرمجية للتطبيقات الدوال البرمجية لتطبيق عن أدوات التحكم بها، أما حزمة أدوات تطوير البرامج SDK فهي دوال البرمجة للتطبيق حرفيًا.
</p>

<p>
	تستخدم الواجهة البرمجية للتطبيقات <abbr title="Application Programming Interface | واجهة برمجية"><abbr title="Application Programming Interface | واجهة برمجية">API</abbr></abbr> في التطبيقات المفتوحة المصدر غالبًا لتوفير الراحة أو الأمان، وتسهل في بعض الأحيان على المبرمج إنشاء أدوات حول تطبيق معقد دون الحاجة إلى فهم الكثير حول كيفية عمله، كما يمكن أن تعمل على حماية البيانات المهمة أو الحساسة مع السماح بالوصول إلى البيانات الأخرى، أما في التطبيقات مسجلة الملكية، فتقدَّم حزمة أدوات تطوير البرامج SDK على أنها الجزء "الأكثر انفتاحًا" من شيفرة البرنامج المصدرية، ويلزمنا غالبًا دفع المال للحصول عليه قانونيًا، ويكون جزء المنتج الذي يدفع المطورون ثمنه ليتمكنوا من التطوير باستخدامه.
</p>

<p>
	لا حاجة إلى أدوات تطوير البرامج في التطبيقات مفتوحة المصدر من الناحية التقنية؛ لأن الشيفرة المصدرية متاحة للاستخدام والتعديل مباشرةً من قبل أي شخص، ومع ذلك توفر بعض المشاريع مفتوحة المصدر حزمة أدوات تطوير البرامج مثل طريقة لتوضيح الدوال الأكثر أهميةً لحالات الاستخدام الأكثر شيوعًا للمطورين، فعلى سبيل المثال عندما تطور تطبيق Qt، يمكنك استخدام أدوات تطوير برامج Qt بالرغم من أن Qt مفتوحة المصدر، أي أنك ستستخدم مكتبات Qt لتطوير التطبيق، أما إذا أردت تطوير Qt نفسها، فستكتب مكتبات بنفسك، لذا لن تستخدمها في عملية التطوير.
</p>

<p>
	يمكن ألا يكون الفرق بين حزمة أدوات تطوير البرامج والواجهة البرمجية للتطبيقات واضحًا في بعض الحالات، ولكن عمومًا توفر حزمة أدوات تطوير البرامج الوصول إلى المكتبات، بينما تستخدم الواجهة البرمجية للتطبيقات هذه المكتبات لإنتاج نتيجة بناءً على أمر معين يمكن تنفيذه من خلالها.
</p>

<h2>
	إنشاء واجهة برمجية للتطبيقات <abbr title="Application Programming Interface | واجهة برمجية"><abbr title="Application Programming Interface | واجهة برمجية">API</abbr></abbr>
</h2>

<p>
	تعمل الواجهة البرمجية للتطبيقات على تسهيل التفاعل، وفي <a href="https://academy.hsoub.com/programming/general/%D8%B9%D9%84%D9%88%D9%85-%D8%A7%D9%84%D8%AD%D8%A7%D8%B3%D9%88%D8%A8/" rel="">علم الحواسيب</a> غالبًا ما يكون التفاعل عبارةً عن طلب وإجابة، وإذا كتبت شيفرةً تستمع إلى التعليمات عبر بروتوكول -دون تدخل بشري مباشر أو معه- فمن المحتمل أنك أنشأت واجهة برمجية لتطبيقات.
</p>

<p>
	يمكن كتابة <abbr title="Application Programming Interface | واجهة برمجية"><abbr title="Application Programming Interface | واجهة برمجية">API</abbr></abbr> بأي لغة برمجة، وكُتِب العديد منها <a href="https://academy.hsoub.com/programming/java/%D9%85%D8%AF%D8%AE%D9%84-%D8%A5%D9%84%D9%89-%D8%A3%D8%B3%D8%A7%D8%B3%D9%8A%D8%A7%D8%AA-%D8%A7%D9%84%D8%A8%D8%B1%D9%85%D8%AC%D8%A9-%D8%A8%D9%84%D8%BA%D8%A9-java-%D9%85%D8%A7-%D9%87%D9%8A-%D8%A7%D9%84%D8%A8%D8%B1%D9%85%D8%AC%D8%A9%D8%9F-r371/" rel="">بلغة Java</a> بمساعدة البرامج الوسيطة middleware مثل <a href="https://www.jboss.org/" rel="external nofollow">JBoss</a> و<a href="https://www.3scale.net/" rel="external nofollow">scale3</a>، بينما كُتب البعض الآخر <a href="https://wiki.hsoub.com/Python" rel="external">بلغة Python</a> باستخدام <a href="https://academy.hsoub.com/programming/python/flask/%D8%A3%D8%B3%D8%A7%D8%B3%D9%8A%D8%A7%D8%AA-%D8%A5%D8%B7%D8%A7%D8%B1-%D8%A7%D9%84%D8%B9%D9%85%D9%84-flask-%D8%A7%D9%84%D9%85%D9%88%D8%AC%D9%87%D8%A7%D8%AA-r337/" rel="">Flask</a> أو <a href="https://academy.hsoub.com/programming/python/django/%D9%85%D8%AF%D8%AE%D9%84-%D8%A5%D9%84%D9%89-%D8%A5%D8%B7%D8%A7%D8%B1-%D8%A7%D9%84%D8%B9%D9%85%D9%84-django%C2%A0-r353/" rel="">Django</a> أو Pyramid، بينما لا يزال البعض الآخر مكتوبًا بلغات <a href="https://wiki.hsoub.com/Ruby" rel="external">Ruby</a> وPerl وLua وC و<a href="https://academy.hsoub.com/programming/cpp/%D9%85%D8%AF%D8%AE%D9%84-%D8%A5%D9%84%D9%89-c-r802/" rel="">++C</a> و<a href="https://academy.hsoub.com/tags/%D8%B3%D9%84%D8%B3%D9%84%D8%A9%20net.%20%D9%84%D9%84%D9%85%D8%AD%D8%AA%D8%B1%D9%81%D9%8A%D9%86/" rel="">NET.</a>، وأي لغة أخرى تقريبًا.
</p>

<h2>
	الواجهة البرمجية للتطبيقات من نمط RESTful
</h2>

<p>
	وصف الدكتور روي فيلدنغ Roy Fielding في إحدى أطروحاته أسلوب <abbr title="Application Programming Interface | واجهة برمجية"><abbr title="Application Programming Interface | واجهة برمجية">API</abbr></abbr> الذي أسماه "Representational State Transfer"، والذي يعرف اختصارًا REST، وهنالك عدد من المعايير والشروط التي تجعل الواجهة البرمجية واجهةً من النمط RESTful، ومن أهمها أن تكون عديمة الحالة statelessness، أي أن لا يخزن الخادم (وهو جانب الواجهة البرمجية للتطبيقات الذي يتخذ إجراءً بناءً على الطلبات الواردة من العميل) أي بيانات للمستخدم، وأن يستلم كل ما يحتاجه من البيانات منه، أي يجب أن تحتوي الواجهة البرمجية للتطبيقات من النمط RESTful على استدعاءات مصممة لتوفير جميع البيانات اللازمة لإكمال التفاعل.
</p>

<p>
	فإذا كتبت واجهةً برمجيةً للتطبيقات لتوفير الرصيد المصرفي للمستخدم، فيجب أن تستقبل اسم المستخدم وكلمة المرور -أو مفتاح <abbr title="Application Programming Interface | واجهة برمجية"><abbr title="Application Programming Interface | واجهة برمجية">API</abbr></abbr>- والحساب المصرفي المقصود، والأمر المطلوب لاسترداد الرصيد المصرفي، بالإضافة إلى أي خيارات مثل نوع العملة واللغة، ويجب تقديم كل هذه المعلومات مع كل طلب؛ لأن الخادم سيعود -بعد كل طلب- إلى حالة عدم المعرفة الافتراضية، كما لو أنه لم يستلم أي طلب من أي شخص، حتى لو أجرى المستخدم مهامًا ذات صلة من قبل، مثل الحصول على رصيد الحساب قبل تحويل الأموال من هذا الحساب إلى حساب آخر، وسيطلب الخادم مرةً أخرى إرسال جميع بيانات الاعتماد والتفاصيل ضمن الطلب.
</p>

<p>
	توجد عدة فوائد للواجهة البرمجية للتطبيقات من النمط RESTful، منها فصل العميل والخادم، ولكن هذا ليس كل شيء، فنظرًا لعدم تخزين الخادم لبيانات المستخدم وعدم اعتماده على نوع معين من الواجهات؛ فيمكن لعدة مطورين تطوير عملاء فريدين للخوادم، أي سنتمكّن من تطوير تطبيق هاتف وتطبيق قائم على الطرفية terminal-based لنفس الخادم دون تعديل، لأن الواجهة البرمجية للتطبيقات توفر واجهةً متوافقةً مع كليهما، إذ تعمل معظم الأوامر الطرفية بنفس الطريقة، حتى أن الأوامر التي تسمح لملفات الإعدادات (التي تخزن الخيارات الدائمة) لا زالت توفر متغيرات البيئة أو خيارات سطر الأوامر لتحديد المعاملات parameter والمدخلات والمخرجات المهمة، لذا يشبه التعامل مع الواجهة البرمجية للتطبيقات من النمط RESTful إلى حد كبير تنفيذ أمر على نظام آخر.
</p>

<h2>
	الاستفادة من الواجهة البرمجية للتطبيقات
</h2>

<p>
	إذا لم تستخدم الواجهة البرمجية للتطبيقات مطلقًا، فحاول استخدامها لشيء بسيط، ودوّن ملاحظات حول ما يعجبك فيها وما حدودها، وإذا كنت مطورًا فحاول كتابة واجهة برمجية للتطبيقات، إذ ساعد مفهوم الواجهة البرمجية للتطبيقات، مثل التطبيقات مفتوحة المصدر نفسها، على أن تصبح الحوسبة أكثر مرونةً وسهولةً وكفاءةً، فتعلمه، واجعله مفتوح المصدر!
</p>

<p>
	لمعرفة المزيد حول الواجهة البرمجية للتطبيقات يمكنك الرجوع إلى المقالات ضمن وسم <a href="https://academy.hsoub.com/tags/api/" rel="">api</a>
</p>

<p>
	ترجمة -وبتصرف- للمقال <a href="https://opensource.com/resources/what-api" rel="external nofollow">?What is an <abbr title="Application Programming Interface | واجهة برمجية"><abbr title="Application Programming Interface | واجهة برمجية">API</abbr></abbr></a> من موقع opensource.com.
</p>

<h2>
	اقرأ أيضًا
</h2>

<ul>
	<li>
		<a href="https://academy.hsoub.com/programming/java/%D9%85%D9%82%D8%AF%D9%85%D8%A9-%D8%A5%D9%84%D9%89-%D9%88%D8%A7%D8%AC%D9%87%D8%A9-%D8%A8%D8%B1%D9%85%D8%AC%D8%A9-%D8%A7%D9%84%D8%AA%D8%B7%D8%A8%D9%8A%D9%82%D8%A7%D8%AA-stream-api-%D9%81%D9%8A-%D8%AC%D8%A7%D9%81%D8%A7-r1433/" rel="">مقدمة إلى واجهة برمجة التطبيقات Stream <abbr title="Application Programming Interface | واجهة برمجية"><abbr title="Application Programming Interface | واجهة برمجية">API</abbr></abbr> في جافا</a>
	</li>
	<li>
		<a href="https://academy.hsoub.com/programming/php/laravel/%d8%a5%d9%86%d8%b4%d8%a7%d8%a1-%d9%88%d8%a7%d8%ac%d9%87%d8%a9-%d8%a8%d8%b1%d9%85%d8%ac%d9%8a%d8%a9-api-%d9%81%d9%8a-laravel-5-r232/" rel="">إنشاء واجهة برمجية <abbr title="Application Programming Interface | واجهة برمجية"><abbr title="Application Programming Interface | واجهة برمجية">API</abbr></abbr> في Laravel 5</a>
	</li>
	<li>
		<a href="https://academy.hsoub.com/programming/javascript/%D8%A7%D9%84%D9%88%D8%A7%D8%AC%D9%87%D8%A9-%D8%A7%D9%84%D8%A8%D8%B1%D9%85%D8%AC%D9%8A%D8%A9-fetch-%D9%81%D9%8A-javascript-r739/" rel="">الواجهة البرمجية fetch في JavaScript</a>
	</li>
	<li>
		<a href="https://academy.hsoub.com/programming/php/laravel/%d8%a5%d9%86%d8%b4%d8%a7%d8%a1-%d9%88%d8%a7%d8%ac%d9%87%d8%a9-%d8%a8%d8%b1%d9%85%d8%ac%d9%8a%d8%a9-%d8%a8%d8%b3%d9%8a%d8%b7%d8%a9-%d8%a8%d8%a7%d8%b3%d8%aa%d8%ae%d8%af%d8%a7%d9%85-%d8%a5%d8%b7%d8%a7%d8%b1-%d8%a7%d9%84%d8%b9%d9%85%d9%84-%d8%a7%d9%84%d9%85%d8%b5%d8%ba%d9%91%d8%b1-lumen-r571/" rel="">إنشاء واجهة برمجية بسيطة باستخدام إطار العمل المصغّر Lumen</a>
	</li>
</ul>
]]></description><guid isPermaLink="false">1512</guid><pubDate>Wed, 13 Apr 2022 15:00:00 +0000</pubDate></item><item><title>&#x627;&#x644;&#x62A;&#x648;&#x627;&#x635;&#x644; &#x628;&#x64A;&#x646; &#x627;&#x644;&#x639;&#x645;&#x644;&#x64A;&#x627;&#x62A; &#x641;&#x64A; &#x627;&#x644;&#x628;&#x631;&#x645;&#x62C;&#x629;</title><link>https://academy.hsoub.com/programming/general/%D8%A7%D9%84%D8%AA%D9%88%D8%A7%D8%B5%D9%84-%D8%A8%D9%8A%D9%86-%D8%A7%D9%84%D8%B9%D9%85%D9%84%D9%8A%D8%A7%D8%AA-%D9%81%D9%8A-%D8%A7%D9%84%D8%A8%D8%B1%D9%85%D8%AC%D8%A9-r1521/</link><description><![CDATA[
<p><img src="https://academy.hsoub.com/uploads/monthly_2022_04/62481499a1036_--.png.78892c600a9f25210b072ced5cec8b16.png" /></p>
<p>
	سنستخدم في هذا المقال الدالة <code>os.fork()‎</code> التي لا توجد في نظام ويندوز، لأنه بطيء جدًا -موازنةً بأنظمة يونكس- في إنشاء العمليات الجديدة، إلى درجة عدم استخدام <code>fork()‎</code> حتى لو استطعنا ذلك، لكن يمكن حل هذه المشكلة باستخدام الخيوط threads، التي تعمل على كل من يونكس وويندوز، وسنشرحها في مقال لاحق، فإذا كنت تستخدم ويندوز فيفضّل أن تقرأ القسم الخاص بالمفاهيم هنا لأنها ستُستخدم في المقال التالي، لكن لا داعي لكتابة الأمثلة الموجودة هنا لأنها لن تعمل معك، أما إذا كنت تستخدم أحد أنظمة يونكس فلن تواجهك مشكلةً فيها.
</p>

<p>
	سنشرح في هذا المقال من سلسلة <a href="https://academy.hsoub.com/tags/%D8%AA%D8%B9%D9%84%D9%85%20%D8%A7%D9%84%D8%A8%D8%B1%D9%85%D8%AC%D8%A9/" rel="">تعلم البرمجة</a>:
</p>

<ul>
	<li>
		الحالات التي تستدعي IPC وأسبابها.
	</li>
	<li>
		أساسيات الأنابيب pipes.
	</li>
	<li>
		نسخ العمليات باستخدام <code>os.fork()‎</code>.
	</li>
	<li>
		التواصل من خلال الأنابيب.
	</li>
	<li>
		إنهاء العمليات باستخدام <code>os.kill()‎</code>.
	</li>
</ul>

<h2>
	تعريف التواصل بين العمليات
</h2>

<p>
	التواصل بين العمليات inter-process communication واختصارًا IPC، هو آلية تمكّن عمليةً ما من التواصل وتبادل البيانات مع عملية أخرى، وقد شرحنا في <a href="https://academy.hsoub.com/programming/python/%D8%A7%D9%84%D8%AA%D9%88%D8%A7%D8%B5%D9%84-%D9%85%D8%B9-%D9%86%D8%B8%D8%A7%D9%85-%D8%A7%D9%84%D8%AA%D8%B4%D8%BA%D9%8A%D9%84-%D8%B9%D8%A8%D8%B1-%D8%A8%D8%A7%D9%8A%D8%AB%D9%88%D9%86-r1520/" rel="">المقال السابق: استخدام نظام التشغيل</a> أن العملية برنامج تنفيذي، وأنها تستطيع التواصل مع غيرها من العمليات باستخدام المزايا الموجودة في وحدة <code>subprocess</code>، وعلى الرغم من أن هذه التقنيات مفيدة في التواصل مع البرامج الأخرى، إلا أنها لا توفر التحكم الدقيق المطلوب أحيانًا للتطبيقات الكبيرة، فمن الشائع في تلك التطبيقات استخدام عدة عمليات في نفس الوقت، بحيث تنفذ كل منها مهمةً مستقلةً، وتطلب بقية العمليات خدمات منها، فمثلًا قد يكون <a href="https://academy.hsoub.com/devops/servers/%D9%85%D8%AF%D8%AE%D9%84-%D8%A5%D9%84%D9%89-%D8%AE%D8%A7%D8%AF%D9%85-%D8%A7%D9%84%D9%88%D9%8A%D8%A8-r574/" rel="">لخادم الويب</a> عملية تراقب طلبات الويب من المتصفحات وتخدمها في صفحات <a href="https://wiki.hsoub.com/HTML" rel="external">HTML</a> بسيطة، لكنه يستخدم عمليةً أخرى لتوفير طلبات البيانات الأعقد، وربما عملية أخرى لمعالجة طلبات ftp، وتُصمم كل عملية بحيث تنفذ مهمةً واحدةً فقط بكفاءة عالية، ويسمح هذا التصميم للمدير بمشاركة حمل المعالجة مع عدة عمليات، فإذا كان لدينا طلبات ftp كثيرة مثلًا، فيمكن بدء عملية ftp جديدة، وتوزيع طلبات ftp على العمليتين.
</p>

<h3>
	أهمية التواصل بين العمليات
</h3>

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

<h3>
	هل تشبه هذه التقنية تقنية العميل/الخادم؟
</h3>

<p>
	يكثر استخدام مصطلح العميل/الخادم في التطبيقات التجارية، وهو مصطلح خاص بمعمارية البرمجيات، ويشير إلى نوع محدد من إعدادات التواصل بين العمليات، ترسل فيه إحدى العمليات -وهي العميل client- طلبات إلى عملية أخرى -هي الخادم server-، لكن الخادم لا يطلب أي شيء أبدًا من العميل، وقد يكون لدينا عدة عمليات من نوع "العميل" تصل إلى خادم واحد، ويمكن لذلك الخادم نفسه أن يكون عميلًا لخوادم أخرى، فيما يعرف بحوسبة العميل/الخادم متعدد المستويات <a href="http://n-tier.com/articles/csovervw.html" rel="external nofollow">N-Tier Client/Server</a>، التي تستخدم التواصل بين العمليات، إلا أنه لا يُشترط أن تكون تقنية التواصل بين العمليات مبنيةً على تقنية العميل/الخادم، ومن الممكن أن يكون لدينا شبكة من العمليات ترسل كل منها رسائل إلى بقية العمليات دون أي تخطيط ثابت بين العملاء والخوادم، ويُسمى هذا بحوسبة النِد للنِد peer-to-peer computing، وقد يبدو هذا نموذجًا جذابًا إلا أنه صعب الإدارة إذا زاد عدد العمليات، لذا يظل النموذج التقليدي للعميل/الخادم هو الأكثر استقرارًا والأسهل في تصميمه وتشغيله.
</p>

<h3>
	هل لهذه التقنية علاقة بالعتاد؟
</h3>

<p>
	تكلمنا في وصفنا السابق للعميل والخادم عن البرمجيات والعمليات فقط، لكن ربما تكون قد سمعت هذه المصطلحات في العتاد أيضًا، خاصةً مصطلح الخادم server الذي يشير إلى الحواسيب القوية التي يتشاركها عدة مستخدمين، وهذه إساءة إلى المعنى الحقيقي لحوسبة العميل/الخادم التي هي معمارية برمجية خالصة، ومستقلة عن العتاد.
</p>

<p>
	تميل عمليات الخوادم في الواقع العملي إلى العمل على حواسيب مستقلة وقوية، ويُشار إلى الجمع بين العتاد وعمليات الخوادم باسم الخادم، ويأخذنا هذا الأسلوب من استخدام تقنية العميل/الخادم إلى عالم حوسبة الشبكات الذي ننظر فيه في المقال التالي.
</p>

<p>
	يمكن ملاحظة تشابه هذه المصطلحات مع تلك المستخدمة في <a href="https://academy.hsoub.com/programming/general/%D8%A7%D9%84%D8%A8%D8%B1%D9%85%D8%AC%D8%A9-%D9%83%D8%A7%D8%A6%D9%86%D9%8A%D8%A9-%D8%A7%D9%84%D8%AA%D9%88%D8%AC%D9%87-r1375/" rel="">البرمجة كائنية التوجه</a>، لأن استخدام الرسائل بين العمليات يشبه إرسال الرسائل بين الكائنات في البرمجة الكائنية، وفعليًا توجد الكثير من الأمور المشتركة بين النموذج الكائني ونموذج التواصل بين العمليات، وقد طُورت بعض معماريات IPC لتستفيد من هذه الأوجه المشتركة، مثل معمارية وسيط طلب الكائن المشترك Common Object Request Broker أو COBRA اختصارًا، حيث نسجل الكائنات في تلك المعمارية مع وسيط طلب لكائن مركزي ORB، وتُوجَّه الرسائل المرسَلة إلى الكائن من أي مكان في الهيكل إلى العملية التي سجلت الكائن، ولن ننظر فيها هنا، ويمكن العودة إلى تطبيقات بايثون لوسطاء طلبات الكائنات المركزية ORB لمزيد من المعلومات.
</p>

<p>
	سنبدأ الآن كتابة بعض الشيفرات، لكن يجب أن ننظر أولًا في بعض آليات التواصل بين العمليات، وسندرس اثنتين منها، الأولى هي تقنية الأنبوب pipe المستخدمة لتبادل البيانات بين عمليتين.
</p>

<h2>
	تعريف الأنبوب Pipe
</h2>

<p>
	يمكن النظر إلى الأنبوب Pipe على أنه يشبه الخرطوم، حيث نسكب البيانات في أحد طرفيه ليخرج من الآخر، وهو يشبه الملف من حيث التعامل معه على أنه تدفق متسلسل للبيانات، لكنه يختلف عن الملف في أن له طرفين، لذا نحصل عند إنشائه على نقطتي نهاية، لنقرأ من إحداهما، ونكتب إلى الأخرى. وعلى عكس الملف لا تُخزّن البيانات حقيقةً عند إغلاق الأنبوب، لذا سنفقد كل ما كتبناه في أحد طرفي الأنبوب ولم نقرأه من الجانب الآخر.
</p>

<p>
	يمكن توضيح استخدام الأنابيب مثل قنوات بين العمليات كما يلي:
</p>

<p style="text-align: center;">
	<a class="ipsAttachLink ipsAttachLink_image" data-fileid="95234" href="https://academy.hsoub.com/uploads/monthly_2022_04/pipes.png.7ed66e62e827873690bb3e1bf7455232.png" rel="" data-fileext="png"><img alt="pipes.png" class="ipsImage ipsImage_thumbnailed" data-fileid="95234" data-unique="lz7nstt5j" src="https://academy.hsoub.com/uploads/monthly_2022_04/pipes.png.7ed66e62e827873690bb3e1bf7455232.png"></a>
</p>

<p>
	نرى هنا عمليتين سميناهما <code>Parent</code> و<code>Child</code>، لأسباب ستبينها بعد قليل، وتستطيع عملية <code>Parent</code> أن تكتب في <code>Pipe A</code>، وتقرأ من <code>Pipe B</code>، أما عملية <code>Child</code> فتستطيع القراءة من <code>Pipe A</code> والكتابة في <code>Pipe B</code>، ويُستخدم كل أنبوب لإرسال طلب أو إعادة بيانات وفقًا للعملية التي بدأت عملية التبادل، ويعطينا ذلك تحديًا مثيرًا للاهتمام في سبب تسمية الأنابيب.
</p>

<p>
	سنكتب الآن بعض التعليمات البرمجية لنرى كيف يمكن بناء آلية IPC باستخدام بايثون، وسيكون المبدأ العام هو إنشاء عملية تكون أصلًا parent وتفتح أنبوبين، ثم نشتق نسخةً منها لتكون فرعًا فيه نفس الأنبوبين، ثم نستخدم الأنابيب للتواصل بين الأصل والفرع، وأول ما سنفعله هو معرفة كيفية استخدام الأنابيب لإرسال البيانات واستلامها، حيث سننشئ أنبوبًا باستخدام دالة <code>os.pipe()‎</code> تعيد اثنين من واصفات الملفات، واحد لكل طرف من أطراف الأنبوب، ثم نستخدم دوال <code>os.read/write</code> لإرسال البيانات في الأنبوب:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_5534_14" style=""><span class="kwd">import</span><span class="pln"> os

</span><span class="pun">#</span><span class="pln"> </span><span class="pun">أنشئ</span><span class="pln"> </span><span class="pun">الأنبوب</span><span class="pln">
receive</span><span class="pun">,</span><span class="pln"> transmit </span><span class="pun">=</span><span class="pln"> os</span><span class="pun">.</span><span class="pln">pipe</span><span class="pun">()</span><span class="pln">

data </span><span class="pun">=</span><span class="pln"> </span><span class="str">'Here is a data string'</span><span class="pln">
length </span><span class="pun">=</span><span class="pln"> os</span><span class="pun">.</span><span class="pln">write</span><span class="pun">(</span><span class="pln">transmit</span><span class="pun">,</span><span class="pln"> bytes</span><span class="pun">(</span><span class="pln">data</span><span class="pun">,</span><span class="pln"> </span><span class="str">'utf8'</span><span class="pun">))</span><span class="pln">
print</span><span class="pun">(</span><span class="str">'Length of data sent: '</span><span class="pun">,</span><span class="pln"> length</span><span class="pun">)</span><span class="pln">

</span><span class="pun">#</span><span class="pln"> </span><span class="lit">1024</span><span class="pln"> </span><span class="pun">مخزن</span><span class="pln"> </span><span class="pun">مؤقت</span><span class="pln"> </span><span class="pun">حجمه</span><span class="pln"> 
</span><span class="pun">#</span><span class="pln"> </span><span class="pun">لضمان</span><span class="pln"> </span><span class="pun">استقبال</span><span class="pln"> </span><span class="pun">جميع</span><span class="pln"> </span><span class="pun">البيانات</span><span class="pln">
print</span><span class="pun">(</span><span class="pln"> </span><span class="str">'The pipe contains:'</span><span class="pun">,</span><span class="pln"> os</span><span class="pun">.</span><span class="pln">read</span><span class="pun">(</span><span class="pln">receive</span><span class="pun">,</span><span class="pln"> </span><span class="lit">1024</span><span class="pun">).</span><span class="pln">decode</span><span class="pun">(</span><span class="str">'utf8'</span><span class="pun">)</span><span class="pln"> </span><span class="pun">)</span></pre>

<p>
	لاحظ أننا نحتاج إلى تحويل البيانات من وإلى مصفوفات البايتات byte arrays، تحويلًا مشتركًا مع معظم عمليات مستوى النظام، ويحدث كل ذلك في عملية واحدة، لذا لا يكون ذا فائدة كبيرة، لكننا نستطيع فصل شيفرة القراءة والكتابة والبدء في تنفيذ شيء ما، بمجرد استنساخ عمليتنا، فكيف ننشئ عملية الاستنساخ تلك؟
</p>

<h2>
	عمليات الاستنساخ
</h2>

<p>
	إن الآلية المستخدمة في توليد الفروع spawning أو اشتقاقها forking هي استخدام استدعاء النظام <code>os.fork()‎</code> الذي يعيد قيمًا مختلفةً وفقًا لمكاننا في العملية الأصل أو الفرع، وتكون قيمة الإعادة في العملية الأصلية هي معرِّف العملية أو pid للعملية الفرع، اما إذا كنا في العملية الفرع فستكون قيمة إعادة <code>fork</code> صفرًا، وهذا يعني أنه سيكون لدينا في الشيفرة تعليمة <code>if</code> تتحقق من قيمة إعادة <code>fork()‎</code>، فإن كانت صفرًا فستنفَّذ دوال العملية الفرع، وإن لم تكن كذلك فستنفَّذ دوال العملية الأصل، ويفضَّل وضع الدوال في وحدات منفصلة واستدعاؤها حسب الحاجة، للسيطرة على مجريات التنفيذ، إلا أننا لن نفعل ذلك هنا لأن الشيفرة قصيرة وستكفينا قائمة واحدة، ونعيد التذكير هنا أن ويندوز لا يفعل هذا، أي لا يدعم دالة <code>fork()‎</code>، لذا لن تعمل الشيفرة في ويندوز، وسيضطر مستخدم ويندوز إلى الانتظار إلى الفصل التالي ليعرف كيفية كتابة برامج العميل/الخادم.
</p>

<p>
	سننشئ الآن عمليةً فرعيةً تستطيع إجراء عملية بسيطة لتنسيق النصوص، وتعيد القيمة التي نمررها إليها مسبوقةً ومتبوعةً بالجملة <code>Ni</code>.
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_5534_16" style=""><span class="kwd">import</span><span class="pln"> os</span><span class="pun">,</span><span class="pln">signal

</span><span class="pun">#</span><span class="pln"> </span><span class="pun">أنشئ</span><span class="pln"> </span><span class="pun">الأنابيب</span><span class="pln">

</span><span class="typ">ServerReceive</span><span class="pun">,</span><span class="typ">ClientSend</span><span class="pln"> </span><span class="pun">=</span><span class="pln"> os</span><span class="pun">.</span><span class="pln">pipe</span><span class="pun">()</span><span class="pln">
</span><span class="typ">ClientReceive</span><span class="pun">,</span><span class="pln"> </span><span class="typ">ServerSend</span><span class="pln"> </span><span class="pun">=</span><span class="pln"> os</span><span class="pun">.</span><span class="pln">pipe</span><span class="pun">()</span><span class="pln">

pid </span><span class="pun">=</span><span class="pln"> os</span><span class="pun">.</span><span class="pln">fork</span><span class="pun">()</span><span class="pln">
</span><span class="kwd">if</span><span class="pln"> pid </span><span class="pun">==</span><span class="pln"> </span><span class="lit">0</span><span class="pun">:</span><span class="pln">  </span><span class="pun">#</span><span class="pln"> </span><span class="pun">في</span><span class="pln"> </span><span class="pun">الفرع</span><span class="pln">
   </span><span class="kwd">while</span><span class="pln"> </span><span class="typ">True</span><span class="pun">:</span><span class="pln"> </span><span class="pun">#</span><span class="pln"> </span><span class="pun">قدمها</span><span class="pln"> </span><span class="pun">بلا</span><span class="pln"> </span><span class="pun">نهاية</span><span class="pln">
      data </span><span class="pun">=</span><span class="pln"> os</span><span class="pun">.</span><span class="pln">read</span><span class="pun">(</span><span class="typ">ServerReceive</span><span class="pun">,</span><span class="lit">1024</span><span class="pun">)</span><span class="pln">
      </span><span class="kwd">if</span><span class="pln"> data</span><span class="pun">:</span><span class="pln">  </span><span class="pun">#</span><span class="pln"> </span><span class="pun">تحقق</span><span class="pln"> </span><span class="pun">من</span><span class="pln"> </span><span class="pun">استلام</span><span class="pln"> </span><span class="pun">شيء</span><span class="pln"> </span><span class="pun">ما!</span><span class="pln">
         data </span><span class="pun">=</span><span class="pln"> </span><span class="str">'Ni!\n'</span><span class="pln"> </span><span class="pun">+</span><span class="pln"> data </span><span class="pun">+</span><span class="pln"> </span><span class="str">'\nNi!'</span><span class="pln">
      </span><span class="kwd">else</span><span class="pun">:</span><span class="pln"> data </span><span class="pun">=</span><span class="pln"> </span><span class="str">"Error: received empty message"</span><span class="pln">
      os</span><span class="pun">.</span><span class="pln">write</span><span class="pun">(</span><span class="typ">ServerSend</span><span class="pun">,</span><span class="pln">data</span><span class="pun">)</span><span class="pln">
</span><span class="kwd">else</span><span class="pun">:</span><span class="pln"> </span><span class="pun">#</span><span class="pln"> </span><span class="pun">في</span><span class="pln"> </span><span class="pun">الأصل</span><span class="pln">
   data </span><span class="pun">=</span><span class="pln"> </span><span class="pun">[</span><span class="str">'The Knights who say Ni!'</span><span class="pun">,</span><span class="pln">
           </span><span class="str">'Appear in the film "Monty Python and the Holy Grail" '</span><span class="pun">]</span><span class="pln">
   </span><span class="kwd">for</span><span class="pln"> line in data</span><span class="pun">:</span><span class="pln">
       os</span><span class="pun">.</span><span class="pln">write</span><span class="pun">(</span><span class="typ">ClientSend</span><span class="pun">,</span><span class="pln">line</span><span class="pun">)</span><span class="pln">
       print os</span><span class="pun">.</span><span class="pln">read</span><span class="pun">(</span><span class="typ">ClientReceive</span><span class="pun">,</span><span class="lit">1024</span><span class="pun">)</span><span class="pln">

   </span><span class="pun">#</span><span class="pln"> </span><span class="pun">والآن</span><span class="pln"> </span><span class="pun">أنه</span><span class="pln"> </span><span class="pun">العملية</span><span class="pln"> </span><span class="pun">الفرع</span><span class="pln">
   os</span><span class="pun">.</span><span class="pln">kill</span><span class="pun">(</span><span class="pln">pid</span><span class="pun">,</span><span class="pln">signal</span><span class="pun">.</span><span class="pln">SIGTERM</span><span class="pun">)</span><span class="pln"> </span></pre>

<p>
	لاحظ أننا نستخدم <code>pid</code> الذي استلمناه من <code>fork</code> لإنهاء العملية الفرع، فإذا فشلنا في ذلك فستصبح العملية الفرع عمليةً خلفيةً أو خفيةً daemon، تعمل بصمت بلا نهاية بانتظار ظهور البيانات على أنبوب الدخل الخاص بها، أما الإنهاء الفعلي فيكون باستخدام دالة <code>os.kill()‎</code>، التي تُستخدم لإرسال أي رسالة إلى أي عملية -بغض النظر عن اسمها-، وتسمى إشارة الإنهاء هنا <code>SIGTERM</code> كما هو محدد في وحدة <code>signal</code>، وتختلف القائمة الكاملة وفقًا لكل منصة، وتكون موثقةً في مكتبة <code>libc</code> الخاصة <a href="https://academy.hsoub.com/programming/c/" rel="">بلغة C</a> لمنصتك، لكن يمكن الحصول عليها بسهولة كما يلي في محث <a href="https://wiki.hsoub.com/Python" rel="external">بايثون</a>:
</p>

<pre class="ipsCode prettyprint lang-py prettyprinted" id="ips_uid_5534_18" style=""><span class="pun">&gt;&gt;&gt;</span><span class="pln"> dir</span><span class="pun">(</span><span class="pln">signal</span><span class="pun">)</span></pre>

<p>
	أو في سطر أوامر يونكس (لاحظ أن هذا حرف L وليس العدد 1):
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_5534_22" style=""><span class="pln">$ kill </span><span class="pun">-</span><span class="pln">l</span></pre>

<p>
	ونحصل في حالة يونكس على القيمة العددية التي يمكن استخدامها في أمر <code>kill()‎</code> مباشرةً، لكن هذه القيمة لن تعمل في منصات مختلفة.
</p>

<p>
	أنشأنا الأنابيب ونقلنا البيانات عبرها، كما أنشأنا عمليةً فرعيةً وأرسلنا البيانات إليها، وعدلنا البيانات في العملية الفرعية وأرسلنا البيانات إلى العملية الأصل، وأخيرًا أنهينا العملية الفرع، وهذا كل ما نحتاج إليه في التواصل الأساسي بين العمليات، أما الآن فسنرى مثالًا حقيقيًا عمليًا، نعود فيه إلى برنامج دليل جهات الاتصال مرةً أخرى.
</p>

<h2>
	دليل جهات الاتصال بتقنية العميل/الخادم
</h2>

<p>
	بنينا نسخةً من دليل جهات الاتصال في فصل <a href="https://academy.hsoub.com/programming/general/%D8%A7%D9%84%D8%AA%D8%B9%D8%A7%D9%85%D9%84-%D9%85%D8%B9-%D8%A7%D9%84%D9%85%D9%84%D9%81%D8%A7%D8%AA-%D9%81%D9%8A-%D8%A7%D9%84%D8%A8%D8%B1%D9%85%D8%AC%D8%A9-r1334/#:~:text=%D9%87%D9%8A%20%D8%AF%D9%88%D9%86%20%D9%85%D8%B4%D8%A7%D9%83%D9%84.-,%D8%AF%D9%84%D9%8A%D9%84%20%D8%AC%D9%87%D8%A7%D8%AA%20%D8%A7%D9%84%D8%A7%D8%AA%D8%B5%D8%A7%D9%84,-%D9%84%D9%82%D8%AF%20%D9%83%D8%AA%D8%A8%D9%86%D8%A7%20%D8%AF%D9%84%D9%8A%D9%84" rel="">الملفات</a> باستخدام قاموس، وسنعيد استخدام ذلك المثال لكننا سنبني هذه المرة نسخة العميل/الخادم.
</p>

<p>
	لاحظ أن الشيفرة الأصلية كسرت إحدى قواعد الممارسة السليمة التي ذكرناها من قبل، وهي أننا أدرجنا شيفرة واجهة المستخدم في دوالنا المساعِدة، فإذا كنا سنستخدم تلك الشيفرة مرةً أخرى فسنحصل على رسائل مختلطة من العملية الفرعية والعملية الأصل، ونريد أن نعدل الشيفرة قليلًا كي نحولها إلى نموذج يمكن استخدامه، والمهم هنا إزالة أي تعليمة <code>print</code> من الدوال، وتمرير البيانات وسطاء، كما نريد إعادة النتيجة من كل دالة، بمجرد إنهاء ذلك نستطيع استيراد الشيفرة والوصول إلى الدوال المساعدة دون تنفيذ دالة <code>main()‎</code>، وعلى ذلك تكون الدوال التي سنوفرها هي:
</p>

<ul>
	<li>
		<code>readBook(filename)‎</code>
	</li>
	<li>
		<code>saveBook(book, filename)‎</code>
	</li>
	<li>
		<code>addEntry(book, name, data)‎</code>
	</li>
	<li>
		<code>removeEntry(book, name)‎</code>
	</li>
	<li>
		<code>findEntry(book, name)‎</code>
	</li>
</ul>

<p>
	وستبدو الشيفرة المعدلة كما يلي:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_5534_24" style=""><span class="pln">def readBook</span><span class="pun">(</span><span class="pln">filename</span><span class="pun">=</span><span class="str">'addbook.dat'</span><span class="pun">):</span><span class="pln">
    </span><span class="kwd">import</span><span class="pln"> os
    book </span><span class="pun">=</span><span class="pln"> </span><span class="pun">{}</span><span class="pln">
    </span><span class="kwd">if</span><span class="pln"> os</span><span class="pun">.</span><span class="pln">path</span><span class="pun">.</span><span class="pln">exists</span><span class="pun">(</span><span class="pln">filename</span><span class="pun">):</span><span class="pln">
       store </span><span class="pun">=</span><span class="pln"> open</span><span class="pun">(</span><span class="pln">filename</span><span class="pun">,</span><span class="str">'r'</span><span class="pun">)</span><span class="pln">
       </span><span class="kwd">for</span><span class="pln"> line in store</span><span class="pun">:</span><span class="pln">
          name</span><span class="pun">,</span><span class="pln">entry </span><span class="pun">=</span><span class="pln"> line</span><span class="pun">.</span><span class="pln">strip</span><span class="pun">().</span><span class="pln">split</span><span class="pun">(</span><span class="str">':'</span><span class="pun">)</span><span class="pln">
          book</span><span class="pun">[</span><span class="pln">name</span><span class="pun">]</span><span class="pln"> </span><span class="pun">=</span><span class="pln"> entry
    </span><span class="kwd">else</span><span class="pun">:</span><span class="pln">
        store </span><span class="pun">=</span><span class="pln"> open</span><span class="pun">(</span><span class="pln">filename</span><span class="pun">,</span><span class="str">'w'</span><span class="pun">)</span><span class="pln"> </span><span class="pun">#</span><span class="pln"> </span><span class="pun">أنشئ</span><span class="pln"> </span><span class="pun">ملفًا</span><span class="pln"> </span><span class="pun">فارغًا</span><span class="pln"> </span><span class="pun">جديدًا</span><span class="pln">
    store</span><span class="pun">.</span><span class="pln">close</span><span class="pun">()</span><span class="pln">
    </span><span class="kwd">return</span><span class="pln"> book

def saveBook</span><span class="pun">(</span><span class="pln">book</span><span class="pun">,</span><span class="pln"> filename </span><span class="pun">=</span><span class="pln"> </span><span class="str">"addbook.dat"</span><span class="pun">):</span><span class="pln">
    store </span><span class="pun">=</span><span class="pln"> open</span><span class="pun">(</span><span class="pln">filename</span><span class="pun">,</span><span class="str">'w'</span><span class="pun">)</span><span class="pln">
    </span><span class="kwd">for</span><span class="pln"> name</span><span class="pun">,</span><span class="pln">entry in book</span><span class="pun">.</span><span class="pln">items</span><span class="pun">():</span><span class="pln">
        line </span><span class="pun">=</span><span class="pln"> </span><span class="str">"%s:%s"</span><span class="pln"> </span><span class="pun">%</span><span class="pln"> </span><span class="pun">(</span><span class="pln">name</span><span class="pun">,</span><span class="pln">entry</span><span class="pun">)</span><span class="pln">
        store</span><span class="pun">.</span><span class="pln">write</span><span class="pun">(</span><span class="pln">line </span><span class="pun">+</span><span class="pln"> </span><span class="str">'\n'</span><span class="pun">)</span><span class="pln">
    store</span><span class="pun">.</span><span class="pln">close</span><span class="pun">()</span><span class="pln">

def addEntry</span><span class="pun">(</span><span class="pln">book</span><span class="pun">,</span><span class="pln"> name</span><span class="pun">,</span><span class="pln"> data</span><span class="pun">):</span><span class="pln">
    book</span><span class="pun">[</span><span class="pln">name</span><span class="pun">]</span><span class="pln"> </span><span class="pun">=</span><span class="pln"> data
    </span><span class="kwd">return</span><span class="pln"> </span><span class="str">'Added entry for '</span><span class="pln"> </span><span class="pun">+</span><span class="pln"> name

def removeEntry</span><span class="pun">(</span><span class="pln">book</span><span class="pun">,</span><span class="pln"> name</span><span class="pun">):</span><span class="pln">
    del</span><span class="pun">(</span><span class="pln">book</span><span class="pun">[</span><span class="pln">name</span><span class="pun">])</span><span class="pln">
    </span><span class="kwd">return</span><span class="pln"> </span><span class="str">'Deleted entry for '</span><span class="pln"> </span><span class="pun">+</span><span class="pln"> name

def findEntry</span><span class="pun">(</span><span class="pln">book</span><span class="pun">,</span><span class="pln"> name</span><span class="pun">):</span><span class="pln">
    </span><span class="kwd">if</span><span class="pln"> name in book</span><span class="pun">.</span><span class="pln">keys</span><span class="pun">():</span><span class="pln">
       result </span><span class="pun">=</span><span class="pln"> </span><span class="str">"%s : %s"</span><span class="pln"> </span><span class="pun">%</span><span class="pln"> </span><span class="pun">(</span><span class="pln">name</span><span class="pun">,</span><span class="pln"> book</span><span class="pun">[</span><span class="pln">name</span><span class="pun">])</span><span class="pln">
    </span><span class="kwd">else</span><span class="pun">:</span><span class="pln"> result </span><span class="pun">=</span><span class="pln"> </span><span class="str">"Sorry, no entry for: "</span><span class="pln"> </span><span class="pun">+</span><span class="pln"> name
    </span><span class="kwd">return</span><span class="pln"> result</span></pre>

<p>
	لاحظ أننا تجاهلنا دوال واجهة المستخدم لأننا لا نحتاج إليها هنا، لكن قد نرغب في إجراء التعديلات المناسبة للسماح لها بالعمل مثل برنامج منفصل، يكون وحدةً لنسخة العميل/الخادم، ولتكتب ذلك ليكون تدريبًا عمليًا لك.
</p>

<p>
	بمجرد أن نصلح الشيفرة وتكون صالحةً للعمل في برنامج مستقل، أو بحفظ الشيفرة أعلاه في ملف <code>address_srv.py</code>، وهو ما فعلناه، نستطيع أن نتابع كتابة شيفرة العميل/الخادم، وستتكون من الهيكل القياسي لإنشاء الأنابيب واشتقاق العملية، حيث سنقرأ في العملية الفرعية الأنبوب الوارد، ونفسر البيانات على أنها أمر متبوع بالوسطاء التي توفرت، ثم نستدعي دالة قاعدة البيانات المناسبة، وسنعرض -سواء في العملية الأصل أو الفرع- على المستخدم قائمةً، ونطلب أي بيانات إضافية وفقًا لما اختير قبل إرسال سلسلة البيانات المدمجة إلى العملية الفرع أو الخادم، ثم يقرأ العميل الاستجابة ويقدمها إلى المستخدم، وسيبدو البرنامج الرئيسي كما يلي:
</p>

<pre class="ipsCode prettyprint lang-py prettyprinted" id="ips_uid_5534_26" style=""><span class="kwd">import</span><span class="pln"> os</span><span class="pun">,</span><span class="pln"> signal</span><span class="pun">,</span><span class="pln"> address_srv

fromClient</span><span class="pun">,</span><span class="pln">toServer </span><span class="pun">=</span><span class="pln"> os</span><span class="pun">.</span><span class="pln">pipe</span><span class="pun">()</span><span class="pln">
fromServer</span><span class="pun">,</span><span class="pln">toClient </span><span class="pun">=</span><span class="pln"> os</span><span class="pun">.</span><span class="pln">pipe</span><span class="pun">()</span><span class="pln">

pid </span><span class="pun">=</span><span class="pln"> os</span><span class="pun">.</span><span class="pln">fork</span><span class="pun">()</span><span class="pln">
</span><span class="kwd">if</span><span class="pln"> pid </span><span class="pun">==</span><span class="pln"> </span><span class="lit">0</span><span class="pun">:</span><span class="pln">   </span><span class="com"># نحن الخادم</span><span class="pln">
   addresses </span><span class="pun">=</span><span class="pln"> address_srv</span><span class="pun">.</span><span class="pln">readBook</span><span class="pun">()</span><span class="pln">
   </span><span class="kwd">while</span><span class="pln"> </span><span class="kwd">True</span><span class="pun">:</span><span class="pln">
      s </span><span class="pun">=</span><span class="pln"> os</span><span class="pun">.</span><span class="pln">read</span><span class="pun">(</span><span class="pln">fromClient</span><span class="pun">,</span><span class="lit">1024</span><span class="pun">)</span><span class="pln">
      cmd</span><span class="pun">,</span><span class="pln">data </span><span class="pun">=</span><span class="pln"> s</span><span class="pun">.</span><span class="pln">split</span><span class="pun">(</span><span class="str">':'</span><span class="pun">)</span><span class="pln">
      </span><span class="kwd">if</span><span class="pln"> cmd </span><span class="pun">==</span><span class="pln"> </span><span class="str">"add"</span><span class="pun">:</span><span class="pln">
         details </span><span class="pun">=</span><span class="pln"> data</span><span class="pun">.</span><span class="pln">split</span><span class="pun">(</span><span class="str">','</span><span class="pun">)</span><span class="pln">
         name </span><span class="pun">=</span><span class="pln"> details</span><span class="pun">[</span><span class="lit">0</span><span class="pun">]</span><span class="pln">
         entry </span><span class="pun">=</span><span class="pln"> </span><span class="str">','</span><span class="pun">.</span><span class="pln">join</span><span class="pun">(</span><span class="pln">details</span><span class="pun">[</span><span class="lit">1</span><span class="pun">:])</span><span class="pln">
         s </span><span class="pun">=</span><span class="pln"> address_srv</span><span class="pun">.</span><span class="pln">addEntry</span><span class="pun">(</span><span class="pln">addresses</span><span class="pun">,</span><span class="pln"> name</span><span class="pun">,</span><span class="pln"> entry</span><span class="pun">)</span><span class="pln">
         address_srv</span><span class="pun">.</span><span class="pln">saveBook</span><span class="pun">(</span><span class="pln">addresses</span><span class="pun">)</span><span class="pln">
      </span><span class="kwd">elif</span><span class="pln"> cmd </span><span class="pun">==</span><span class="pln"> </span><span class="str">"rem"</span><span class="pun">:</span><span class="pln">
         s </span><span class="pun">=</span><span class="pln"> address_srv</span><span class="pun">.</span><span class="pln">removeEntry</span><span class="pun">(</span><span class="pln">addresses</span><span class="pun">,</span><span class="pln"> data</span><span class="pun">)</span><span class="pln">
         address_srv</span><span class="pun">.</span><span class="pln">saveBook</span><span class="pun">(</span><span class="pln">addresses</span><span class="pun">)</span><span class="pln">
      </span><span class="kwd">elif</span><span class="pln"> cmd </span><span class="pun">==</span><span class="pln"> </span><span class="str">"fnd"</span><span class="pun">:</span><span class="pln">
         s </span><span class="pun">=</span><span class="pln"> address_srv</span><span class="pun">.</span><span class="pln">findEntry</span><span class="pun">(</span><span class="pln">addresses</span><span class="pun">,</span><span class="pln"> data</span><span class="pun">)</span><span class="pln">
      </span><span class="kwd">else</span><span class="pun">:</span><span class="pln"> s </span><span class="pun">=</span><span class="pln"> </span><span class="str">"ERROR: Unrecognized command: "</span><span class="pln"> </span><span class="pun">+</span><span class="pln"> cmd
      os</span><span class="pun">.</span><span class="pln">write</span><span class="pun">(</span><span class="pln">toClient</span><span class="pun">,</span><span class="pln">s</span><span class="pun">)</span><span class="pln">
</span><span class="kwd">else</span><span class="pun">:</span><span class="pln">     </span><span class="com"># We are the client</span><span class="pln">
   menu </span><span class="pun">=</span><span class="pln"> </span><span class="str">'''
   1) Add Entry
   2) Delete Entry
   3) Find Entry

   4) Quit
   '''</span><span class="pln">
   </span><span class="kwd">while</span><span class="pln"> </span><span class="kwd">True</span><span class="pun">:</span><span class="pln">
      </span><span class="kwd">print</span><span class="pun">(</span><span class="pln"> menu </span><span class="pun">)</span><span class="pln">
      </span><span class="kwd">try</span><span class="pun">:</span><span class="pln"> choice </span><span class="pun">=</span><span class="pln"> int</span><span class="pun">(</span><span class="pln">input</span><span class="pun">(</span><span class="str">'Choose an option[1-4] '</span><span class="pun">))</span><span class="pln">
      </span><span class="kwd">except</span><span class="pun">:</span><span class="pln"> </span><span class="kwd">continue</span><span class="pln">
      </span><span class="kwd">if</span><span class="pln"> choice </span><span class="pun">==</span><span class="pln"> </span><span class="lit">1</span><span class="pun">:</span><span class="pln">
         name </span><span class="pun">=</span><span class="pln"> input</span><span class="pun">(</span><span class="str">'Enter the name: '</span><span class="pun">)</span><span class="pln">
         num </span><span class="pun">=</span><span class="pln"> input</span><span class="pun">(</span><span class="str">'Enter the House number: '</span><span class="pun">)</span><span class="pln">
         street</span><span class="pun">=</span><span class="pln"> input</span><span class="pun">(</span><span class="str">'Enter the Street name: '</span><span class="pun">)</span><span class="pln">
         town </span><span class="pun">=</span><span class="pln"> input</span><span class="pun">(</span><span class="str">'Enter the Town: '</span><span class="pun">)</span><span class="pln">
         phone </span><span class="pun">=</span><span class="pln"> input</span><span class="pun">(</span><span class="str">'Enter the Phone number: '</span><span class="pun">)</span><span class="pln">
         data </span><span class="pun">=</span><span class="pln"> </span><span class="str">"%s,%s,%s,%s,%s"</span><span class="pln"> </span><span class="pun">%</span><span class="pln"> </span><span class="pun">(</span><span class="pln">name</span><span class="pun">,</span><span class="pln">num</span><span class="pun">,</span><span class="pln">street</span><span class="pun">,</span><span class="pln">town</span><span class="pun">,</span><span class="pln">phone</span><span class="pun">)</span><span class="pln">
         cmd </span><span class="pun">=</span><span class="pln"> </span><span class="str">"add:%s"</span><span class="pln"> </span><span class="pun">%</span><span class="pln"> data
      </span><span class="kwd">elif</span><span class="pln"> choice </span><span class="pun">==</span><span class="pln"> </span><span class="lit">2</span><span class="pun">:</span><span class="pln"> 
         name </span><span class="pun">=</span><span class="pln"> input</span><span class="pun">(</span><span class="str">'Enter the name: '</span><span class="pun">)</span><span class="pln">
         cmd </span><span class="pun">=</span><span class="pln"> </span><span class="str">'rem:%s'</span><span class="pln"> </span><span class="pun">%</span><span class="pln"> name
      </span><span class="kwd">elif</span><span class="pln"> choice </span><span class="pun">==</span><span class="pln"> </span><span class="lit">3</span><span class="pun">:</span><span class="pln"> 
         name </span><span class="pun">=</span><span class="pln"> input</span><span class="pun">(</span><span class="str">'Enter the name: '</span><span class="pun">)</span><span class="pln">
         cmd </span><span class="pun">=</span><span class="pln"> </span><span class="str">'fnd:%s'</span><span class="pln"> </span><span class="pun">%</span><span class="pln"> name
      </span><span class="kwd">elif</span><span class="pln"> choice </span><span class="pun">==</span><span class="pln"> </span><span class="lit">4</span><span class="pun">:</span><span class="pln"> 
         </span><span class="kwd">break</span><span class="pln">
      </span><span class="kwd">else</span><span class="pun">:</span><span class="pln">
         </span><span class="kwd">print</span><span class="pun">(</span><span class="pln"> </span><span class="str">"Invalid choice, must be between 1 and 4."</span><span class="pln"> </span><span class="pun">)</span><span class="pln">
         </span><span class="kwd">continue</span><span class="pln">

      os</span><span class="pun">.</span><span class="pln">write</span><span class="pun">(</span><span class="pln">toServer</span><span class="pun">,</span><span class="pln"> cmd</span><span class="pun">)</span><span class="pln">
       </span><span class="kwd">print</span><span class="pun">(</span><span class="pln"> </span><span class="str">"\nRESULT: "</span><span class="pun">,</span><span class="pln"> os</span><span class="pun">.</span><span class="pln">read</span><span class="pun">(</span><span class="pln">fromServer</span><span class="pun">,</span><span class="lit">1024</span><span class="pun">)</span><span class="pln"> </span><span class="pun">)</span><span class="pln">

   os</span><span class="pun">.</span><span class="pln">kill</span><span class="pun">(</span><span class="pln">pid</span><span class="pun">,</span><span class="pln"> signal</span><span class="pun">.</span><span class="pln">SIGTERM</span><span class="pun">)</span></pre>

<p>
	لا شك أننا نستطيع ترتيب تلك الشيفرة لتكون أفضل باستخدام بعض دوال سلاسل <code>if/elif</code>، لكن المثال أصغر من أن يستدعي ذلك، ويجب ملاحظة بعض النقاط هي:
</p>

<ul>
	<li>
		استخدام <code>break</code> لإيقاف الحلقة التكرارية.
	</li>
	<li>
		استخدام <code>continue</code> للعودة إلى قمة الحلقة مرةً أخرى.
	</li>
</ul>

<p>
	وقد شرحنا ذلك باختصار في فصل <a href="https://academy.hsoub.com/programming/general/%D9%85%D9%82%D8%AF%D9%85%D8%A9-%D9%81%D9%8A-%D8%A7%D9%84%D8%A8%D8%B1%D9%85%D8%AC%D8%A9-%D8%A7%D9%84%D8%B4%D8%B1%D8%B7%D9%8A%D8%A9-r1329/" rel="">مقدمة في البرمجة الشرطية</a>، ويُرجع إلى توثيق كل منها للمزيد من التفاصيل.
</p>

<p>
	من الممكن توسيع هذا التدريب ليستخدم نسخة قاعدة البيانات التي شرحناها من قبل لتكون هي الخادم بدلًا من نسخة القاموس، وسنترك ذلك تدريبًا للقارئ.
</p>

<p>
	تكمن العقبة في مثل هذا النموذج من برمجة العميل/الخادم في أن الخادم لا يستطيع التحدث إلا مع العميل الذي بدأه، مع أنه يسهل إنشاء آلية لإنتاج عمليات إضافية تدرك أنها يجب أن تتصرف مثل عملاء لا خوادم، وكان من الأفضل بدء تشغيل الخادم أولًا ثم إلحاق عدة عملاء به، وهو ما سنفعله في نهاية المقال التالي حيث نشرح الشبكات بمزيد من التفصيل.
</p>

<h2>
	خاتمة
</h2>

<p>
	في نهاية هذا المقال نأمل أن تكون تعلمت ما يلي:
</p>

<ul>
	<li>
		تستطيع العمليات أن تتواصل فيما بينها بواسطة الأنابيب.
	</li>
	<li>
		تستطيع العمليات الأصل أن تستنسخ نفسها باستخدام <code>os.fork</code>.
	</li>
	<li>
		يجب إنهاء العمليات الفرعية وإلا ستعمل بلا نهاية، وتستهلك موارد الحاسوب، وننهيها باستخدام دالة <code>os.kill</code>.
	</li>
</ul>

<p>
	ترجمة -بتصرف- <a href="http://www.alan-g.me.uk/l2p2/tutipc.htm" rel="external nofollow">للفصل السادس والعشرين: Inter-Process Communication</a> من كتاب Learn To Program لصاحبه Alan Gauld.
</p>

<h2>
	اقرأ أيضًا
</h2>

<ul>
	<li>
		المقال التالي: <a href="https://academy.hsoub.com/devops/networking/%D8%AA%D9%88%D8%A7%D8%B5%D9%84-%D8%A7%D9%84%D8%A8%D8%B1%D8%A7%D9%85%D8%AC-%D9%88%D8%A7%D9%84%D8%B9%D9%85%D9%84%D9%8A%D8%A7%D8%AA-%D8%A7%D9%84%D8%A8%D8%B1%D9%85%D8%AC%D9%8A%D8%A9-%D8%B9%D8%A8%D8%B1-%D8%A7%D9%84%D8%B4%D8%A8%D9%83%D8%A9-r603/" rel="">تواصل البرامج والعمليات البرمجية عبر الشبكة</a>
	</li>
	<li>
		المقال السابق: <a href="https://academy.hsoub.com/programming/python/%D8%A7%D9%84%D8%AA%D9%88%D8%A7%D8%B5%D9%84-%D9%85%D8%B9-%D9%86%D8%B8%D8%A7%D9%85-%D8%A7%D9%84%D8%AA%D8%B4%D8%BA%D9%8A%D9%84-%D8%B9%D8%A8%D8%B1-%D8%A8%D8%A7%D9%8A%D8%AB%D9%88%D9%86-r1520/" rel="">التواصل مع نظام التشغيل عبر بايثون</a>
	</li>
	<li>
		<a href="https://academy.hsoub.com/programming/general/%D8%B9%D9%84%D9%88%D9%85-%D8%A7%D9%84%D8%AD%D8%A7%D8%B3%D9%88%D8%A8/" rel="">المدخل الشامل لتعلم علوم الحاسوب</a>
	</li>
	<li>
		<a href="https://academy.hsoub.com/programming/general/%D8%A7%D9%84%D8%AA%D8%B9%D8%A7%D9%85%D9%84-%D9%85%D8%B9-%D8%A7%D9%84%D9%85%D9%84%D9%81%D8%A7%D8%AA-%D9%81%D9%8A-%D8%A7%D9%84%D8%A8%D8%B1%D9%85%D8%AC%D8%A9-r1334/" rel="">التعامل مع الملفات في البرمجة</a>
	</li>
	<li>
		<a href="https://academy.hsoub.com/certificates/comptia/%D9%85%D8%AF%D8%AE%D9%84-%D8%A5%D9%84%D9%89-%D8%B4%D8%A8%D9%83%D8%A7%D8%AA-%D8%A7%D9%84%D8%AD%D9%88%D8%A7%D8%B3%D9%8A%D8%A8-%D9%85%D8%B5%D8%B7%D9%84%D8%AD%D8%A7%D8%AA-%D9%88%D9%81%D9%87%D9%85-%D8%B7%D8%A8%D9%82%D8%A7%D8%AA-%D8%A7%D9%84%D8%B4%D8%A8%D9%83%D8%A9-r65/" rel="">مدخل إلى شبكات الحواسيب: مصطلحات وفهم طبقات الشبكة</a>
	</li>
</ul>
]]></description><guid isPermaLink="false">1521</guid><pubDate>Mon, 11 Apr 2022 15:01:00 +0000</pubDate></item><item><title>&#x627;&#x644;&#x623;&#x62F;&#x648;&#x627;&#x62A; &#x627;&#x644;&#x62A;&#x64A; &#x64A;&#x62C;&#x628; &#x639;&#x644;&#x649; &#x643;&#x644; &#x645;&#x637;&#x648;&#x631; &#x648;&#x64A;&#x628; &#x627;&#x633;&#x62A;&#x62E;&#x62F;&#x627;&#x645;&#x647;&#x627;</title><link>https://academy.hsoub.com/programming/general/%D8%A7%D9%84%D8%A3%D8%AF%D9%88%D8%A7%D8%AA-%D8%A7%D9%84%D8%AA%D9%8A-%D9%8A%D8%AC%D8%A8-%D8%B9%D9%84%D9%89-%D9%83%D9%84-%D9%85%D8%B7%D9%88%D8%B1-%D9%88%D9%8A%D8%A8-%D8%A7%D8%B3%D8%AA%D8%AE%D8%AF%D8%A7%D9%85%D9%87%D8%A7-r1724/</link><description><![CDATA[
<p><img src="https://academy.hsoub.com/uploads/monthly_2022_10/6337c9a4c178e_5.png.ffa9b4f0716b7a46e4d04c1860effce7.png" /></p>

<p>
	لا شك أن كل مطور ويب يتعامل مع الكثير من الأدوات، والتي تساعده خلال تطوير المواقع. بالطبع الأدوات كثيرة ولكل مطور ويب تفضيلاته الخاصة، ولكن توجد بعض الأدوات التي لا يمكن الاستغناء عنها لأي مطور ويب. في هذا الفيديو، سنخبرك عن 5 أدوات يجب على كل مطور ويب استخدامها عند تطوير المواقع.
</p>

<p style="text-align: center;">
	<iframe allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture" allowfullscreen="" frameborder="0" height="480" title="5 أدوات يجب على كل مطور ويب استخدامها" width="853" src="https://www.youtube.com/embed/0oS1uWYlxYk"></iframe>
</p>

<p>
	بعد تعرفك على أبرز الأدوات المهمة للمطور، يمكنك تعلم المزيد عن هذه الأدوات في المقالات المجانية المقدمة من أكاديمية حسوب في مجالي <a href="https://academy.hsoub.com/programming/" rel="">البرمجة</a> والـ <a href="https://academy.hsoub.com/devops/" rel="">DevOps</a> للتأكد من التحكم أكثر في هذه الأدوات التي ستستخدمها خلال عملك وتعلمك للتطوير.
</p>

<p>
	يمكنك أيضًا الانضمام إلى <a href="https://academy.hsoub.com/" rel="">إحدى دورات حسوب</a> لتعلم تطوير الويب باحترافية أكبر، حيث يمكنك اختيار المجال الذي ترغب في تعلمه واللغة التي سيقوم عليها تطويرك، والاشتراك بها؛ وهنا يمكنك الاستعانة بالتوثيقات المجانية للغات البرمجية الأكثر شيوعًا والمتاحة على <a href="https://wiki.hsoub.com/%D8%A7%D9%84%D8%B5%D9%81%D8%AD%D8%A9_%D8%A7%D9%84%D8%B1%D8%A6%D9%8A%D8%B3%D9%8A%D8%A9" rel="external">موسوعة حسوب</a>، لإثراء رحلة تعلمك وعملك أكثر.
</p>
]]></description><guid isPermaLink="false">1724</guid><pubDate>Wed, 06 Apr 2022 15:30:00 +0000</pubDate></item><item><title>&#x643;&#x64A;&#x641; &#x62A;&#x635;&#x628;&#x62D; &#x645;&#x637;&#x648;&#x631; Full Stack</title><link>https://academy.hsoub.com/programming/general/%D9%83%D9%8A%D9%81-%D8%AA%D8%B5%D8%A8%D8%AD-%D9%85%D8%B7%D9%88%D8%B1-full-stack-r1719/</link><description><![CDATA[
<p><img src="https://academy.hsoub.com/uploads/monthly_2022_09/633527174dddd_Full-stack.png.0e6f1294990be37d18f8b0afcfe8cc96.png" /></p>

<p>
	لعلك قد سمعت سابقًا عن شخص ما يعمل بوظيفة مطور Full-stack أو أن شركةً ما تسعى لتوظيف مطور Full-stack، ولكن ماذا تعني كلمة Full-stack؟ وماهي المهام التي قد يؤديها بها مطور Full-stack؟ وكيف يمكن أن تصبح مطور Full-stack؟
</p>

<p>
	يوضح الفيديو الآتي كل الإجابات اللازمة على الأسئلة السابقة، كما يبين أبرز المهارات والمكتسبات البرمجية اللازم توفرها في المطور نفسه، حتى يكون مطور Full-stack.
</p>

<p>
	<iframe allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture" allowfullscreen="" frameborder="0" height="480" title="كيف أصبح مطور Full Stack" width="853" src="https://www.youtube.com/embed/XqhWutUP5qY"></iframe>
</p>

<p>
	بعد اطلاعك على الفيديو وتعرفك على مفهوم مطور الـ Full-stack والمتطلبات البرمجية اللازمة لتكون مطورًا من هذا النوع، بات في إمكانك تحديد اللغات البرمجية التي تحتاج لتعلمها لتصل إلى هدفك في أن تكون مطور واجهات أمامية وخلفية معًا Full-stack، وهنا يمكنك الاطلاع مجانًا على بعض <a href="https://academy.hsoub.com/programming/" rel="">المقالات البرمجية المتاحة على أكاديمية حسوب</a>، كما يمكنك الاستعانة <a href="https://academy.hsoub.com/" rel="">بدورات احترافية</a> مقدمة بهذا الخصوص، وذلك بالاشتراك في <a href="https://academy.hsoub.com/learn/front-end-web-development/" rel="">دورة تطوير واجهات المستخدم</a> لإتمام تعلمك الاحترافي في الواجهات الأمامية Front-end، واختيار أي من الدورات الأخرى الموجهة للواجهات الخلفية Back-end وفقًا للغة التي تراها أنسب لك كالآتي:
</p>

<ul>
<li>
		<a href="https://academy.hsoub.com/learn/python-application-development/" rel="">دورة تطوير التطبيقات باستخدام لغة Python</a>
	</li>
	<li>
		<a href="https://academy.hsoub.com/learn/ruby-web-application-development/" rel="">دورة تطوير تطبيقات الويب باستخدام لغة Ruby</a>
	</li>
	<li>
		<a href="https://academy.hsoub.com/learn/php-web-application-development/" rel="">تطوير تطبيقات الويب باستخدام لغة PHP</a>
	</li>
	<li>
		<a href="https://academy.hsoub.com/learn/javascript-application-development/" rel="">تطوير التطبيقات باستخدام لغة JavaScript</a>
	</li>
</ul>
<p>
	يمكنك أيضًا دعم مرحلة تعلمك وما بعدها بالاطلاع على التوثيقات المجانية الخاصة بأبرز اللغات البرمجية الشائعة، وذلك على <a href="https://wiki.hsoub.com/%D8%A7%D9%84%D8%B5%D9%81%D8%AD%D8%A9_%D8%A7%D9%84%D8%B1%D8%A6%D9%8A%D8%B3%D9%8A%D8%A9" rel="external">موسوعة حسوب</a>.
</p>
]]></description><guid isPermaLink="false">1719</guid><pubDate>Tue, 29 Mar 2022 15:30:00 +0000</pubDate></item><item><title>&#x627;&#x644;&#x623;&#x62E;&#x637;&#x627;&#x621; &#x627;&#x644;&#x633;&#x628;&#x639; &#x627;&#x644;&#x642;&#x627;&#x62A;&#x644;&#x629; &#x644;&#x623;&#x64A; &#x645;&#x634;&#x631;&#x648;&#x639; &#x628;&#x631;&#x645;&#x62C;&#x64A;</title><link>https://academy.hsoub.com/programming/general/%D8%A7%D9%84%D8%A3%D8%AE%D8%B7%D8%A7%D8%A1-%D8%A7%D9%84%D8%B3%D8%A8%D8%B9-%D8%A7%D9%84%D9%82%D8%A7%D8%AA%D9%84%D8%A9-%D9%84%D8%A3%D9%8A-%D9%85%D8%B4%D8%B1%D9%88%D8%B9-%D8%A8%D8%B1%D9%85%D8%AC%D9%8A-r1736/</link><description><![CDATA[
<p><img src="https://academy.hsoub.com/uploads/monthly_2022_10/633d0b89ef7a7_-----.png.a771e8e26d0cfd305ed7fdcc24863a6b.png" /></p>

<p>
	قد تظن أن إدارة مشروع برمجيات خلال فترة التطوير عملية سهلة، ولكن الواقع عكس ذلك إذ أن مشروع البرمجيات حاله حال المشاريع الأخرى، إذ عليك مراعاة بعض الأمور والتفاصيل وأخذها بعين بالحسبان لتجنب الأخطاء أثناء عملية التطوير.
</p>

<p>
	في هذا الفيديو سنعرفك بأبرز الأخطاء التي قد تؤدي إلى فشل مشروع البرمجيات، والتي يجب عليك تجنبها لضمان استمرارية مشروعك
</p>

<p style="text-align: center;">
	<iframe allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture" allowfullscreen="" frameborder="0" height="480" title="الأخطاء السبع القاتلة لأي مشروع برمجي" width="853" src="https://www.youtube.com/embed/dICBdH6rMZ0"></iframe>
</p>

<p>
	بعد تعرفك على أهم الأخطاء القاتلة للمشروع البرمجي، بات عليك أخذها بالحسبان لتجنب الوقوع فيها. يمكنك التعرف أكثر على البرمجيات وكيفية التعامل معها برمجيًا من خلال المقالات المجانية المقدمة من أكاديمية حسوب في <a href="https://academy.hsoub.com/programming/" rel="">قسم البرمجة</a>، كما يمكنك التعرف باحترافية أكبر على أساسيات البرمجة وأنماط التصميم والخوارزميات عن طريق الاشتراك في <a href="https://academy.hsoub.com/programming/https://academy.hsoub.com/programming/https://academy.hsoub.com/programming/https://academy.hsoub.com/programming/https://academy.hsoub.com/programming/" rel="">دورة علوم الحاسوب</a> المقدمة من أكاديمية حسوب.
</p>
]]></description><guid isPermaLink="false">1736</guid><pubDate>Sun, 20 Mar 2022 15:30:00 +0000</pubDate></item><item><title>&#x647;&#x644; &#x627;&#x644;&#x628;&#x631;&#x645;&#x62C;&#x629; &#x635;&#x639;&#x628;&#x629; &#x648;&#x645;&#x648;&#x62C;&#x647;&#x629; &#x644;&#x641;&#x626;&#x627;&#x62A; &#x645;&#x62D;&#x62F;&#x62F;&#x629; &#x641;&#x642;&#x637;&#x61F;</title><link>https://academy.hsoub.com/programming/general/%D9%87%D9%84-%D8%A7%D9%84%D8%A8%D8%B1%D9%85%D8%AC%D8%A9-%D8%B5%D8%B9%D8%A8%D8%A9-%D9%88%D9%85%D9%88%D8%AC%D9%87%D8%A9-%D9%84%D9%81%D8%A6%D8%A7%D8%AA-%D9%85%D8%AD%D8%AF%D8%AF%D8%A9-%D9%81%D9%82%D8%B7%D8%9F-r1718/</link><description><![CDATA[
<p><img src="https://academy.hsoub.com/uploads/monthly_2022_09/6333e545d258d_--.png.423fdbe53f99ccc92e4b7a1a9a5dc9bc.png" /></p>

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

<p>
	خلال هذا الفيديو سنعمل على توضيح <a href="https://academy.hsoub.com/programming/general/%d9%83%d9%8a%d9%81-%d8%aa%d8%aa%d8%b9%d9%84%d9%85-%d8%a7%d9%84%d8%a8%d8%b1%d9%85%d8%ac%d8%a9-r17/" rel="">آلية تعلم البرمجة</a>، وأن <a href="https://academy.hsoub.com/programming/general/%D9%84%D8%BA%D8%A7%D8%AA-%D8%A7%D9%84%D8%A8%D8%B1%D9%85%D8%AC%D8%A9/" rel="">لغات البرمجة</a> ليست صعبة، وما الذي تحتاج إليه من وقت ومعرفة لتعلم البرمجة.
</p>

<p style="text-align: center;">
	<iframe allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture" allowfullscreen="" frameborder="0" height="480" title="هل البرمجة فعلًا صعبة؟" width="853" src="https://www.youtube.com/embed/B8U1CE6V_is"></iframe>
</p>

<p>
	الآن، وبعد اطلاعك على محتوى الفيديو، بات في إمكانك تحديد مسارك الصحيح <a href="https://academy.hsoub.com/programming/general/%D8%AA%D8%B9%D9%84%D9%85-%D8%A7%D9%84%D8%A8%D8%B1%D9%85%D8%AC%D8%A9-r662/" rel="">لتعلم البرمجة</a> وتفادي الصعوبات والمشاكل الشائعة. ستجد على أكاديمية حسوب <a href="https://academy.hsoub.com/programming/" rel="">مجموعة مقالات مجانية حول البرمجة بمختلف نواحيه</a>ا، كما يمكنك الاستعانة <a href="https://wiki.hsoub.com/%D8%A7%D9%84%D8%B5%D9%81%D8%AD%D8%A9_%D8%A7%D9%84%D8%B1%D8%A6%D9%8A%D8%B3%D9%8A%D8%A9" rel="external">بموسوعة حسوب</a> خلال وبعد مرحلة التعلم، وذلك للاطلاع على توثيقات أهم اللغات البرمجية المتاحة في وقتنا هذا. وإن رغبت في تعلم البرمجة باحترافية وتخصص أكبر، يمكنك الاشتراك بإحدى <a href="https://academy.hsoub.com/" rel="">الدورات المقدمة من أكاديمية حسوب</a> بهذا المجال، وفقًا لأهدافك في هذا المجال.
</p>
]]></description><guid isPermaLink="false">1718</guid><pubDate>Mon, 14 Mar 2022 15:30:00 +0000</pubDate></item><item><title>&#x643;&#x64A;&#x641; &#x62A;&#x62D;&#x62A;&#x631;&#x641; &#x627;&#x644;&#x628;&#x631;&#x645;&#x62C;&#x629;&#x61F;</title><link>https://academy.hsoub.com/programming/general/%D9%83%D9%8A%D9%81-%D8%AA%D8%AD%D8%AA%D8%B1%D9%81-%D8%A7%D9%84%D8%A8%D8%B1%D9%85%D8%AC%D8%A9%D8%9F-r2067/</link><description><![CDATA[
<p><img src="https://academy.hsoub.com/uploads/monthly_2023_08/567981710_.png.cc543233b7a838789133cc3af1c67810.png" /></p>
<p>
	لا يخفى على أحد أن البرمجة أصبحت من أهم المهارات في عصرنا الحالي، وذلك لأنها دخلت في جميع مجالات حياتنا. كل شيء من حولنا لم نكن لنراه بهذا الشكل لولا البرمجة.<br>
	بالطبع حتى تتمكن من هذا المجال أنت بحاجة إلى بعض النصائح من أشخاص لهم خبرة البرمجة.
</p>

<p>
	في هذا الفيديو نقدم لك أهم النصائح حتى تحترف البرمجة بالطريقة الصحيحة.
</p>

<p>
	<iframe allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share" allowfullscreen="" frameborder="0" height="603" src="https://academy.hsoub.com/applications/core/interface/index.html" title="كيف تحترف البرمجة" width="1072" data-embed-src="https://www.youtube.com/embed/LB3ueddlR54"></iframe>
</p>

<p>
	إذا أردت التعرف أكثر على مجال البرمجة واحترافه، فننصحك بالانطلاق من <a href="https://academy.hsoub.com/learn/computer-science/" rel="">دورة علوم الحاسوب</a>، ولا تنسَ الاستعانة خلال رحلة تعلمك وعملك بتوثيقات <a href="https://wiki.hsoub.com/%D8%A7%D9%84%D8%B5%D9%81%D8%AD%D8%A9_%D8%A7%D9%84%D8%B1%D8%A6%D9%8A%D8%B3%D9%8A%D8%A9" rel="external">موسوعة حسوب</a> المجانية. وإذا أردت متابعة المعلومات البرمجية العلمية مكتوبة فيمكنك الاطلاع على <a href="https://academy.hsoub.com/programming/" rel="">قسم البرمجة في أكاديمية حسوب</a>، كما يمكنك متابعة جديد الفيديوهات التقنية المتاحة على <a href="https://www.youtube.com/@HsoubAcademy" rel="external nofollow">يوتيوب أكاديمية حسوب</a> مجانًا.
</p>
]]></description><guid isPermaLink="false">2067</guid><pubDate>Fri, 11 Mar 2022 15:00:00 +0000</pubDate></item><item><title>&#x645;&#x64A;&#x632;&#x627;&#x62A; &#x62A;&#x637;&#x628;&#x64A;&#x642; &#x627;&#x644;&#x648;&#x64A;&#x628; &#x627;&#x644;&#x62A;&#x642;&#x62F;&#x645;&#x64A; PWA</title><link>https://academy.hsoub.com/programming/general/%D9%85%D9%8A%D8%B2%D8%A7%D8%AA-%D8%AA%D8%B7%D8%A8%D9%8A%D9%82-%D8%A7%D9%84%D9%88%D9%8A%D8%A8-%D8%A7%D9%84%D8%AA%D9%82%D8%AF%D9%85%D9%8A-pwa-r1489/</link><description><![CDATA[
<p><img src="https://academy.hsoub.com/uploads/monthly_2022_02/6210bca2e49e3_------PWA.png.25fe645e1748698da0c0e7a9feecb790.png" /></p>

<p>
	صممت <a href="https://academy.hsoub.com/programming/general/%D9%85%D8%AF%D8%AE%D9%84-%D8%A5%D9%84%D9%89-%D8%AA%D8%B7%D8%A8%D9%8A%D9%82%D8%A7%D8%AA-%D8%A7%D9%84%D9%88%D9%8A%D8%A8-%D8%A7%D9%84%D8%AA%D9%82%D8%AF%D9%85%D9%8A%D8%A9-pwa-r832/" rel="">تطبيقات الويب التقدمية PWA</a> -اختصارًا إلى Progressive Web Apps- باستخدام واجهات برمجة تطبيقات حديثة، لتقديم إمكانيات أفضل وموثوقية وقابلية للتثبيت وذلك للوصول إلى أي شخص في أي مكان على أي جهاز بكتابة شيفرة واحدة.
</p>

<h2>
	ميزات تطبيقات الويب التقدمية الأساسية
</h2>

<p>
	سنعرض في هذا المقال الأسباب التي تجعل تطبيق الويب التقدمي جيدًا على جميع الأجهزة ولجميع المستخدمين من عدة نواحي بغض النظر عن حجم أو نوع الجهاز.
</p>

<h3>
	1. سريعة أداة
</h3>

<p>
	المواقع عالية الأداء تجذب المستخدمين وتحتفظ بهم بشكل أفضل من المواقع ضعيفة الأداء، إذ يلعب الأداء دورا هاما في نجاح أي تجربة عبر الإنترنت. يجب يركز الموقع على تحسين مقاييس الأداء المتعلقة بالمستخدم.
</p>

<p>
	للسرعة أهمية كبيرة في جذب المستخدمين لتطبيقك. إذ أنه في الحقيقة مع زيادة وقت تحميل الصفحة من ثانية واحدة إلى عشر ثوانٍ، يزداد احتمال ارتداد المستخدم إثر ذلك بنسبة 123٪.
</p>

<p>
	الأداء لا يتوقف مع تحميل الصفحة، فيجب ألا يتساءل المستخدمون أبدًا عما إذا كان تفاعلهم - مثلا عند النقر فوق زر ما - يحدث شيئا ما. يجب أن يشعر المستخدم بسلاسة أثناء التمرير وعرض الرسوم المتحركة. يؤثر الأداء على تجربتك بالكامل، بدءًا من كيفية إدراك المستخدمين لتطبيقك إلى أدائه الفعلي.
</p>

<p>
	رغم امتلاك جميع التطبيقات خصوصياتها، إلا أن عمليات تدقيق الأداء في Lighthouse تستند إلى نموذج الأداء المرتكز على المستخدم RAIL user-centric performance model، تسجيل نقاط عالية في عمليات التدقيق هذه يعني زيادة احتمالية تمتع المستخدمين بتجربة ممتعة. يمكنك أيضًا استخدام PageSpeed Insights أو تقرير تجربة مستخدم كروم Chrome User Experience Report للحصول على بيانات أداء واقعية لتطبيق الويب الخاص بك.
</p>

<h3>
	2. تعمل على جميع المتصفحات
</h3>

<p>
	يمكن للمستخدمين اختيار أي متصفح للوصول إلى تطبيق الويب التقدمي الخاص بك قبل تثبيته، فتطبيقات الويب التقدمية هي تطبيقات ويب أساسا، هذا يعني أنها تحتاج إلى العمل عبر جميع المتصفحات.
</p>

<p>
	تتمثل إحدى الطرق الفعالة للقيام بذلك في تحديد الوظائف الأساسية، وإتاحة هذه الوظيفة باستخدام بتقنية بسيطة، ثم تحسين التجربة كلما أمكن، كما يقول Jeremy Keith في تصميم الويب المرن <a href="https://resilientwebdesign.com/" rel="external nofollow">Resilient Web Design</a>، في كثير من الحالات يعني هذا البدء باستخدام <a href="https://wiki.hsoub.com/HTML" rel="external">HTML</a> فقط لتصميم الوظائف الأساسية، وتحسين تجربة المستخدم باستخدام <a href="https://wiki.hsoub.com/CSS" rel="external">CSS</a> و <a href="https://wiki.hsoub.com/JavaScript" rel="external">JavaScript</a> لإنشاء تجربة أكثر جاذبية للمستخدم.
</p>

<p>
	على سبيل المثال نأخذ إرسال النماذج form submission، إن أبسط طريقة لتنفيذ ذلك هي نموذج HTML الذي يرسل طلب POST. ثم يمكنك <a href="https://academy.hsoub.com/design/user-experience/%d9%85%d8%af%d8%ae%d9%84-%d8%a5%d9%84%d9%89-%d8%aa%d8%ac%d8%b1%d8%a8%d8%a9-%d8%a7%d9%84%d9%85%d8%b3%d8%aa%d8%ae%d8%af%d9%85-user-experience-r149/" rel="">تحسين تجربة المستخدم</a> باستعمال JavaScript لإجراء تحقق من صحة النموذج و<a href="https://academy.hsoub.com/programming/javascript/jquery/%D9%85%D9%8F%D9%82%D8%AF%D9%91%D9%85%D8%A9-%D8%A5%D9%84%D9%89-ajax-%D9%88%D8%A7%D9%84%D9%83%D8%A7%D8%A6%D9%86%D8%A7%D8%AA-%D8%A7%D9%84%D9%85%D9%8F%D8%A4%D8%AC%D9%91%D9%84%D8%A9-deferred-objects-%D8%B9%D9%84%D9%89-jquery-r64/" rel="">إرسال النموذج عبر AJAX</a>، <a href="https://academy.hsoub.com/design/user-experience/%D9%85%D8%AF%D8%AE%D9%84-%D8%A5%D9%84%D9%89-%D8%AA%D8%AC%D8%B1%D8%A8%D8%A9-%D8%A7%D9%84%D9%85%D8%B3%D8%AA%D8%AE%D8%AF%D9%85-user-experience-r149/" rel="">تحسين التجربة للمستخدمين</a> الذين يمكنهم دعمها.
</p>

<p>
	ضع في اعتبارك أن المستخدمين سيختبرون موقعك عبر أجهزة ومتصفحات مختلفة، إذا لا يمكنك ببساطة استهداف فئة معينة.
</p>

<p>
	يمكنك التحقق من الميزات المتاحة باستعمال التحقق من الميزات feature detection هذا سيمكنك من تقديم تجربة قابلة للاستخدام على نطاق واسع من المستخدمين، بما في ذلك أولئك الذين يستخدمون المتصفحات والأجهزة التي قد لا تكون موجودة حاليا.
</p>

<h3>
	3. تستجيب لجميع أحجام الشاشات
</h3>

<p>
	يمكن للمستخدمين <a href="https://academy.hsoub.com/programming/javascript/%D8%AA%D9%88%D9%81%D9%8A%D8%B1-%D8%AA%D8%AC%D8%B1%D8%A8%D8%A9-%D8%AA%D8%AB%D8%A8%D9%8A%D8%AA-%D9%85%D8%AE%D8%B5%D8%B5%D8%A9-%D8%AF%D8%A7%D8%AE%D9%84-%D8%AA%D8%B7%D8%A8%D9%8A%D9%82-%D8%A7%D9%84%D9%88%D9%8A%D8%A8-%D8%A7%D9%84%D8%AA%D9%82%D8%AF%D9%85%D9%8A-pwa-r1445/" rel="">استعمال تطبيق الويب التقدمي PWA </a>الخاص بك على أي شاشة ويتوفر المحتوى بجميع الأحجام.
</p>

<p>
	يمكن أن تأتي الأجهزة بأحجام مختلفة، ويمكن للمستخدمين استخدام تطبيقك بأحجام مختلفة على نفس الجهاز، لذلك من المهم جدا التأكد من أن المحتوى يتلاءم مع أحجام مختلفة وليس مع إطار العرض viewport فقط، ويجب أيضا أن تتأكد من أن محتوى موقعك وجميع ميزاته قابلة للاستخدام في جميع الأجهزة والأحجام.
</p>

<p>
	لا تتغير المهام التي يريد المستخدمون إكمالها والمحتوى الذي يريدون الوصول إليه مع تغير حجم الشاشة. ويمكن إعادة ترتيب المحتوى بأحجام ليناسب حجم العرض، ويجب أن يكون متوفرا، كما يقول Luke Wroblewski في كتابه Mobile First، البدء بشيء صغيرا وتطويره وليس العكس يمكنه في الواقع تحسين تصميم الموقع.
</p>

<p>
	تتطلب الأجهزة المحمولة من فرق التطوير التركيز فقط على البيانات والإجراءات الأكثر أهمية في التطبيق. لا توجد مساحة في شاشة 320x480 بكسل للعناصر الإضافية وغير الضرورية، لذا عليك أن تعطي الأولوية للعناصر المهمة.
</p>

<h3>
	4. يوفر صفحة يمكن الوصول إليها دون إنترنت
</h3>

<p>
	عندما يكون المستخدمون غير متصلين، فإن الاحتفاظ بهم في تطبيق الويب التقدمي الخاص بك يوفر تجربة أكثر سلاسة من الصفحة الافتراضية للمتصفح التي تعرض حالة عدم الاتصال بإنترنت.
</p>

<p>
	يتوقع المستخدمون أن تعمل التطبيقات المثبتة بغض النظر عن وجود إنترنت. لا يعرض التطبيق المخصص بالنظام صفحة فارغة عندما يكون الجهازة مفصولا عن الإنترنت، كذلك الأمر بالنسبة لتطبيق الويب التقدمي إذ يجب ألا يعرض الصفحة الافتراضية للمتصفح في وضع عدم الاتصال بالإنترنت.
</p>

<p>
	إن توفير تجربة مخصصة في وضع عدم الاتصال، سواء حاول المستخدم الولوج لرابط لم يتم تخزينه أو حاول استخدام ميزة تتطلب اتصالا يساعد على جعل تجربة الويب الخاصة بك تشغر المستخدم بأنها جزء من الجهاز الذي يتم التشغيله عليه.
</p>

<p>
	يمكنك جعل تطبيق الويب التقدمي الخاص بك يعمل بدون اتصال وذلك بتخزين صفحة لا تتطلب اتصالا بالإنترنت مؤقتًا لاستخدامها لاحقًا أثناء حدث تثبيت منجز الخدمة، إذا انتقل المستخدم إلى وضع عدم الاتصال، فيمكنك حينها استخدام الصفحة التي خزنتها. ويمكنك متابعة <a href="https://googlechrome.github.io/samples/service-worker/custom-offline-page/" rel="external nofollow">offline page sample</a> للاطلاع على مثال على ذلك أثناء العمل ومعرفة كيفية تنفيذه بنفسك.
</p>

<h3>
	5. قابل للتثبيت
</h3>

<p>
	يميل المستخدمون الذين الذين ثبتوا التطبيق أو أضافوه إلى أجهزتهم إلى التفاعل مع هذه التطبيقات بشكل أكبر.
</p>

<p>
	تثبيت تطبيق الويب التقدمي يُشعِر المستخدم أن تطبيق الويب التقدمي الخاص بك مثل جميع التطبيقات المثبتة الأخرى. إذ يتم تشغيله من نفس المكان الذي تشغل منه المستخدمون تطبيقاتهم الأخرى. ويتم يتم تشغيله في نافذة تطبيق خاصة به منفصلة عن المتصفح ويظهر في قائمة المهام، مثله مثل التطبيقات الأخرى.
</p>

<p>
	السبب الذي يجعلك ترغب في أن يثبت المستخدمون تطبيق الويب التقدمي الخاص بك هو نفس السبب الذي يجعلك ترغب في تثبيت تطبيقك المخصص للنظام من متجر التطبيقات، فالمستخدمون الذين يثبتون تطبيق الويب التقدمي الخاص بك هم عادة الأكثر تفاعلاً، ومقايس تفاعلهم أفضل من المستخدمين العاديين، وغالبا ما يكون ذلك قريبا من مقاييس تفاعل المستخدمين على تطبيقك المخصص للنظام، تتضمن هذه المقاييس عددًا أكبر من الزيارات المتكررة، وقضاء وقت أطول على تطبيقك ومعدلات تحويل أعلى.
</p>

<h2>
	ميزات تطبيقات الويب التقدمية المثالية
</h2>

<p>
	تحتاج إلى ما هو أكثر من مجرد قائمة التحقق الأساسية لإنشاء تطبيق ويب تقدمي رائع ويكون أفضل تطبيق في فئته.
</p>

<p>
	يهدف وجود قائمة التحقق المثلى لتطبيق الويب التقدمي إلى جعله جزء من الجهاز الذي يعمل عليه بالاستفادة من ميزات الويب التي تجعله قويا.
</p>

<h3>
	1. يوفر إمكانية العمل دون إنترنت
</h3>

<p>
	يمكن أن يعمل تطبيقك بنفس الطريقة التي يعمل بها أثناء وجود اتصال بالإنترنت عندما لا يكون الاتصال ضروريا.
</p>

<p>
	إضافة إلى توفير صفحة مخصصة لا تتطلب وصولا للإنترنت، يتوقع المستخدمون أن يكون تطبيق الويب التقدمي قابلا للاستخدام أثناء عدم الاتصال، مثلا: يجب في تطبيقات السفر وشركات الطيران أن تكون التفاصيل حول الرحلة وتذاكر الصعود إلى الطائرة متاحة بسهولة أثناء عدم الاتصال بالإنترنت. ويجب أن تسمح تطبيقات الموسيقى والفيديو والبودكاست بالتشغيل في وضع عدم الاتصال. ويجب أن تقوم تطبيقات التواصل الإجتماعي والأخبار بتخزين المحتوى الحديث مؤقتًا حتى يتمكن المستخدمون من قراءته أثناء عدم الاتصال بالإنترنت. ويتوقع المستخدمون أيضًا أن يظل دخولهم مسجلا في وضع عدم الاتصال، لذلك عليه أن تصمم مصادقة دون اتصال.
</p>

<p>
	يوفر تطبيق الويب التقدمي تجربة حقيقية شبيهة بالتطبيقات المخصصة للنظام أثناء وضع عدم الاتصال.
</p>

<p>
	بعد أن تقوم بتحديد الميزات التي يتوقع المستخدمون استعمالها دون اتصال بالإنترنت، ستحتاج إلى جعل المحتوى الخاص بك متاحًا وقابلًا للتكيف مع حالات عدم الاتصال بالإنترنت. يمكنك استخدام IndexedDB وهو نظام تخزين NoSQL في المتصفح مصمم لتخزين البيانات واستردادها دون اتصال، ويمكنك مزامنة الخلفية background sync للسماح للمستخدمين بعمل بعض الإجراءات أثناء عدم الاتصال بالإنترنت وتأجيل الاتصالات بالخادم حتى يتوفر الإتصال مرة أخرى.
</p>

<p>
	يمكنك أيضًا استخدام منجزات الخدمة لتخزين أنواع أخرى من المحتوى مثل الصور والفيديو والصوتيات استخدامها دون اتصال بالإنترنت، بالإضافة لذلك يمكنك استخدامها في الجلسات الآمنة طويلة الأمد للحفاظ على تسجيل دخول المستخدمين.
</p>

<p>
	من منظور <a href="https://academy.hsoub.com/files/11-%D9%85%D8%AF%D8%AE%D9%84-%D8%A5%D9%84%D9%89-%D8%AA%D8%AC%D8%B1%D8%A8%D8%A9-%D8%A7%D9%84%D9%85%D8%B3%D8%AA%D8%AE%D8%AF%D9%85-user-experience-ux/" rel="">تجربة المستخدم</a>، يمكنك استخدام الواجهات أو الشاشات الهيكلية skeleton screens التي تمنح المستخدمين تصورًا حول المحتوى الذي يجري تحميله، ويمكن تخزين ذلك المحتوى وعرضه لاحقا بدون اتصال بالإنترنت.
</p>

<h3>
	2. إمكانية وصول كاملة
</h3>

<p>
	يجتاز تطبيق الويب التقدمي متطلبات سهولة الوصول <a href="https://www.w3.org/TR/WCAG20/" rel="external nofollow">WCAG 2.0</a>.
</p>

<p>
	يرغب معظم المستخدمين في مرحلة ما في الاستفادة من تطبيق الويب التقدمي الخاص بك، وإن بناء تطبيقك بطريقة تم تغطيتها بموجب متطلبات الوصول <a href="https://www.w3.org/TR/WCAG20/" rel="external nofollow">WCAG 2.0</a>. يجعل المستخدمون قادرين على التفاعل مع تطبيق الويب التقدمي الخاص بك وفهمه على نطاق واسع وجعله قادرا على تلبية احتياجاتهم المؤقتة أو الدائمة.
</p>

<p>
	بجعل تطبيق الويب التقدمي الخاص بك قابلا للوصول، فإنك تضمن أنه يمكن استخدامه من طرف الجميع.
</p>

<p>
	يجب عليك إجراء اختبارات إمكانية الوصول يدويًا. ويمكن أن تساعدك أدوات مثل Accessibility في <a href="https://academy.hsoub.com/programming/workflow/%D8%AF%D9%84%D9%8A%D9%84%D9%83-%D8%A5%D9%84%D9%89-%D8%A7%D8%B3%D8%AA%D8%B9%D9%85%D8%A7%D9%84-%D8%A7%D9%84%D8%A3%D8%AF%D8%A7%D8%A9-lighthouse-r691/" rel="">Lighthouse</a> و axe، ويمكنك أتمتة بعض اختبارات إمكانية الوصول باستعمال Accessibility Insights. من المهم أيضًا استخدام العناصر ذات الدلالة المتعارف عليها بدلاً من صياغة عناصر جديدة بنفسك، على سبيل المثال: استخدام العناصر a و button يضمن ذلك أنه عندما تحتاج إلى إنشاء وظائف أكثر تقدمًا سيكون الوصول المتوقع من خلال هذه العناصر محققا (كمثال arrows أو tabs)..
</p>

<h3>
	3. يمكن الوصول إليه من خلال البحث
</h3>

<p>
	يمكن الوصول لتطبيق الويب التقدمي PWA الخاص بك بسهولة من خلال البحث.
</p>

<p>
	إحدى أكبر مزايا الويب في القدرة على الوصول إلى المواقع والتطبيقات من خلال البحث. في الواقع يكون مصدر أكثر من نصف حركة مرور الموقع الإلكتروني من البحث الأساسي (محركات البحث).
</p>

<p>
	إن التأكد من وجود عناوين URL الأساسية للمحتوى وتكمن محركات البحث من فهرستها أمر بالغ الأهمية للمستخدمين ليتمكنوا من العثور على تطبيق الويب التقدمي الخاص بك. خاصة إن كان التقديم من جانب العميل client-side rendering.
</p>

<p>
	للقيام بذلك عليك بداية التأكد من أن جميع عناوين URL الخاصة بك تمتلك وصفا وتعريفا فريدا. يمكنك بعدها استخدام <a href="https://academy.hsoub.com/marketing/search-engine-optimisation/%D8%A3%D8%AF%D8%A7%D8%A9-%D9%85%D8%B4%D8%B1%D9%81%D9%8A-%D8%A7%D9%84%D9%85%D9%88%D8%A7%D9%82%D8%B9-%D9%85%D9%86-%D8%AC%D9%88%D8%AC%D9%84-google-search-console-r499/" rel="">Google Search Console</a> ومراجعات تحسين محرك البحث من <a href="https://academy.hsoub.com/programming/workflow/%D8%AF%D9%84%D9%8A%D9%84%D9%83-%D8%A5%D9%84%D9%89-%D8%A7%D8%B3%D8%AA%D8%B9%D9%85%D8%A7%D9%84-%D8%A7%D9%84%D8%A3%D8%AF%D8%A7%D8%A9-lighthouse-r691/" rel="">Lighthouse</a> لتصحيح وإصلاح مشكلات قابلية الاكتشاف لتطبيق الويب التقدمي الخاص بك. ويمكنك استخدام أدوات مشرفي المواقع الخاصة بمحركي بحث Bing أو Yandex، والنظر في تضمين البيانات المنظمة <a href="https://wiki.hsoub.com/Algorithms/data_structures" rel="external">structured data</a> عبر مخططات من Schema.org في تطبيق الويب التقدمي الخاص بك.
</p>

<h3>
	4. يعمل مع أي جهاز إدخال
</h3>

<p>
	يمكن استخدام <a href="https://academy.hsoub.com/programming/general/%D9%85%D8%AF%D8%AE%D9%84-%D8%A5%D9%84%D9%89-%D8%AA%D8%B7%D8%A8%D9%8A%D9%82%D8%A7%D8%AA-%D8%A7%D9%84%D9%88%D9%8A%D8%A8-%D8%A7%D9%84%D8%AA%D9%82%D8%AF%D9%85%D9%8A%D8%A9-pwa-r832/" rel="">تطبيق الويب التقدمي PWA</a> مع الفأرة أو لوحة المفاتيح أو القلم أو لوحة اللمس.
</p>

<p>
	تقدم الأجهزة إمكانيات مختلفة للاستخدام، ويجب أن يكون المستخدمون قادرين على التغيير بينها وبنفس القدر من سلاسة أثناء استعمالهم للتطبيق الخاص بك، يجب ألا تعتمد أساليب الإدخال على حجم الشاشة، مما يعني أن إطارات العرض الكبيرة تحتاج إلى دعم اللمس وأن إطارات العرض الصغيرة تحتاج إلى دعم لوحات المفاتيح والماوس، تأكد قدر ما تستطيع من أن التطبيق الخاص بك وجميع ميزاته تدعم استخدام أي طريقة إدخال قد يختارها المستخدم، يجب عليك أيضًا عند الحاجة تحسين تطبيقك للسماح بعناصر تحكم خاصة بالإدخال (مثل عنصر السحب-للتحديث pull-to-refresh).
</p>

<p>
	توفر واجهة برمجة تطبيقات Pointer Events <abbr title="Application Programming Interface | واجهة برمجية">API</abbr> واجهة موحدة للتعامل مع مختلف الإدخالات، وهي مفيدة بشكل خاص لإضافة دعم القلم واللمس ولوحة المفاتيح، تأكد من أنك تستخدم العناصر الدلالية الصحيحة (الروابط anchors، الأزرار buttons، متحكمات النماذج form controls وما إلى ذلك) ولا تقم بنائها باستخدام كود أو عناصر HTML لا تمتلك دلالة معروف لدي المستخدم (وهذا يحسن إمكانية الوصول).
</p>

<p>
	تأكد عند تضمين الحدث "عند مرور الفأرة" من إمكانية تفعيلها عند النقر أيضًا.
</p>

<h3>
	5. طلب الأذونات
</h3>

<p>
	عند طلب الإذن لاستخدام واجهات برمجة تطبيقات، استعمل السياق واطلب الإذن الذي تريده.
</p>

<p>
	تم تصميم الواجهات البرمجية التي تتطلب أذونات، مثل الإشعارات والموقع الجغرافي وبيانات الاعتماد، لتكون مزعجة للمستخدم عن قصد، لأنه غالبًا ما تكون هذه الإشعارات مرتبطة بوظائف غير مسموح تنفيذها إلا بموافقة المستخدم.
</p>

<p>
	يؤدي تفعيل رسالة طلب الأذونات من المستخدم دون سياق مناسب إلى تقليل احتمالية موافقة المستخدمين على تلك الأذونات وزيادة احتمالية عدم ثقتهم بالتطبيق مستقبلا. في حال كنت تحتاج الإذن، يجب عليك ان تشغل طلب الإذن فقط بعد تقديم سبب منطقي في سياق مناسب للمستخدم.
</p>

<h3>
	6. يوفر كود نظيف بأفضل الممارسات
</h3>

<p>
	يمكن استخدام تطبيق الويب التقدمي PWA مع الفأرة أو لوحة المفاتيح أو القلم أو لوحة اللمس.
</p>

<p>
	هناك الكثير من الأمور التي عليك أخذها في الاعتبار عند بناء تطبيق ويب حديث، وإبقاء تطبيقك محدثا والكود الخاص به نضيفا يجعل تقديم ميزات جديدة تلبي الأهداف الموضحة في قائمة التحقق هذه أمرا أسهل.
</p>

<p>
	هناك عدة أمور عليك التحقق منها ليكون الكود الخاص بتطبيقك نظيفا، نذكر منها: تجنب استخدام المكتبات التي تملك ثغرات الأمنية المعروفة، التأكد من أنك لا تستخدم واجهات برمجية موقوفة Deprecated APIs، إزالة أنماط الويب المضادة من الكود الخاص بك (مثل <code>document.write()‎</code> أو امتلاك القيمة non-passive لحدث التمرير)، وأيضا التأكد من أن تطبيق الويب التقدمي الخاص بك يستمر في العمل حتى إذا فشل تحميل التحليلات أو مكتبات الطرف الثالث الأخرى.
</p>

<p>
	ترجمة -وبتصرف- للمقال <a href="https://web.dev/pwa-checklist/" rel="external nofollow">What makes a good Progressive Web App?‎</a> لصاحبيه Sam Richard وPete LePage.
</p>

<h2>
	اقرأ أيضًا
</h2>

<ul>
<li>
		<a href="https://academy.hsoub.com/programming/general/%D9%85%D8%A7-%D9%87%D9%8A-%D8%AA%D8%B7%D8%A8%D9%8A%D9%82%D8%A7%D8%AA-%D8%A7%D9%84%D9%88%D9%8A%D8%A8-%D8%A7%D9%84%D8%AA%D9%82%D8%AF%D9%85%D9%8A%D8%A9-pwa%D8%9F-r1480/" rel="">ما هي تطبيقات الويب التقدمية PWA؟</a>
	</li>
	<li>
		<a href="https://academy.hsoub.com/programming/javascript/%D8%AA%D9%88%D9%81%D9%8A%D8%B1-%D8%AA%D8%AC%D8%B1%D8%A8%D8%A9-%D8%AA%D8%AB%D8%A8%D9%8A%D8%AA-%D9%85%D8%AE%D8%B5%D8%B5%D8%A9-%D8%AF%D8%A7%D8%AE%D9%84-%D8%AA%D8%B7%D8%A8%D9%8A%D9%82-%D8%A7%D9%84%D9%88%D9%8A%D8%A8-%D8%A7%D9%84%D8%AA%D9%82%D8%AF%D9%85%D9%8A-pwa-r1445/" rel="">توفير تجربة تثبيت مخصصة داخل تطبيق الويب التقدمي PWA</a>
	</li>
	<li>
		<a href="https://academy.hsoub.com/programming/general/%D8%AA%D8%B4%D8%BA%D9%8A%D9%84-%D8%AA%D8%B7%D8%A8%D9%8A%D9%82%D8%A7%D8%AA-%D8%A7%D9%84%D9%88%D9%8A%D8%A8-%D8%A7%D9%84%D8%AA%D9%82%D8%AF%D9%85%D9%8A%D8%A9-pwa-%D9%81%D9%8A-%D9%88%D8%B6%D8%B9-%D8%A7%D9%86%D9%82%D8%B7%D8%A7%D8%B9-%D8%A7%D9%84%D8%A7%D8%AA%D8%B5%D8%A7%D9%84-r1386/" rel="">تشغيل تطبيقات الويب التقدمية PWA في وضع انقطاع الاتصال</a>
	</li>
	<li>
		<a href="https://academy.hsoub.com/programming/general/%D8%AC%D8%AF%D9%88%D9%89-%D8%A7%D9%84%D8%A7%D8%B9%D8%AA%D9%85%D8%A7%D8%AF-%D8%B9%D9%84%D9%89-%D8%AA%D8%B7%D8%A8%D9%8A%D9%82%D8%A7%D8%AA-%D8%A7%D9%84%D9%88%D9%8A%D8%A8-%D8%A7%D9%84%D8%AA%D9%82%D8%AF%D9%85%D9%8A%D8%A9-pwa-%D8%B9%D9%88%D8%B6-%D8%AA%D8%B7%D8%A8%D9%8A%D9%82%D8%A7%D8%AA-%D8%A7%D9%84%D8%AC%D9%88%D8%A7%D9%84%D8%A7%D8%AA-%D8%A7%D9%84%D8%A3%D8%B5%D9%8A%D9%84%D8%A9-r1488/" rel="">جدوى الاعتماد على تطبيقات الويب التقدمية PWA عوض تطبيقات الجوالات الأصيلة</a>
	</li>
</ul>
]]></description><guid isPermaLink="false">1489</guid><pubDate>Sat, 19 Feb 2022 09:54:26 +0000</pubDate></item><item><title>&#x62C;&#x62F;&#x648;&#x649; &#x627;&#x644;&#x627;&#x639;&#x62A;&#x645;&#x627;&#x62F; &#x639;&#x644;&#x649; &#x62A;&#x637;&#x628;&#x64A;&#x642;&#x627;&#x62A; &#x627;&#x644;&#x648;&#x64A;&#x628; &#x627;&#x644;&#x62A;&#x642;&#x62F;&#x645;&#x64A;&#x629; PWA &#x639;&#x648;&#x636; &#x62A;&#x637;&#x628;&#x64A;&#x642;&#x627;&#x62A; &#x627;&#x644;&#x62C;&#x648;&#x627;&#x644;&#x627;&#x62A; &#x627;&#x644;&#x623;&#x635;&#x64A;&#x644;&#x629;</title><link>https://academy.hsoub.com/programming/general/%D8%AC%D8%AF%D9%88%D9%89-%D8%A7%D9%84%D8%A7%D8%B9%D8%AA%D9%85%D8%A7%D8%AF-%D8%B9%D9%84%D9%89-%D8%AA%D8%B7%D8%A8%D9%8A%D9%82%D8%A7%D8%AA-%D8%A7%D9%84%D9%88%D9%8A%D8%A8-%D8%A7%D9%84%D8%AA%D9%82%D8%AF%D9%85%D9%8A%D8%A9-pwa-%D8%B9%D9%88%D8%B6-%D8%AA%D8%B7%D8%A8%D9%8A%D9%82%D8%A7%D8%AA-%D8%A7%D9%84%D8%AC%D9%88%D8%A7%D9%84%D8%A7%D8%AA-%D8%A7%D9%84%D8%A3%D8%B5%D9%8A%D9%84%D8%A9-r1488/</link><description><![CDATA[
<p><img src="https://academy.hsoub.com/uploads/monthly_2022_02/6210b69013c64_-------PWA-----.png.26bcca256f9d37fa714ffde81f734094.png" /></p>

<p>
	<a href="https://academy.hsoub.com/programming/general/%D9%85%D8%AF%D8%AE%D9%84-%D8%A5%D9%84%D9%89-%D8%AA%D8%B7%D8%A8%D9%8A%D9%82%D8%A7%D8%AA-%D8%A7%D9%84%D9%88%D9%8A%D8%A8-%D8%A7%D9%84%D8%AA%D9%82%D8%AF%D9%85%D9%8A%D8%A9-pwa-r832/" rel="">تطبيقات الويب التقدمية</a> أو PWA تكون على سلم أولويات العديد من الشركات بغرض تحديث مواقعها ودعم هذه التقنية لتحقيق توقعات المستخدمين، وكحال كل التقنيات والمفاهيم الجديدة يطرح أصحاب الأعمال أسئلة مهمة: ماذا يريد عملاؤنا؟ وإلى أي حد سيساهم هذا في نمو عملنا؟ وما الذي هو ممكن تقنيا باستعمال تطبيقات الويب التقدمية PWA أم نحتاج إلى تطبيق جوال أصلي خاص بمنصات الجوال؟
</p>

<p style="text-align: center;">
	<a class="ipsAttachLink ipsAttachLink_image" data-fileid="92296" href="https://academy.hsoub.com/uploads/monthly_2022_02/2.png.26c16dc9ddaaca7b7e1becfa720d3c62.png" rel=""><img alt="2.png" class="ipsImage ipsImage_thumbnailed" data-fileid="92296" data-unique="8cte5hpxf" src="https://academy.hsoub.com/uploads/monthly_2022_02/2.thumb.png.07fc77263b8c5e411081f257a3e43080.png" style="width: 700px; height: auto;"></a>
</p>

<p>
	غالبا ما يشارك العديد من المسؤولين أصحاب المصطلحة في تشكيل الإستراتيجية الرقمية، كمدير الإنتاج و<a href="https://academy.hsoub.com/marketing/experiences/11-%D8%AE%D8%A8%D9%8A%D8%B1-%D8%AA%D8%B3%D9%88%D9%8A%D9%82-%D9%8A%D8%B1%D9%88%D9%88%D9%86-%D9%82%D8%B5%D8%B5-%D9%81%D8%B4%D9%84%D9%87%D9%85-%D9%88%D8%A7%D9%84%D8%AF%D8%B1%D9%88%D8%B3-%D8%A7%D9%84%D9%85%D8%B3%D8%AA%D9%81%D8%A7%D8%AF%D8%A9-%D9%85%D9%86%D9%87%D8%A7-r403/" rel="">كُبراء مشرفي التسويق CMO</a> وهم المشرفون الرئيسيون على تأثير الميزات على العمل، ويقوم الرئيس التنفيذي للتقنية CTO بتقييم جدوى وموثوقية التقنية، ويتحقق <a href="https://academy.hsoub.com/design/user-experience/%D9%81%D9%87%D9%85-%D9%88%D8%AF%D8%B1%D8%A7%D8%B3%D8%A9-%D8%A7%D9%84%D9%85%D8%B3%D8%AA%D8%AE%D8%AF%D9%85%D9%8A%D9%86-%D9%81%D9%8A-%D9%85%D8%AC%D8%A7%D9%84-%D8%AA%D8%AC%D8%B1%D8%A8%D8%A9-%D8%A7%D9%84%D9%85%D8%B3%D8%AA%D8%AE%D8%AF%D9%85-r235/" rel="">محللو تجرِبة المستخدم</a> UX researchers من أن المِيزة تحقق تطلعات العملاء.
</p>

<p>
	تسعى هذه المقالة إلى الإجابة عن الأسئلة الثلاث السابقة وستبدأ بمعرفة احتياجات العميل ثم ترجمتها إلى ميزات في تطبيق الويب المتقدم PWA ثم التركيز على العمل، ثم معرفة تأثير كل مِيزة على العمل.
</p>

<h2>
	تطبيقات الويب التقدمية تحقق تطلعات العملاء
</h2>

<p>
	القاعدة التي تتبعها جوجل عند تصميم أي منتج هي "<a href="https://www.google.com/about/philosophy.html" rel="external nofollow">ركز على العميل وكل شيء آخر سيتبع ذلك</a>"، أي فكر في المستخدم أولا: ما الذي يحتاجه العملاء؟ وكيف ستقدمه تطبيقات الويب التقدمية لهم؟
</p>

<p style="text-align: center;">
	<a class="ipsAttachLink ipsAttachLink_image" data-fileid="92297" href="https://academy.hsoub.com/uploads/monthly_2022_02/3.png.9ba71339540b0d7204526f91eb128b42.png" rel=""><img alt="3.png" class="ipsImage ipsImage_thumbnailed" data-fileid="92297" data-unique="kfxkmmgjr" src="https://academy.hsoub.com/uploads/monthly_2022_02/3.thumb.png.6480ba38638f6992550c5f6ca99e0413.png" style="width: 650px; height: auto;"></a>
</p>

<p>
	عند إجراء بحوث على المستخدم، نجد أنماطا مثيرة للإهتمام مع المصدر المستقى منه:
</p>

<ul>
<li>
		يكره المستخدمون التأخير والانتظار على الهاتف: يمكن مقارنة مستوى القلق في هذه الحالة <a href="https://blog.hubspot.com/marketing/mobile-website-load-faster" rel="external nofollow">بمشاهدة فلم رعب</a>.
	</li>
	<li>
		يستخدم 50% من المستخدمين موقع الشركة على المتصفح، <a href="https://www.thinkwithgoogle.com/data/smartphone-user-mobile-shopping-preferences/" rel="external nofollow">لأنهم لا يحبون تنزيل التطبيقات</a>.
	</li>
	<li>
		أحد أكثر الأسباب لحذف التطبيقات هو <a href="https://www.thinkwithgoogle.com/data/why-users-uninstall-travel-apps/" rel="external nofollow">نفاذ التخزين</a> (في حين تحجز تطبيقات الويب التقدمية أقل من 1 ميغابايت).
	</li>
	<li>
		مستخدمو الهواتف الذكية لديهم قابلية أكبر للشراء من المواقع التي تقدم <a href="https://www.thinkwithgoogle.com/data/smartphone-mobile-app-and-site-purchase-data/" rel="external nofollow">توصيات ذات صلة </a> ويقول 85% من المستخدمين أن <a href="https://www.thinkwithgoogle.com/data/smartphone-user-notification-preferences/" rel="external nofollow">إشعارات الهاتف مفيدة</a>.
	</li>
</ul>
<p>
	استنادا إلى هذه البيانات نجد أن المستخدم يفضل التجربة الأسرع القابلة للتثبيت الموثوقة والجذابة!
</p>

<h2>
	تستفيد تطبيقات الويب التقدمية من إمكانيات الويب الحديثة
</h2>

<p>
	تقدم تطبيقات الويب التقدمية أفضل الممارسات، وواجهات ويب برمجية حديثة Web APIs، تهدف إلى تلبية احتياجات عملائك من خلال جعل موقعك سريعا، وقابلا للتثبيت، وموثوقًا، وجذابا. كمثال، استعمال <a href="https://academy.hsoub.com/programming/general/%D9%85%D9%81%D9%87%D9%88%D9%85-service-worker-%D9%88%D8%AA%D8%A3%D8%AB%D9%8A%D8%B1%D9%87-%D9%81%D9%8A-%D8%A3%D8%AF%D8%A7%D8%A1-%D9%88%D8%A8%D9%86%D9%8A%D8%A9-%D9%85%D9%88%D8%A7%D9%82%D8%B9-%D9%88%D8%AA%D8%B7%D8%A8%D9%8A%D9%82%D8%A7%D8%AA-%D8%A7%D9%84%D9%88%D9%8A%D8%A8-r833/" rel="">منجزات الخدمة service workers</a> للتخزين المؤقت والقيام بالتحميل المسبق للموارد يجعل موقعك سريعًا، ويعد جعل الموقع قابلا للتثبيت وسيلة سريعة للولوج للموقع من الواجهة الرئيسية، وواجهات برمجة الويب الجديد مثل إشعارات الويب تجعل جذب المستخدمين سهلا، مع إمكانية تخصيص المحتوى.
</p>

<p style="text-align: center;">
	<a class="ipsAttachLink ipsAttachLink_image" data-fileid="92298" href="https://academy.hsoub.com/uploads/monthly_2022_02/4.png.294c1887ba79e1aecddc22cedfb64251.png" rel=""><img alt="4.png" class="ipsImage ipsImage_thumbnailed" data-fileid="92298" data-unique="pxn4jnj80" src="https://academy.hsoub.com/uploads/monthly_2022_02/4.thumb.png.96049e7beb3be9343e815cbf261dbaf7.png" style="width: 800px; height: auto;"></a>
</p>

<h2>
	فهم التأثير على العمل
</h2>

<p>
	يمكن أن يكون للنجاح عدة تعريفات اعتمادًا على نشاطك مثل:
</p>

<ul>
<li>
		قضاء المستخدمون وقتًا أطول في خدماتك
	</li>
	<li>
		<a href="https://academy.hsoub.com/apps/web/wordpress/4-%D8%B7%D8%B1%D9%82-%D8%B3%D8%B1%D9%8A%D8%B9%D8%A9-%D9%84%D8%AA%D8%AE%D9%81%D9%8A%D8%B6-%D9%85%D8%B9%D8%AF%D9%84-%D8%A7%D9%84%D8%A7%D8%B1%D8%AA%D8%AF%D8%A7%D8%AF-%D8%B9%D9%84%D9%89-%D9%85%D8%AF%D9%88%D9%86%D8%A7%D8%AA-%D9%88%D9%88%D8%B1%D8%AF%D8%A8%D8%B1%D9%8A%D8%B3-r65/" rel="">انخفاض معدل ارتداد المستخدمين</a>
	</li>
	<li>
		تحسين معدلات التحويل
	</li>
	<li>
		عودة عدد أكبر من المستخدمين
	</li>
</ul>
<p>
	تساهم أغلب مشاريع تطبيقات الويب التقدمية في رفع معدل تحويل المستخدمين للهاتف، ويمكنك معرفة المزيد عبر <a href="https://www.pwastats.com/" rel="external nofollow">PWA case studies</a>. اعتمادا على أهدافك، قد ترغب في إعطاء أولوية لبعض مميزات تطبيقات الويب التقدمية، وهو أمر جيد، إذ يمكنك اختبار الميزات وإطلاقها بشكل منفصل.
</p>

<p>
	دعنا نقيس تأثير كل مِيزة على العمل (السرعة، قابلية للتثبيت، الموثوقية، الجذب).
</p>

<h2>
	تأثير سرعة الموقع على العمل
</h2>

<p>
	أثبتت دراسة حديثة من موقع <a href="https://www2.deloitte.com/ie/en/pages/consulting/articles/milliseconds-make-millions.html" rel="external nofollow">Deloitte Digital</a> أن سرعة الموقع لها تأثير كبير على مقياس الأعمال.
</p>

<p>
	هناك الكثير مما يمكنك فعله لتحسين سرعة موقعك وبذلك تحسين تنقل المستخدمين، فإن كنت لا تدري من أين تبدأ، ترشدك الأداة <a href="https://developers.google.com/web/tools/lighthouse" rel="external nofollow">Lighthouse</a> إلى الأمور ذات الأولوية التي تتطلب إصلاح، واستمر في <a href="https://web.dev/fast/" rel="external nofollow">قراءة المزيد من مقالات حول PWA</a>.
</p>

<p>
	عندما تريد تحسين سرعة موقعك، استعمل الأدوات المناسبة وخذ قياسات متكررة، كمثال: استعمل Lighthouse لقياس الأداء وضع أهدافا واضحة، مثل الحصول على قياس جيد في مقياس أساس حيوية الويب Core Web Vitals scores، وإظافة ميزانية الأداء إلى عملية البناء الخاصة بك، بفضل القياسات المتكررة ومنهجية قيمة السرعة value of speed، يمكنك عزل تأثير تغيرات السرعة وحساب قيمة المداخيل الإضافية التي حققها عملك.
</p>

<p style="text-align: center;">
	<a class="ipsAttachLink ipsAttachLink_image" data-fileid="92299" href="https://academy.hsoub.com/uploads/monthly_2022_02/5.png.92f72b77fce535c51e5808b9dcd7f5f6.png" rel=""><img alt="5.png" class="ipsImage ipsImage_thumbnailed" data-fileid="92299" data-unique="mddldvrnz" src="https://academy.hsoub.com/uploads/monthly_2022_02/5.thumb.png.582e46049e1ef5e7cdba10fa5ffce770.png" style="width: 750px; height: auto;"></a>
</p>

<p>
	جعلت eBay <a href="https://web.dev/shopping-for-speed-on-ebay/" rel="external nofollow">السرعة هدف الشركة سنة</a> 2019، استخدموا تقنية قيمة السرعة value of speed، لتحسين المسار الحرج، والتحميل المسبق، واستنتجوا أنه لكل تحسين في سرعة التحميل قدره 100 ملي ثانية، تزيد نسبة إضافة المنتجات للسلة بمقدار 0.5%.
</p>

<p style="text-align: center;">
	<a class="ipsAttachLink ipsAttachLink_image" data-fileid="92300" href="https://academy.hsoub.com/uploads/monthly_2022_02/6.png.538726714bf6b1bb1af5c9c7353dd616.png" rel=""><img alt="6.png" class="ipsImage ipsImage_thumbnailed" data-fileid="92300" data-unique="d8odo0y7s" src="https://academy.hsoub.com/uploads/monthly_2022_02/6.thumb.png.2ac66ec241a0308da4d81e22b9095d9c.png" style="width: 600px; height: auto;"></a>
</p>

<h2>
	تأثير قابلية تثبيت الموقع على العمل
</h2>

<p>
	لم قد ترغب في أن يثبت المستخدم تطبيق الويب التقدمي الخاص بك؟ الجواب: لجعل عودة المستخدم أسهل، لأن تطبيق الاندرويد سيتطلب على الأقل 3 خطوات: إعادة التوجيه لجوجل بلاي، تنزيل التطبيق، وإعادة فتح التطبيق.
</p>

<p>
	تثبيط تطبيقات الويب التقدمية يتطلب ضغطة زر واحدة، ولا تتطلب تحويل المستخدم عن المسار الحالي.
</p>

<p style="text-align: center;">
	<a class="ipsAttachLink ipsAttachLink_image" data-fileid="92301" href="https://academy.hsoub.com/uploads/monthly_2022_02/7.png.cfcd6e65c150041f8fa82f880ebacbb4.png" rel=""><img alt="7.png" class="ipsImage ipsImage_thumbnailed" data-fileid="92301" data-unique="2tyd72mey" src="https://academy.hsoub.com/uploads/monthly_2022_02/7.thumb.png.1734b32117fc3193bc84630c2b427dfb.png" style="width: 800px; height: auto;"></a>
</p>

<p>
	بمجرد تثبيتها سيكون المستخدم قادرا على تشغيلها من الشاشة الرئيسة بضغطة زر واحدة، كما يمكنهم رؤيتها في قائمة التطبيقات المشغلة والانتقال بينها وبين التطبيقات الأخرى.
</p>

<p>
	إضافة لإمكانية الوصول إليها كأي تطبيق هاتف، لتطبيقات الويب التقدمية تجربة قائمة بذاتها مستقلة عن المتصفح، إذ تستفيد من خدمات الجهاز كالإنتقال بينها وبين التطبيقات الأخرى والإعدادات.
</p>

<p>
	من المحتمل أن تجد أن من ثبتوا تطبيق الويب المتقدم الخاص بك أكثر تفاعلا من الزوار العاديين، بزيارات متكررة أكثر، ووقت أطول في الموقع، ومعدل تحويل أعلى، تقريبا بنفس مستوى مستخدمي التطبيق الخاص الموجه للنظام.
</p>

<p>
	لجعل تطبيق الويب المتقدم الخاص بك قابل للتثبيت يجب أن يفي بالمتطلبات الأساسية، وبمجرد فعل ذلك سيكون متاحا للتثبيت.
</p>

<p style="text-align: center;">
	<a class="ipsAttachLink ipsAttachLink_image" data-fileid="92302" href="https://academy.hsoub.com/uploads/monthly_2022_02/8.png.d6b9076efd5100e7e68c8285a29d3377.png" rel=""><img alt="8.png" class="ipsImage ipsImage_thumbnailed" data-fileid="92302" data-unique="6xo8g86io" src="https://academy.hsoub.com/uploads/monthly_2022_02/8.thumb.png.37cbcbc8589115462aa3db09995d8893.png" style="width: 700px; height: auto;"></a>
</p>

<p>
	بمجرد أن تبدأ بالتسويق لتثبيت تطبيق الويب المتقدم الخاص بك، يجب عليه البدء بقياس عدد من نفذوا عملية بالتثبيت، وكيف يستخدمون تطبيقك.
</p>

<p>
	لزيادة عدد المستخدمين المثبتين لتطبيق الويب المتقدم الخاص بك، ربما تجرب عبارات تسويقية مختلفة كمثال فقط: "ثبت تطبيقنا في ثانية واحدة"، أو "أضف اختصارنا لمتابعة حالة طلبك" في أماكن مختلفة (أعلى الصفحة، في الخلاصة)، وجرب طرحها في خطوات مختلفة (في الصفحة الثانية للزائر، أو بعد الحجز).
</p>

<p>
	لمعرفة المكان الذي يغادر منه المستخدمون وكيفية تحسين الاحتفاظ بهم، يمكن قياس مسار التثبيت بأربع طرق:
</p>

<ul>
<li>
		عدد المستخدمين المؤهلين لتلقي التثبيت
	</li>
	<li>
		عدد المستخدمين الذين ضغطوا على زر التثبيت
	</li>
	<li>
		عدد المستخدمين الذين وافقوا على التثبيت ثم رفضوه
	</li>
	<li>
		عدد المستخدمين الذين ثبتوا التطبيق بنجاح
	</li>
</ul>
<p>
	بإمكانك <a href="https://academy.hsoub.com/marketing/core-concepts-of-marketing/%D8%A7%D9%84%D8%AA%D8%B3%D9%88%D9%8A%D9%82-%D8%A7%D9%84%D8%B9%D8%A7%D9%84%D9%85%D9%8A-%D8%A7%D9%84%D8%A3%D9%87%D8%AF%D8%A7%D9%81-%D9%88%D8%A7%D9%84%D8%A3%D8%B3%D8%A8%D8%A7%D8%A8-%D9%88%D8%A7%D9%84%D9%85%D8%B9%D9%88%D9%82%D8%A7%D8%AA-%D9%88%D8%A7%D9%84%D9%85%D8%B1%D8%A7%D8%AD%D9%84-r431/" rel="">التسويق لتطبيقك</a> بشكل عام أو اختباره على فئة صغيرة من المستخدمين، وبعد عدة أيام أو أسابيع يفترض أنك تملك بيانات كافية لمعرفة تأثير الحاصل على عملك. ما هو سلوك المستخدمين القادمين من الاختصار المثبت لتطبيقك، هل يتفاعلون بشكل أكبر، وهل يتحولون لموقعك أكثر؟
</p>

<p>
	لإحصاء المستخدمين الذين ثبتوا تطبيق الويب التقدمي PWA الخاص بك، استخدم الحدث <a href="https://web.dev/customize-install/#detect-install" rel="external nofollow">appinstalled</a> واستخدم <a href="https://wiki.hsoub.com/JavaScript" rel="external">الجافاسكربت</a> لمعرفة إن كان المستخدمون في وضع مستقل (يشير هذا إلى مستخدمي تطبيق PWA المثبت)، ثم استخدمها كمتغيرات أو أبعاد في تحليلاتك لسلوك الزوار.
</p>

<p style="text-align: center;">
	<a class="ipsAttachLink ipsAttachLink_image" data-fileid="92303" href="https://academy.hsoub.com/uploads/monthly_2022_02/9.png.2f947b011f4f7db5040285988beed95b.png" rel=""><img alt="9.png" class="ipsImage ipsImage_thumbnailed" data-fileid="92303" data-unique="r4btwn359" src="https://academy.hsoub.com/uploads/monthly_2022_02/9.thumb.png.428b6f291d20cd1a74503dba22a1e772.png" style="width: 750px; height: auto;"></a>
</p>

<p>
	تعد دراسة الحالة الخاصة بـ <a href="https://www.thinkwithgoogle.com/_qs/documents/8971/Weekendesk_PWA_-_EXTERNAL_CASE_STUDY.pdf" rel="external nofollow">Weekendesk</a> مثيرة للاهتمام: إذ طرحوا على المستخدمين تثبيت تطبيق PWA في الصفحة ثانية للزيارة، لزيادة معدل التثبيت إلى الحد الأقصى، ولاحظوا أن العملاء الذين يعودون عبر الاختصار على الشاشة الرئيسية كانت فرصة حجزهم لإقامة لديهم أعلى بمرتين ونصف من باقي المستخدمين.
</p>

<p style="text-align: center;">
	<a class="ipsAttachLink ipsAttachLink_image" data-fileid="92290" href="https://academy.hsoub.com/uploads/monthly_2022_02/10.png.7dd4ef0fa2e57009a9f4e26680c5c2eb.png" rel=""><img alt="10.png" class="ipsImage ipsImage_thumbnailed" data-fileid="92290" data-unique="1w8hc2wai" src="https://academy.hsoub.com/uploads/monthly_2022_02/10.thumb.png.9d88e17ba86e55a794b154ce0f9530b5.png" style="width: 750px; height: auto;"></a>
</p>

<p>
	التثبيت وسيلة ممتازة لزيادة عدد الزوار العائدين ورفع وفاء عملاءك، ويمكنك أيضا التفكير في تخصيص تجرِبة هؤلاء المستخدمين المدفوعين.
</p>

<p>
	حتى بامتلاكك لتطبيق مخصص للنظام الأساسي، يمكنك أن تجرب اقتراح <a href="https://academy.hsoub.com/programming/general/%D9%85%D8%A7-%D9%87%D9%8A-%D8%AA%D8%B7%D8%A8%D9%8A%D9%82%D8%A7%D8%AA-%D8%A7%D9%84%D9%88%D9%8A%D8%A8-%D8%A7%D9%84%D8%AA%D9%82%D8%AF%D9%85%D9%8A%D8%A9-pwa%D8%9F-r1480/" rel="">تطبيق الويب التقدمي PWA</a> الخاص بك للمستخدمين الذي رفضوا أو لم يتفاعلوا مع اقتراحك تثبيت تطبيقك الأساسي، بعض المستخدمين "الشبه متفاعلين" ربما لا يستوفون شروط تثبيت التطبيق الرئيسي، يمكن معالجة هذا الفوج من المستخدمين من خلال تثبيت تطبيق PWA لديهم إذ يعد بديلا أخف.
</p>

<p style="text-align: center;">
	<a class="ipsAttachLink ipsAttachLink_image" data-fileid="92291" href="https://academy.hsoub.com/uploads/monthly_2022_02/11.png.8f329ac82db93d38dbd440c5fb6da975.png" rel=""><img alt="11.png" class="ipsImage ipsImage_thumbnailed" data-fileid="92291" data-unique="x5j0pf6q3" src="https://academy.hsoub.com/uploads/monthly_2022_02/11.thumb.png.fde1119036be0a7ecaaeacd06bf35b5c.png" style="width: 750px; height: auto;"></a>
</p>

<h2>
	تأثير موثوقية الموقع على العمل
</h2>

<p>
	لعبة الديناصور في جوجل كروم، هي لعبة تُعرَض لما يكون الجهاز في وضع غير متصل بالإنترنت، <a href="https://www.blog.google/products/chrome/chrome-dino/" rel="external nofollow">تُعلَب أكثر من 270 مليون مرة في الشهر</a>. هذا الرقم يثبت لك قلة موثوقية الإنترنت، خاصة في البلدان التي بها بيانات جوال غير موثوقة أو باهظة الثمن مثل الهند، والبرازيل، والمكسيك، وإندونيسيا.
</p>

<p>
	عندما يشغل المستخدم تطبيقا ما قام بتثبيته من متجر التطبيقات، يتوقع فتحه، بغض النظر عما إذا كان متصلا بالإنترنت أم لا. يجب ألا تكون تطبيقات الويب التقدمية مختلفة عن ذلك، على الأقل، يجب أن تقدم صفحة تظهر أن المستخدم غير متصل بالإنترنت، وأن التطبيق غير متاح، يمكنك اتخاذ بعض الإجراءات كوظائف في التطبيق في حال كان غير متصل، كمثال، يمكنك توفير وصول إلى التذاكر أو بطاقات الصعود إلى الطائرة، وقوائم الرغبات المحفوظة، ومعلومات الاتصال، والمقالات أو الوصفات التي شاهدها المستخدم مؤخرًا، وما إلى ذلك.
</p>

<p style="text-align: center;">
	<a class="ipsAttachLink ipsAttachLink_image" data-fileid="92292" href="https://academy.hsoub.com/uploads/monthly_2022_02/12.png.7d80bddb9ff6992004b13a17a2551d22.png" rel=""><img alt="12.png" class="ipsImage ipsImage_thumbnailed" data-fileid="92292" data-unique="fps04csq9" src="https://academy.hsoub.com/uploads/monthly_2022_02/12.thumb.png.abbab733225aab7c1059978541abe2a7.png" style="width: 750px; height: auto;"></a>
</p>

<p>
	بمجرد اعتمادك تجربة موثوقية المستخدم، ربما قد ترغب في قياسها؛ كم عدد المستخدمين غير المتصلين؟ ومن أي البلدان هم؟ وهل يبقون في الموقع حين يستعيدون الاتصال؟
</p>

<p>
	يمكن قياس الاستخدام في حالة عدم الإتصال بتسجيل إشعارات الإحصاءات analytics pings عندما يتحول المستخدم بين وضع الاتصال وعدم الاتصال، هذا يعلمك عن عدد المستخدمين الذين استكملوا تصفح موقعك في أثناء عدم الاتصال بالإنترنت.
</p>

<p style="text-align: center;">
	<a class="ipsAttachLink ipsAttachLink_image" data-fileid="92293" href="https://academy.hsoub.com/uploads/monthly_2022_02/13.png.e2927f0334a3dc125341e87211d5b072.png" rel=""><img alt="13.png" class="ipsImage ipsImage_thumbnailed" data-fileid="92293" data-unique="acb3696zv" src="https://academy.hsoub.com/uploads/monthly_2022_02/13.thumb.png.085cb0e10122e788e7ec86d1ed8c2279.png" style="width: 750px; height: auto;"></a>
</p>

<p>
	توضح دراسة حالة <a href="https://www.thinkwithgoogle.com/intl/en-154/insights-inspiration/case-studies/trivago-embrace-progressive-web-apps-as-the-future-of-mobile/" rel="external nofollow">Trivago </a> كيفية تأثير ذلك على أهداف عملك: إذ بالنسبة للمستخدمين الذين انقطعت جلساتهم بسبب عدم اتصالهم بالإنترنت لفترة (تقريبًا ثلاثة بالمئة من المستخدمين)، فإن 67٪ ممن استعادوا اتصالهم بالإنترنت استمروا في تصفح الموقع.
</p>

<h2>
	تأثير جاذبية الموقع للمستخدمين على العمل
</h2>

<p>
	تسمح إشعارات الويب للمستخدمين بتلقي التحديثات في الوقت المناسب من المواقع التي يحبونها وتسمح لك بإعادة دمجهم بشكل فعال مع المحتوى المخصص ذي الصلة. رغم ذلك عليك التعامل بحذر، إذ أن مطالبة المستخدم بالاشتراك في الإشعارات في أول ولوج للتطبيق، قد ينظر له كشيء غير مرغوب، ويؤثر سلبا على تجربة المستخدمين، تأكد من اتباع أفضل الممارسات عند مطالبة المستخدمين بالاشتراك في إشعارات الويب الخاصة بك، كإبراز فائدتها أولا.
</p>

<p>
	تقنيا، تتم عملية إرسال إشعارات الويب في الخلفية بفضل <a href="https://academy.hsoub.com/programming/general/%D9%85%D9%81%D9%87%D9%88%D9%85-service-worker-%D9%88%D8%AA%D8%A3%D8%AB%D9%8A%D8%B1%D9%87-%D9%81%D9%8A-%D8%A3%D8%AF%D8%A7%D8%A1-%D9%88%D8%A8%D9%86%D9%8A%D8%A9-%D9%85%D9%88%D8%A7%D9%82%D8%B9-%D9%88%D8%AA%D8%B7%D8%A8%D9%8A%D9%82%D8%A7%D8%AA-%D8%A7%D9%84%D9%88%D9%8A%D8%A8-r833/" rel="">منجز الخدمة service worker</a> وغالبا ما يتم إرسالها باستخدام نظام مصمم لإرسال الإشعارات (Firebase مثلا)، ولهذه الميزة قيمة تجارية كبيرة لمستخدمي الأجهزة المحمولة Android وسطح المكتب، فهي تزيد الزيارات المتكررة وبذلك ترتفع المبيعات والتحويلات للموقع.
</p>

<p>
	لقياس فعالية حملات الإشعارات الخاصة بك، تحتاج إلى قياس مسار التحويل بالكامل:
</p>

<ul>
<li>
		عدد المستخدمين المؤهلين لتلقي الإشعارات
	</li>
	<li>
		عدد المستخدمين الذين ينقرون فوق رسالة طلب التسجيل في الإشعارات المخصصة
	</li>
	<li>
		عدد المستخدمين الذين يمنحون إذن تقلي الإشعارات
	</li>
	<li>
		عدد المستخدمين الذين يتلقون الإشعارات
	</li>
	<li>
		عدد المستخدمين الذين يتفاعلون مع الإشعارات
	</li>
	<li>
		التحويل والتفاعل من المستخدمين القادمين من الإشعارات
	</li>
</ul>
<p style="text-align: center;">
	<a class="ipsAttachLink ipsAttachLink_image" data-fileid="92294" href="https://academy.hsoub.com/uploads/monthly_2022_02/14.png.6c1457de46b4e8ec3bdca2e933f5347d.png" rel=""><img alt="14.png" class="ipsImage ipsImage_thumbnailed" data-fileid="92294" data-unique="ux0kxbbsi" src="https://academy.hsoub.com/uploads/monthly_2022_02/14.thumb.png.8c54bec0504b54bc5adcff9526acd967.png"></a>
</p>

<p>
	هناك الكثير من دراسات الحالة الرائعة حول إشعارات الويب، مثل <a href="https://useinsider.com/case-studies/carrefour/" rel="external nofollow">Carrefour كارفور</a> الذي ضاعف معدل التحويل بمقدار 4.5 عن طريق إعادة إشراك المستخدمين بسلة المشتريات التي تم التخلي عنها.
</p>

<h2>
	الإطلاق التدريجي: إضافة ميزة تلو الأخرى
</h2>

<p>
	<a href="https://academy.hsoub.com/programming/general/%D9%85%D8%AF%D8%AE%D9%84-%D8%A5%D9%84%D9%89-%D8%AA%D8%B7%D8%A8%D9%8A%D9%82%D8%A7%D8%AA-%D8%A7%D9%84%D9%88%D9%8A%D8%A8-%D8%A7%D9%84%D8%AA%D9%82%D8%AF%D9%85%D9%8A%D8%A9-pwa-r832/" rel="">تطبيقات الويب التقدمية</a> هي مواقع حديثة تستفيد من حجم الوصول الهائل للويب، جنبا إلى جنب مع الميزات التي يحبها مستخدمو الأجهزة المحمولة والمكتبية في تطبيقاتهم، يستفيدون من مجموعة من أفضل الممارسات التقنية وواجهات برمجة تطبيقات الويب الحديثة Web APIs، والتي يمكن تنفيذها بشكل مستقل وفقًا لأولوياتك وخصوصيات عملك.
</p>

<p style="text-align: center;">
	<a class="ipsAttachLink ipsAttachLink_image" data-fileid="92295" href="https://academy.hsoub.com/uploads/monthly_2022_02/15.png.1a87983c3f499dbae2dfea21f5f5b67d.png" rel=""><img alt="15.png" class="ipsImage ipsImage_thumbnailed" data-fileid="92295" data-unique="tph6c3biq" src="https://academy.hsoub.com/uploads/monthly_2022_02/15.thumb.png.d836eb391d8a47673d686a8653755817.png"></a>
</p>

<p>
	لجعل تحديث موقعك لدعم تطبيقات الويب التقدمية PWA سريعًا، نشجعك على أن تكون مرنًا، بحيث تقوم بإطلاق الميزات بشكل متتابع ميزة تلو اخرى، ابحث مع المستخدمين عن الميزات التي ستجلب لهم أكبر قيم، ثم ناقشها مع المطورين والمصممين لديك، وأخيرا لا تنسى مقدار الدخل الإضافي الذي جلبه تحويل موقعك لتطبيق ويب تقدمي بدقة.
</p>

<p>
	ترجمة -وبتصرف- للمقال <a href="https://web.dev/drive-business-success" rel="external nofollow">How Progressive Web Apps can drive business success?‎</a> لصاحبه Sébastien Fourault.
</p>

<h2>
	اقرأ أيضًا
</h2>

<ul>
<li>
		<a href="https://academy.hsoub.com/programming/general/%D9%85%D8%A7-%D9%87%D9%8A-%D8%AA%D8%B7%D8%A8%D9%8A%D9%82%D8%A7%D8%AA-%D8%A7%D9%84%D9%88%D9%8A%D8%A8-%D8%A7%D9%84%D8%AA%D9%82%D8%AF%D9%85%D9%8A%D8%A9-pwa%D8%9F-r1480/" rel="">ما هي تطبيقات الويب التقدمية PWA؟</a>
	</li>
	<li>
		<a href="https://academy.hsoub.com/programming/general/%D9%86%D9%85%D8%A7%D8%B0%D8%AC-%D8%A7%D9%82%D8%AA%D8%B1%D8%A7%D8%AD%D8%A7%D8%AA-%D8%AA%D8%AB%D8%A8%D9%8A%D8%AA-%D8%AA%D8%B7%D8%A8%D9%8A%D9%82%D8%A7%D8%AA-%D8%A7%D9%84%D9%88%D9%8A%D8%A8-%D8%A7%D9%84%D8%AA%D9%82%D8%AF%D9%85%D9%8A%D8%A9-pwa-r1446/" rel="">نماذج اقتراحات تثبيت تطبيقات الويب التقدمية PWA</a>
	</li>
	<li>
		<a href="https://academy.hsoub.com/programming/general/%D8%AA%D8%B4%D8%BA%D9%8A%D9%84-%D8%AA%D8%B7%D8%A8%D9%8A%D9%82%D8%A7%D8%AA-%D8%A7%D9%84%D9%88%D9%8A%D8%A8-%D8%A7%D9%84%D8%AA%D9%82%D8%AF%D9%85%D9%8A%D8%A9-pwa-%D9%81%D9%8A-%D9%88%D8%B6%D8%B9-%D8%A7%D9%86%D9%82%D8%B7%D8%A7%D8%B9-%D8%A7%D9%84%D8%A7%D8%AA%D8%B5%D8%A7%D9%84-r1386/" rel="">تشغيل تطبيقات الويب التقدمية PWA في وضع انقطاع الاتصال</a>
	</li>
</ul>
]]></description><guid isPermaLink="false">1488</guid><pubDate>Sat, 19 Feb 2022 09:52:06 +0000</pubDate></item><item><title>&#x623;&#x633;&#x627;&#x633;&#x64A;&#x627;&#x62A; &#x627;&#x644;&#x62A;&#x62D;&#x631;&#x64A;&#x643;: &#x625;&#x646;&#x634;&#x627;&#x621; &#x635;&#x641;&#x62D;&#x627;&#x62A; &#x648;&#x64A;&#x628; &#x62A;&#x641;&#x627;&#x639;&#x644;&#x64A;&#x629; &#x645;&#x62A;&#x62C;&#x627;&#x648;&#x628;&#x629;</title><link>https://academy.hsoub.com/programming/general/%D8%A3%D8%B3%D8%A7%D8%B3%D9%8A%D8%A7%D8%AA-%D8%A7%D9%84%D8%AA%D8%AD%D8%B1%D9%8A%D9%83-%D8%A5%D9%86%D8%B4%D8%A7%D8%A1-%D8%B5%D9%81%D8%AD%D8%A7%D8%AA-%D9%88%D9%8A%D8%A8-%D8%AA%D9%81%D8%A7%D8%B9%D9%84%D9%8A%D8%A9-%D9%85%D8%AA%D8%AC%D8%A7%D9%88%D8%A8%D8%A9-r1481/</link><description><![CDATA[
<p><img src="https://academy.hsoub.com/uploads/monthly_2022_02/620b34c23a83b_-------.png.6b91930934f0ea716c2f4257c9ad6a42.png" /></p>

<p>
	يلعب <a href="https://academy.hsoub.com/files/14-%D8%A7%D9%84%D8%AA%D8%AD%D8%B1%D9%8A%D9%83-%D8%B9%D8%A8%D8%B1-css/" rel="">التحريك Animation</a> دورًا كبيرًا في رفع جاذبية تطبيقات ومواقع الويب للمستخدمين الذين أصبحوا يتوقعون دومًا الحصول على واجهات استخدام تفاعلية عالية التجاوب؛ إلا أن تحريك واجهات الاستخدام ليس أمرًا مباشرًا وسهلًا، حيث يستلزم تحديد ما يجب تحريكه وما تأثير هذا التحريك على انطباع <a href="https://academy.hsoub.com/design/user-experience/%d9%85%d8%af%d8%ae%d9%84-%d8%a5%d9%84%d9%89-%d8%aa%d8%ac%d8%b1%d8%a8%d8%a9-%d8%a7%d9%84%d9%85%d8%b3%d8%aa%d8%ae%d8%af%d9%85-user-experience-r149/" rel="">وتجربة المستخدمين</a>.
</p>

<ul>
<li>
		يُستخدم التحريك لإضفاء الحياة على المشاريع.
	</li>
	<li>
		يجب أن يدعم التحريك <a href="https://academy.hsoub.com/design/user-experience/%D8%AA%D8%AC%D8%B1%D8%A8%D8%AA%D9%86%D8%A7-%D9%81%D9%8A-%D8%A5%D9%86%D8%B4%D8%A7%D8%A1-%D8%A3%D8%AF%D8%A7%D8%A9-%D8%AA%D8%B3%D8%AC%D9%84-%D8%AA%D9%81%D8%A7%D8%B9%D9%84%D8%A7%D8%AA-%D8%A7%D9%84%D9%85%D8%B3%D8%AA%D8%AE%D8%AF%D9%85-r479/" rel="">تفاعل المستخدم</a>.
	</li>
	<li>
		يجب الانتباه لتكلفة تحريك الخصائص والتي قد تختلف من خاصيةٍ لأخرى.
	</li>
</ul>
<h2>
	أساسيات التحريك
</h2>

<p>
	نعرض فيما يلي أهم القضايا الواجب الانتباه إليها عند التحريك:
</p>

<h3>
	اختيار الخصائص المناسبة للتحريك
</h3>

<p>
	يُضيف التحريك كثيرًا من المتعة للمستخدمين ويرفع من تفاعلهم مع المشروع؛ حيث يُمكن عمليًا تحريك أي شيء، مثل العرض والارتفاع والموضع والألوان والخلفيات؛ ولكن يجب الانتباه في نفس الوقت إلى تأثيرات التحريك على الأداء وانعكاساتها على هوية التطبيق، حيث يُمكن أن يؤثر التحريك المتقطع أو المُختار بصورةٍ سيئة على تردِّي تجربة الاستخدام مما يستلزم الانتباه جيدًا إلى حُسن اختيار التحريك المُناسب والفعّال.
</p>

<h3>
	استخدام التحريك لدعم التفاعل
</h3>

<p>
	يجب استخدام التحريك بصورةٍ مدروسة بهدف تعزيز تفاعل المستخدمين (وليس فقط لمجرد إمكانية التحريك)، وتجنبًا لمضايقتهم أو إعاقتهم. يُمكن مثلًا استخدام توهجٍ خفيف، أو حركة ارتدادٍ بسيطة لإعلام المستخدم بتلَقّي أفعاله، مثل النقر على أيقونة قائمة، أو السحب لفتح شريط تمرير، أو النقر على زر. يجب تجنُّب التحريك الذي يقطع أو يُعرقل نشاط المستخدم دون أي داعٍ.
</p>

<h3>
	تجنب تحريك الخصائص المكلفة
</h3>

<p>
	يُعدّ التحريك الذي يؤدي إلى تقطُّعاتٍ في الصفحة من أسوأ أنواع التحريك، والذي يُحبط المستخدمين ويُشعرهم بعدم الرضا لدرجة أنهم يتمنون بألّا يوجد أي تحريكٍ على الإطلاق.
</p>

<p>
	يُمكن أن تكون بعض الخصائص أكثر تكلفةً من غيرها عند تغييرها، كما يُمكن أن يؤدي هذا التغيير إلى ظهور التقطُّعات في الصفحة؛ حيث يُمكن مثلًا أن يتطلب تغيير ظل صندوق <code>box-shadow</code> لعنصرٍ ما عملية طلاء paint أكثر تكلفةً بكثير من تغيير لون نصه. وبالمثل، من المرجح أن يكون تغيير عرض <code>width</code> عنصر ما أكثر تكلفةً من تغيير تحويلاته <code>transform</code>.
</p>

<p>
	نعرض المزيد من الإرشادات حول أداء التحريك في الفقرة الأخيرة من هذه المقالة. يُمكن الالتزام فقط بالتحويلات transforms وتعديلات الشفافية opacity واستخدام "سوف يُعدّل" <code>will-change</code> في حال عدم الرغبة بقراءة المزيد والخوض في التفصيلات. يُمكن معرفة ماذا ينشُط تمامًا عند تحريك أي خاصية بالرجوع إلى <a href="http://csstriggers.com/" rel="external nofollow">مُشغّلات أنماط CSS</a>.
</p>

<h2>
	التحريك باستخدام أنماط CSS موازنة مع استخدام JavaScript
</h2>

<p>
	يُمكن التحريك، إما باستخدام أنماط <a href="https://wiki.hsoub.com/CSS" rel="external">CSS</a>، أو <a href="https://wiki.hsoub.com/JavaScript" rel="external">JavaScript</a>؛ حيث يعتمد قرار الاختيار بين واحدٍ منهما على الارتباطات الأخرى للمشروع وعلى أنواع التأثيرات المطلوبة.
</p>

<ul>
<li>
		يُستخدم تحريك CSS لتنفيذ الانتقالات البسيطة من النمط "لقطة واحدة one-shot"، مثل تبديل حالات عناصر الواجهة.
	</li>
	<li>
		يُستخدم تحريك JavaScript للحصول على تأثيراتٍ متقدمة، مثل الارتداد أو التوقف أو الإيقاف المؤقت أو الإرجاع أو الإبطاء.
	</li>
	<li>
		يُمكن استخدام <a href="https://academy.hsoub.com/programming/general/%D9%85%D8%AF%D8%AE%D9%84-%D8%A5%D9%84%D9%89-%D8%A7%D9%84%D9%88%D8%A7%D8%AC%D9%87%D8%A7%D8%AA-%D8%A7%D9%84%D8%A8%D8%B1%D9%85%D8%AC%D9%8A%D8%A9-api-r1314/" rel="">واجهة برمجة</a> التطبيقات للتحريك Web Animations <abbr title="Application Programming Interface | واجهة برمجية">API</abbr> أو أي إطار عمل حديث مناسب عند اختيار التحريك باستخدام JavaScript.
	</li>
</ul>
<p>
	يُمكن إنشاء معظم عمليات التحريك الأساسية باستخدام <a href="https://academy.hsoub.com/programming/css/%d8%aa%d8%b9%d8%b1%d9%91%d9%81-%d8%b9%d9%84%d9%89-%d8%a3%d8%b3%d8%a7%d8%b3%d9%8a%d8%a7%d8%aa-css-r70/" rel="">CSS</a> أو <a href="https://academy.hsoub.com/programming/javascript/%D9%85%D9%82%D8%AF%D9%85%D8%A9-%D8%A5%D9%84%D9%89-%D9%84%D8%BA%D8%A9-javascript-r664/" rel="">JavaScript</a>، لكن يختلف الجهد والزمن اللازمين لإنشاء التحريك حسب الطريقة المختارة (راجع الفقرة الأخيرة من هذه المقالة)؛ حيث يوجد لكل طريقةٍ محاسنها ومساوئها، نعرض فيما يلي الإرشادات العامة:
</p>

<ul>
<li>
		تُستخدم CSS عندما يكون لعناصر الواجهة حالات أقل محتواة ضمن نفس العنصر؛ حيث تكون الانتقالات والتحريك مثالية لجلب قائمة انتقال إلى جهةٍ معينة مثلًا أو إظهار تلميحٍ ما. يُمكن اللجوء إلى JavaScript للتحكم بالحالات إلا أن التحريك نفسه يكون في CSS.
	</li>
	<li>
		تُستخدم JavaScript عند الحاجة للتحكم الواسع في التحريك. تُعدّ واجهة برمجة التطبيقات Web Animations <abbr title="Application Programming Interface | واجهة برمجية">API</abbr> المنهج المُعتمد على المعايير القياسية والمتاح حاليًا في معظم المتصفحات الحديثة، مما يوفر كائناتٍ حقيقية مثالية للتطبيقات المعقدة الموجهة بالكائنات. تُعدّ JavaScript مفيدةً أيضًا عند الحاجة إلى إيقاف التحريك، أو إيقافه مؤقتًا، أو إبطائه، أو عكسه.
	</li>
	<li>
		يُمكن استخدام إطار التحريك للطلب <code>requestAnimationFrame</code> مباشرًة عند الحاجة لتنسيق مشهدٍ كاملٍ يدويًا. يُعدّ ذلك منهجًا متقدمًا في JavaScript، إلا أنه يكون مفيدًا عند إنشاء لعبة أو الرسم على لوحة HTML canvas.
	</li>
</ul>
<p>
	بالمقابل، في حال استخدام إطار عمل JavaScript الذي يتضمن وظائف التحريك، مثل دالة التحريك <a href="https://wiki.hsoub.com/jQuery/animate" rel="external"><code>‎.animate()</code></a> في jQuery، فقد يكون من الأنسب الالتزام بذلك في التحريك عمومًا.
</p>

<h3>
	التحريك باستخدام CSS
</h3>

<p>
	يُعدّ <a href="https://academy.hsoub.com/programming/css/%D9%85%D8%AF%D8%AE%D9%84-%D8%A5%D9%84%D9%89-%D8%A7%D9%84%D8%AD%D8%B1%D9%83%D8%A7%D8%AA-%D9%85%D9%81%D9%87%D9%88%D9%85-%D8%A7%D9%84%D8%AD%D8%B1%D9%83%D8%A9-r677/" rel="">التحريك باستخدام CSS</a> أبسط طرق تحريك شيءٍ ما على الشاشة، حيث يوصف هذا الأسلوب بأنه تصريحي لأنه يُحدّد ما المطلوب حدوثه.
</p>

<p>
	يُبين المثال التالي تحريك صندوقٍ باستخدام CSS بمقدار <code>100px</code> في كلا المحورين X و Y، حيث ضُبط زمن الانتقال ليأخذ 500 ميلي ثانية (نصف ثانية). تتغير القيمة <code>transform</code> عند إضافة الصف <code>move</code> ويبدأ الانتقال.
</p>

<pre class="ipsCode prettyprint lang-css prettyprinted" id="ips_uid_9522_14" style="">
<span class="pun">.</span><span class="pln">box </span><span class="pun">{</span><span class="pln">
  transform</span><span class="pun">:</span><span class="pln"> translate</span><span class="pun">(</span><span class="lit">0</span><span class="pun">,</span><span class="pln"> </span><span class="lit">0</span><span class="pun">);</span><span class="pln">
  transition</span><span class="pun">:</span><span class="pln"> transform </span><span class="lit">500ms</span><span class="pun">;</span><span class="pln">
</span><span class="pun">}</span><span class="pln">

</span><span class="pun">.</span><span class="pln">box</span><span class="pun">.</span><span class="pln">move </span><span class="pun">{</span><span class="pln">
  transform</span><span class="pun">:</span><span class="pln"> translate</span><span class="pun">(</span><span class="lit">100px</span><span class="pun">,</span><span class="pln"> </span><span class="lit">100px</span><span class="pun">);</span><span class="pln">
</span><span class="pun">}</span></pre>

<p>
	يُمكن <a href="https://googlesamples.github.io/web-fundamentals/fundamentals/design-and-ux/animations/box-move-simple.html" rel="external nofollow">تجريب المثال</a>.
</p>

<p>
	يوجد إضافًة إلى مدة الانتقال خياراتٍ للتخفيف easing، والتي تُساهم في جعل التحريك يبدو طبيعيًا. يُمكن الرجوع إلى أساسيات التخفيف لمزيدٍ من التفاصيل.
</p>

<p>
	في حال إنشاء صفوفٍ مستقلة في CSS لإدارة التحريك كما هو الحال في المثال أعلاه، يُمكن استخدام JavaScript لتبديل حالة التحريك نعم/لا on/off.
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_9522_18" style="">
<span class="pln">box</span><span class="pun">.</span><span class="pln">classList</span><span class="pun">.</span><span class="pln">add</span><span class="pun">(</span><span class="str">'move'</span><span class="pun">);</span></pre>

<p>
	يوفِّر ذلك توازنًا جيدًا للتطبيقات؛ إذ يُمكن للمطور التركيز على إدارة الحالة باستخدام JavaScript، وتعيين الصفوف المناسبة للعناصر المستهدفة ببساطة، وترك المتصفح يتعامل مع التحريك. يُمكن في حال اعتماد هذا المنهج الاستماع إلى أحداث نهاية الانتقال <code>transitionend</code> للعنصر، وذلك في حال قبول التخلي عن دعم الإصدارات الأقدم من Internet Explorer، حيث كان الإصدار 10 هو الإصدار الأول لدعم هذه الأحداث. دعمت جميع المتصفحات الأخرى هذه الأحداث منذ فترة.
</p>

<p>
	تكون شيفرة JavaScript المطلوبة للاستماع إلى حدث انتهاء الانتقال كما يلي:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_9522_20" style="">
<span class="kwd">var</span><span class="pln"> box </span><span class="pun">=</span><span class="pln"> document</span><span class="pun">.</span><span class="pln">querySelector</span><span class="pun">(</span><span class="str">'.box'</span><span class="pun">);</span><span class="pln">
box</span><span class="pun">.</span><span class="pln">addEventListener</span><span class="pun">(</span><span class="str">'transitionend'</span><span class="pun">,</span><span class="pln"> onTransitionEnd</span><span class="pun">,</span><span class="pln"> </span><span class="kwd">false</span><span class="pun">);</span><span class="pln">

</span><span class="kwd">function</span><span class="pln"> onTransitionEnd</span><span class="pun">()</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
  </span><span class="com">//معالجة إنهاء الانتقال</span><span class="pln">
</span><span class="pun">}</span></pre>

<p>
	يُمكن استخدام <a href="https://academy.hsoub.com/tags/%D8%A7%D9%84%D8%AA%D8%AD%D8%B1%D9%8A%D9%83%20%D9%81%D9%8A%20css/" rel="">التحريك في CSS</a> إضافًة إلى استخدام الانتقالات للحصول على مزيدٍ من التحكم في الإطارات الرئيسية للتحريك الفردي والمُدّد الزمنية والتكرارات.
</p>

<p>
	<strong>ملاحظة</strong>: يُعدّ الإطار الرئيسي keyframe مصطلحًا قديمًا من مصطلحات <a href="https://academy.hsoub.com/design/illustration/%D9%85%D9%82%D8%AF%D9%85%D8%A9-%D8%A5%D9%84%D9%89-%D8%AA%D8%B5%D9%85%D9%8A%D9%85-%D8%A7%D9%84%D8%B1%D8%B3%D9%88%D9%85%D9%8A%D8%A7%D8%AA-%D8%A7%D9%84%D8%AA%D8%B5%D9%85%D9%8A%D9%85-%D8%A7%D9%84%D8%AC%D8%B1%D8%A7%D9%81%D9%8A%D9%83%D9%8A-r536/" rel="">الرسوم</a> المتحركة المرسومة يدويًا. يُنشئ رسامو الرسوم المتحركة إطاراتٍ مُحدّدةً لجزءٍ من العمل، تُدعى الإطارات الرئيسية، والتي من شأنها أن تلتقط أشياءً مثل الجزء الأكثر تطرفًا في حركةٍ ما، ثم يشرعون في رسم جميع الإطارات الفردية بين الإطارات الرئيسية. يسلك التحريك في CSS سلوكًا مشابهًا؛ حيث يُعلَم المتصفح ببعض قيم خصائص CSS في نقاط مُحدّدة ويُطلب منه ملء القيم الناقصة.
</p>

<p>
	يُمكن مثلًا تحريك صندوق المثال السابق بنفس الطريقة مع انتقالات وبتكرارٍ لا نهائي، ولكن بدون أي تفاعلٍ للمستخدم مثل النقر. كما يُمكن تغيير عدة خصائص في نفس الوقت:
</p>

<pre class="ipsCode prettyprint lang-css prettyprinted" id="ips_uid_9522_24" style="">
<span class="pun">.</span><span class="pln">box </span><span class="pun">{</span><span class="pln">
  </span><span class="com">/* اختيار التحريك */</span><span class="pln">
  animation</span><span class="pun">-</span><span class="pln">name</span><span class="pun">:</span><span class="pln"> movingBox</span><span class="pun">;</span><span class="pln">

  </span><span class="com">/* مدّة التحريك */</span><span class="pln">
  animation</span><span class="pun">-</span><span class="pln">duration</span><span class="pun">:</span><span class="pln"> </span><span class="lit">1300ms</span><span class="pun">;</span><span class="pln">

  </span><span class="com">/* عدد مرات التحريك */</span><span class="pln">
  animation</span><span class="pun">-</span><span class="pln">iteration</span><span class="pun">-</span><span class="pln">count</span><span class="pun">:</span><span class="pln"> infinite</span><span class="pun">;</span><span class="pln">

  </span><span class="com">/* تبديل اتجاه التحريك عند كل دورة فردية */</span><span class="pln">
  animation</span><span class="pun">-</span><span class="pln">direction</span><span class="pun">:</span><span class="pln"> alternate</span><span class="pun">;</span><span class="pln">
</span><span class="pun">}</span><span class="pln">

</span><span class="lit">@keyframes</span><span class="pln"> movingBox </span><span class="pun">{</span><span class="pln">
  </span><span class="lit">0</span><span class="pun">%</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
    transform</span><span class="pun">:</span><span class="pln"> translate</span><span class="pun">(</span><span class="lit">0</span><span class="pun">,</span><span class="pln"> </span><span class="lit">0</span><span class="pun">);</span><span class="pln">
    opacity</span><span class="pun">:</span><span class="pln"> </span><span class="lit">0.3</span><span class="pun">;</span><span class="pln">
  </span><span class="pun">}</span><span class="pln">

  </span><span class="lit">25</span><span class="pun">%</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
    opacity</span><span class="pun">:</span><span class="pln"> </span><span class="lit">0.9</span><span class="pun">;</span><span class="pln">
  </span><span class="pun">}</span><span class="pln">

  </span><span class="lit">50</span><span class="pun">%</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
    transform</span><span class="pun">:</span><span class="pln"> translate</span><span class="pun">(</span><span class="lit">100px</span><span class="pun">,</span><span class="pln"> </span><span class="lit">100px</span><span class="pun">);</span><span class="pln">
    opacity</span><span class="pun">:</span><span class="pln"> </span><span class="lit">0.2</span><span class="pun">;</span><span class="pln">
  </span><span class="pun">}</span><span class="pln">

  </span><span class="lit">100</span><span class="pun">%</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
    transform</span><span class="pun">:</span><span class="pln"> translate</span><span class="pun">(</span><span class="lit">30px</span><span class="pun">,</span><span class="pln"> </span><span class="lit">30px</span><span class="pun">);</span><span class="pln">
    opacity</span><span class="pun">:</span><span class="pln"> </span><span class="lit">0.8</span><span class="pun">;</span><span class="pln">
  </span><span class="pun">}</span><span class="pln">
</span><span class="pun">}</span></pre>

<p>
	يُمكن <a href="https://googlesamples.github.io/web-fundamentals/fundamentals/design-and-ux/animations/box-move-keyframes.html" rel="external nofollow">تجريب المثال</a>.
</p>

<p>
	يُمكن تعريف التحريك نفسه بصورةٍ مستقلة عن العنصر الهدف، ويُمكن استخدام خاصية اسم التحريك <code>animation-name</code> لاختيار التحريك المطلوب.
</p>

<p>
	يجب إضافة بادئات البائع vendor prefixes إذا أردنا أن يعمل تحريك CSS على المتصفحات القديمة. ويُمكن للعديد من الأدوات أن تُساعد في إنشاء إصدارات CSS مع البادئة المطلوبة، مما يسمح للمطوّر بكتابة الإصدار دون البادئات في ملفات المصدر الخاصة به.
</p>

<h3>
	التحريك باستخدام JavaScript وواجهة برمجة التطبيقات Web Animations <abbr title="Application Programming Interface | واجهة برمجية">API</abbr>
</h3>

<p>
	يُعدّ إنشاء التحريك باستخدام JavaScript أكثر تعقيدًا موازنًة مع كتابة الانتقالات أو التحريك في CSS، إلا أنه يوفر قوةً أكبر للمطورين. يُمكن استخدام واجهة برمجة التطبيقات <a href="https://w3c.github.io/web-animations/" rel="external nofollow">Web Animations <abbr title="Application Programming Interface | واجهة برمجية">API</abbr></a> إما لتحريك خصائص CSS معينة، أو لإنشاء كائناتٍ ذات تأثيرات مركبة.
</p>

<p>
	يكون استخدام JavaScript للتحريك حتميًا مع كتابة التعليمات سطريًا inline ضمن الشيفرة، كما يُمكن تغليفها داخل كائناتٍ أخرى. تُبيّن الشيفرة التالية كيفية إنشاء نفس تحريك CSS المُوضح في المثال السابق:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_9522_26" style="">
<span class="kwd">var</span><span class="pln"> target </span><span class="pun">=</span><span class="pln"> document</span><span class="pun">.</span><span class="pln">querySelector</span><span class="pun">(</span><span class="str">'.box'</span><span class="pun">);</span><span class="pln">
</span><span class="kwd">var</span><span class="pln"> player </span><span class="pun">=</span><span class="pln"> target</span><span class="pun">.</span><span class="pln">animate</span><span class="pun">([</span><span class="pln">
  </span><span class="pun">{</span><span class="pln">transform</span><span class="pun">:</span><span class="pln"> </span><span class="str">'translate(0)'</span><span class="pun">},</span><span class="pln">
  </span><span class="pun">{</span><span class="pln">transform</span><span class="pun">:</span><span class="pln"> </span><span class="str">'translate(100px, 100px)'</span><span class="pun">}</span><span class="pln">
</span><span class="pun">],</span><span class="pln"> </span><span class="lit">500</span><span class="pun">);</span><span class="pln">
player</span><span class="pun">.</span><span class="pln">addEventListener</span><span class="pun">(</span><span class="str">'finish'</span><span class="pun">,</span><span class="pln"> </span><span class="kwd">function</span><span class="pun">()</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
  target</span><span class="pun">.</span><span class="pln">style</span><span class="pun">.</span><span class="pln">transform </span><span class="pun">=</span><span class="pln"> </span><span class="str">'translate(100px, 100px)'</span><span class="pun">;</span><span class="pln">
</span><span class="pun">});</span></pre>

<p>
	تنحصر المهمة الأساسية للتحريك باستخدام Web Animation في تعديل كيفية تقديم وعرض العنصر للمستخدم؛ أما في حال الرغبة ببقاء العنصر في المكان الذي انتقل إليه، فيجب تعديل أنماطه عند انتهاء التحريك كما في المثال السابق.
</p>

<p>
	تُعدّ واجهة برمجة التطبيقات Web Animations <abbr title="Application Programming Interface | واجهة برمجية">API</abbr> معيارًا جديدًا نسبيًا من W3C، وهو مدعومٌ بصورةٍ أساسية في معظم المتصفحات الحديثة؛ أما بالنسبة للمتصفحات الحديثة غير الداعمة، فيُمكن استخدام <a href="https://github.com/web-animations/web-animations-js" rel="external nofollow">المشروع</a> من النوع "نقص الدعم" polyfill المُتاح على <a href="https://academy.hsoub.com/programming/workflow/git/%d9%83%d9%8a%d9%81-%d8%aa%d8%b3%d8%a7%d9%87%d9%85-%d9%81%d9%8a-%d9%85%d8%b4%d8%a7%d8%b1%d9%8a%d8%b9-%d9%85%d9%81%d8%aa%d9%88%d8%ad%d8%a9-%d8%a7%d9%84%d9%85%d8%b5%d8%af%d8%b1-%d8%b9%d9%84%d9%89-github-r265/" rel="">github</a>؛ وهو مشروع JavaScript يوفر ميزات Web Animation.
</p>

<p>
	توفّر JavaScript للمطور تحكمًا كاملًا في أنماط العنصر عند أي خطوة؛ أي أنه يُمكن إبطاء التحريك أو إيقافه مؤقتًا أو توقيفه أو عكسه من خلال التعامل مع العناصر بصورةٍ مناسبة، ويكون هذا مفيدًا جدًا في بناء التطبيقات المعقدة كائنية التوجه؛ حيث يتمكن المطور من تغليف سلوك التحريك بصورةٍ مناسبة.
</p>

<h2>
	التحريك والأداء
</h2>

<p>
	يجب الحفاظ على 60 إطارًا في الثانية عند التحريك دومًا؛ حيث تؤدي أي قيمةٍ أقل من ذلك إلى ظهور التقطيع، أو توقُّف التحريك واللذان يكونان واضحين للمستخدمين مما يؤدي إلى تردّي تجربة الاستخدام.
</p>

<ul>
<li>
		يجب الحرص على ألّا يُسبب التحريك أية مشاكل في الأداء؛ حيث يجب معرفة تأثير أي خاصية في أنماط CSS على الأداء.
	</li>
	<li>
		يجب الانتباه إلى أن جميع الخصائص التي تُغيُّر في هندسة الصفحة (التخطيط) أو تتسب في الطلاء تكون مُكلفةً على نحوٍ خاص.
	</li>
	<li>
		يجب الالتزام بتعديل التحويلات والشفافية ما أمكن ذلك.
	</li>
	<li>
		يُمكن استخدام سوف يُعدّل <code>will-change</code> للتأكد من معرفة المتصفح ما يُخطط لتحريكه.
	</li>
</ul>
<p>
	لا يكون تحريك الخصائص مجاني، كما أن تحريك بعض الخصائص أقل كلفةً من غيرها؛ حيث يُعدّل مثلًا تحريك العرض <code>width</code> والارتفاع <code>height</code> لعنصرٍ من هندسته، ويُمكن أن يؤدي ذلك إلى تحريك أو تغيير حجوم عناصرٍ أخرى على الصفحة. تُدعى هذه العملية بالتخطيط أو إعادة التدفق في بعض المتصفحات مثل Firefox المعتمدة على محرك المتصفحات Gecko؛ وهي عمليةٌ مكلفةٌ لاسيما إذا احتوت الصفحة على عناصر كثيرة. كلما يُشغّل التخطيط تحتاج الصفحة أو جزءٌ منها إلى إعادة الطلاء والذي يكون أكثر كلفًة من عملية التخطيط نفسها.
</p>

<p>
	يجب تجنُّب تحريك الخصائص التي تؤدي إلى تنشيط التخطيط أو الطلاء ما أمكن ذلك؛ وهذا يعني قصر التحريك على الشفافية <code>opacity</code> أو التحويلات <code>transform</code> بالنسبة لمعظم المتصفحات الحديثة، واللتان يتمكن المتصفح من تحسينها بدرجة عالية. لا يُشكّل التعامل مع التحريك باستخدام JavaScript أو CSS فرقًا بالنسبة للأداء.
</p>

<p>
	يُمكن الرجوع إلى <a href="https://csstriggers.com/" rel="external nofollow">CSS Triggers</a> للحصول على قائمةٍ كاملة لما يُنشّط تشغيله عند استخدام خصائص CSS الفردية، كما يُمكن الرجوع للمرجع الكامل لإنشاء <a href="https://www.html5rocks.com/en/tutorials/speed/high-performance-animations/" rel="external nofollow">تحريك عالي الأداء في عناصر HTML5</a>.
</p>

<h3>
	استخدام خاصية will-change
</h3>

<p>
	تُعلّم الخاصية <code>will-change</code> المتصفح بالنية في تعديل خاصية عنصر، مما يسمح للمتصفح بوضع التحسينات الأكثر ملاءمةً في مكانها قبل إجراء التعديل. ومع ذلك، لا يجب الإفراط في استخدام الخاصية <code>will-change</code>؛ لأن ذلك يؤدي إلى إضاعة الموارد ومزيدًا من مشاكل الأداء.
</p>

<p>
	تنص أحد القواعد التجريبية الأساسية على أنه إذا كان تنشيط التحريك سيبدأ خلال 200 ميلي ثانية القادمة، إما عن طريق تفاعل المستخدم أو بسبب حالة التطبيق، فإن وضع <code>will-change</code> يُعدّ فكرةً جيدة. يجب تمكين <code>will-change</code> في معظم الحالات لكل خاصيةٍ يُخطط لتحريكها لاحقًا. فعلى سبيل المثال، ستكون إضافة <code>will-change</code> للتحويلات والشفافية في أمثلتنا السابقة على النحو التالي:
</p>

<pre class="ipsCode prettyprint lang-css prettyprinted" id="ips_uid_9522_29" style="">
<span class="pun">.</span><span class="pln">box </span><span class="pun">{</span><span class="pln">
  will</span><span class="pun">-</span><span class="pln">change</span><span class="pun">:</span><span class="pln"> transform</span><span class="pun">,</span><span class="pln"> opacity</span><span class="pun">;</span><span class="pln">
</span><span class="pun">}</span></pre>

<p>
	ستُجري المتصفحات التي تدعم هذه الخاصية (حاليًا <a href="https://caniuse.com/#feat=will-change" rel="external nofollow">معظم المتصفحات الحديثة</a>) التحسينات المناسبة في الخلفية لدعم تعديل هذه الخصائص أو تحريكها.
</p>

<h3>
	أداء CSS موازنة مع أداء JavaScript
</h3>

<p>
	يوجد العديد من الصفحات والتعليقات في عالم الويب التي تناقش المزايا النسبية للتحريك باستخدام CSS و JavaScript من منظور الأداء. فيما يلي بعض النقاط التي يجب الانتباه لها:
</p>

<ul>
<li>
		يُدعَم التحريك المعتمد على أنماط CSS و Web Animations بصورةٍ أساسية ويُعالج ضمن خيطٍ thread منفصل يُعرف باسم "الخيط المُركَّب compositor thread"؛ والذي يختلف عن "الخيط الرئيسي main thread" للمتصفح، الذي يُنفذّ التصميم والتخطيط والطلاء وسكريبت جافا؛ مما يعني أنه إذا شغَّل المتصفح بعض المهام المكلفة على الخيط الرئيسي، يبقى التحريك مستمرًا دون أي مقاطعة.
	</li>
	<li>
		يُمكن في كثيرٍ من الحالات معالجة التعديلات الأخرى على التحويلات والشفافية باستخدام الخيط المُركّب.
	</li>
	<li>
		إذا أدى أي تحريكٍ إلى تشغيل الطلاء أو التخطيط أو كليهما، فسيُعهد إلى "الخيط الرئيسي" مهمة تنفيذ العمل وذلك في حالة التحريك المُستند إلى CSS أو JavaScript. يُمكن أن يؤدي الحمل الزائد للتخطيط أو الطلاء إلى بطء أي عملٍ مرتبطٍ بتنفيذ CSS أو JavaScript، مما يجعل المسألة موضع نقاش.
	</li>
</ul>
<p>
	يُمكن العودة إلى <a href="https://csstriggers.com/" rel="external nofollow">CSS Triggers</a> لمزيدٍ من المعلومات حول العمل المُنّشط عند تحريك خاصيةٍ ما.
</p>

<p>
	ترجمة -وبتصرف- للمقالات التالية:
</p>

<ul>
<li>
		<a href="https://developers.google.com/web/fundamentals/design-and-ux/animations" rel="external nofollow">Animations</a> للمؤلف: Paul Lewis.
	</li>
	<li>
		<a href="https://developers.google.com/web/fundamentals/design-and-ux/animations/css-vs-javascript" rel="external nofollow">CSS Versus JavaScript Animations</a> للمؤلفين: Paul Lewis و Sam Thorogood.
	</li>
	<li>
		<a href="https://developers.google.com/web/fundamentals/design-and-ux/animations/animations-and-performance" rel="external nofollow">Animations and Performance</a>
	</li>
</ul>
<p>
	للمؤلفين: Paul Lewis و Sam Thorogood.
</p>

<h2>
	اقرأ أيضًا
</h2>

<ul>
<li>
		<a href="https://academy.hsoub.com/programming/javascript/%d8%a3%d9%8a%d9%91%d9%87%d9%85%d8%a7-%d8%a3%d9%81%d8%b6%d9%84-%d9%84%d9%84%d8%aa%d8%ad%d8%b1%d9%8a%d9%83-animations%d8%9f-%d8%ac%d8%a7%d9%81%d8%a7%d8%b3%d9%83%d8%b1%d8%a8%d8%aa-%d8%a3%d9%85-css%d8%9f-r42/" rel="">أيّهما أفضل للتحريك Animations؟ جافاسكربت أم CSS؟</a>
	</li>
	<li>
		<a href="https://academy.hsoub.com/programming/css/%D8%AE%D8%A7%D8%B5%D9%8A%D8%A7%D8%AA-%D8%A7%D9%84%D8%AD%D8%B1%D9%83%D8%A7%D8%AA-r693/" rel="">خاصيات الحركات</a>
	</li>
	<li>
		<a href="https://academy.hsoub.com/programming/css/%D8%A7%D9%84%D8%AD%D8%B1%D9%83%D8%A7%D8%AA-%D8%A7%D9%84%D9%85%D8%AA%D8%B9%D8%AF%D8%AF%D8%A9-%D8%A7%D9%84%D9%85%D8%AA%D8%B2%D8%A7%D9%85%D9%86%D8%A9-r696/" rel="">الحركات المتعددة المتزامنة</a>
	</li>
	<li>
		<a href="https://academy.hsoub.com/programming/css/%D8%A7%D9%84%D8%A7%D9%86%D8%AA%D9%82%D8%A7%D9%84%D8%A7%D8%AA-%D9%88%D8%AC%D8%A7%D9%81%D8%A7%D8%B3%D9%83%D8%B1%D8%A8%D8%AA-r684/" rel="">الانتقالات وجافاسكربت</a>
	</li>
</ul>
]]></description><guid isPermaLink="false">1481</guid><pubDate>Tue, 15 Feb 2022 05:38:02 +0000</pubDate></item><item><title>&#x645;&#x627; &#x647;&#x64A; &#x62A;&#x637;&#x628;&#x64A;&#x642;&#x627;&#x62A; &#x627;&#x644;&#x648;&#x64A;&#x628; &#x627;&#x644;&#x62A;&#x642;&#x62F;&#x645;&#x64A;&#x629; PWA&#x61F;</title><link>https://academy.hsoub.com/programming/general/%D9%85%D8%A7-%D9%87%D9%8A-%D8%AA%D8%B7%D8%A8%D9%8A%D9%82%D8%A7%D8%AA-%D8%A7%D9%84%D9%88%D9%8A%D8%A8-%D8%A7%D9%84%D8%AA%D9%82%D8%AF%D9%85%D9%8A%D8%A9-pwa%D8%9F-r1480/</link><description><![CDATA[
<p><img src="https://academy.hsoub.com/uploads/monthly_2022_02/620aa2b04f07c_-----PWA.png.f20d11b9de71feeed6cc02bac0ca9bef.png" /></p>

<p>
	الويب منصة رائعة، إذ تُشغل على مستوى كل الأجهزة <a href="https://academy.hsoub.com/files/24-%D8%A3%D9%86%D8%B8%D9%85%D8%A9-%D8%A7%D9%84%D8%AA%D8%B4%D8%BA%D9%8A%D9%84-%D9%84%D9%84%D9%85%D8%A8%D8%B1%D9%85%D8%AC%D9%8A%D9%86/" rel="">وأنظمة التشغيل</a>، وتتميز بنموذج أمان يركز على المستخدم، يتم التحكم في تشغيله ومواصفاته من قبل مجتمع الويب وليس من قبل شركة أو كيان محدد، وهذا يجعله منصة مميزة لتطوير التطبيقات. ويمتلك الويب ميزة رائعة، وهي الروابط، إذ من الممكن البحث عن أي شيء ومشاركة ما وجدته مع أي شخص في أي مكان فقط برابط. تتميز مواقع الويب بكونها محدثة دائما، وسهولة الولوج إلى أي موقع، ويمكن أن تكون تجربتك على الموقع سريعة أو دائمة على حسب ما تحتاجه.
</p>

<p>
	تملك تطبيقات الويب وصولا كبيرا للمستخدمين، إذ يمكنها أن تصل إلى أي شخص في أي مكان وعلى أي جهاز بشيفرة مصدرية واحدة.
</p>

<p>
	تطبيقات الويب معروفة بكونها تطبيقات غنية وموثوقة، ومتواجدة في كل مكان، وتعمل بغض النظر عن اتصالك بالشبكة، وذات تجربة فريدة. ويمكنها قراءة وكتابة الملفات، والاتصال بأجهزة عبر USB والبلوتوث، وحتى التعامل مع البيانات المخزنة في جهازك، كجهات الإتصال والتقويم، ويمكنك حتى التقاط صور وتسجيل الأصوات وتشغيلها، كل هذا والمزيد من الخصائص تكسبها تجربة فريدة لتبدو وكأنها جزء من النظام نفسه.
</p>

<p style="text-align: center;">
	<a class="ipsAttachLink ipsAttachLink_image" data-fileid="91950" href="https://academy.hsoub.com/uploads/monthly_2022_02/1.jpg.77e9ce26a19529684bce403cc2d14739.jpg" rel=""><img alt="1.jpg" class="ipsImage ipsImage_thumbnailed" data-fileid="91950" data-unique="8gy6lzcda" src="https://academy.hsoub.com/uploads/monthly_2022_02/1.thumb.jpg.181985f430706818c0d27646ca575791.jpg" style="width: 450px; height: auto;"></a>
</p>

<p style="text-align: center;">
	الوصول مقابل الإمكانيات لكل من تطبيقات الويب والتطبيقات الخاصة بالنظام وتطبيقات الويب التقدمية PWA
</p>

<p>
	إذا وازنت بين التطبيقات المبنية خصيصًا للنظام وتطبيقات الويب من ناحية الإمكانيات والوصول، فإن التطبيقات المخصصة للنظام بالتأكيد تملك إمكانيات أكبر، ولكن تطبيقات الويب لديها وصول أكبر، فماذا عن تطبيقات الويب التقدمية؟
</p>

<p>
	بنيت <a href="https://academy.hsoub.com/programming/general/%D9%85%D8%AF%D8%AE%D9%84-%D8%A5%D9%84%D9%89-%D8%AA%D8%B7%D8%A8%D9%8A%D9%82%D8%A7%D8%AA-%D8%A7%D9%84%D9%88%D9%8A%D8%A8-%D8%A7%D9%84%D8%AA%D9%82%D8%AF%D9%85%D9%8A%D8%A9-pwa-r832/" rel="">تطبيقات الويب التقدمية</a> PWA -اختصارًا إلى Progressive Web Apps- بحيث تستفيد من واجهة برمجيات الويب الحديثة لتقديم إمكانيات عالية وموثوقية كبيرة وقابلية للتثبيت لتصل للجميع في أي مكان وعلى أي جهاز.
</p>

<h2>
	الركائز الأساسية لتطبيقات الويب التقدمية
</h2>

<p>
	اعتمد تصميم تطبيقات الويب التقدمية على ثلاثة ركائز أساسية: الإمكانيات وقابلية التثبيت والموثوقية، هذه الركائز الثلاث تجعل تجربة تطبيق الويب التقدمي شبيهة بالتطبيقات المخصصة للنظام.
</p>

<h3>
	الإمكانيات
</h3>

<p>
	يقصد بالإمكانيات ما يستطيع الويب فعله، يُعد الويب حاليا قادرًا على القيام بأغلب المهام دون الإعتماد على أي إضافات خارجية، فمثلا، يمكنك إنشاء تطبيق دردشة فيديو باستخدام WebRTC وهي تقنية لدردشة الفيديو في الويب، ومعرفة الموقع، وإرسال إشعارات. ويمكنك جعل التطبيق قابلا للتثبيت، وجعل المحادثات داخل عالم افتراضي باستخدام <a href="https://academy.hsoub.com/programming/javascript/%D9%85%D9%82%D8%AF%D9%85%D8%A9-%D8%A5%D9%84%D9%89-webgl-%D8%AA%D8%B9%D8%B1%D9%8A%D9%81-r481/" rel="">WebGL</a> و WebVR وأصبح بإمكان المطورين مع <a href="https://academy.hsoub.com/programming/general/%D9%83%D9%84-%D9%85%D8%A7-%D8%AA%D8%B1%D9%8A%D8%AF-%D9%85%D8%B9%D8%B1%D9%81%D8%AA%D9%87-%D8%B9%D9%86-webassembly-r869/" rel="">WebAssembly</a> الولوج إلى بيئات مختلفة مثل <a href="https://academy.hsoub.com/programming/c/" rel="">C</a> و <a href="https://academy.hsoub.com/programming/cpp/%D9%85%D8%AF%D8%AE%D9%84-%D8%A5%D9%84%D9%89-c-r802/" rel="">C++‎</a> و Rust وجلب ميزات قوية للويب كانت حكرا على التطبيقات المخصصة للنظام، كمثال موقع <a href="https://squoosh.app" rel="external nofollow">Squoosh.app</a> الذي يقدم إمكانية ضغط صور متقدمة، فحتى وقت قريب، كانت التطبيقات المخصصة للنظام فقط قادرة على القيام بعمليات تتطلب أداءً عالية كالمثال الذي ذكرناه.
</p>

<p>
	رغم أن بعض الإمكانيات لا تزال بعيدة عن متناول الويب، فإن واجهات برمجة التطبيقات WebAPI الجديدة والقادمة تتطلع لجعل ذلك ممكنا، وجعل الويب قادرًا على القيام بما هو أكثر كالوصول لنظام الملفات وعناصر التحكم في الوسائط وإشعارات التطبيق والدعم الكامل للحافظة. كل هذه الميزات يتم تصميمها بنموذج الأذونات، ما يجعل الويب بيئة آمنة.
</p>

<p>
	تطبيقات الويب الآن أقوى من أي وقت مضى، فصار الويب بفضل واجهة التطبيقات البرمجية الحديثة والقادمة وتكنولوجيا WebAssembly قادرًا على القيام بما كان يبدو مستحيلًا في وقت مضى، في حين لازال قادرًا على تقديم المزيد.
</p>

<h3>
	الموثوقية
</h3>

<p>
	يعطي تطبيق الويب التقدمي تجربة أكثر موثوقية سواء كان هناك اتصال بالإنترنت أم لا، حتى بدون إنترنت، يتوقع المستخدم شيئا ما من التطبيق.
</p>

<p>
	إلى جانب ضرورة عمل بعض وظائف التطبيق بدون إنترنت، فإن السرعة أمر بالغ الأهمية في ما يتعلق بموثوقية تطبيقك، إذ تتراوح أوقات تحميل الصفحة بين ثانية واحدة وعشر ثوانٍ، <a href="https://www.thinkwithgoogle.com/marketing-resources/data-measurement/mobile-page-speed-new-industry-benchmarks/" rel="external nofollow">ويزداد اعتمادا على ذلك</a> احتمال ارتداد المستخدم <a href="https://www.thinkwithgoogle.com/marketing-strategies/app-and-mobile/mobile-page-speed-new-industry-benchmarks/" rel="external nofollow">بنسبة 123٪</a>. لا يتوقف الأداء بعد الحدث <code>onload</code>، عندما ينقر المستخدم مثلا فوق زر ما فإنه يتوقع حدوث شيء ما، ويجب أن يشعر المستخدم بسلاسة أثناء التمرير، إذ يؤثر الأداء على تجربة المستخدم كليا، من حيث كيفية نظر المستخدمين لتطبيقك وأدائه الفعلي.
</p>

<p>
	يجب أن تكون التطبيقات الموثوقة قابلة للاستخدام سواء بوجود اتصال بالإنترنت أو بدونه، حتى في <a href="https://academy.hsoub.com/programming/html/html5/%D8%AA%D8%B7%D8%A8%D9%8A%D9%82%D8%A7%D8%AA-%D8%A7%D9%84%D9%88%D9%8A%D8%A8-%D8%A7%D9%84%D8%AA%D9%8A-%D8%AA%D8%B9%D9%85%D9%84-%D8%AF%D9%88%D9%86-%D8%A7%D8%AA%D8%B5%D8%A7%D9%84-%E2%80%93-%D8%A7%D9%84%D8%AC%D8%B2%D8%A1-%D8%A7%D9%84%D8%A3%D9%88%D9%84-r441/" rel="">حال عدم اتصال التطبيق بالإنترنت</a>، يتوقع المستخدمون الولوج لأشياء كقائمة الرغبات أو التذاكر المحفوظة وغيرها من الأمور. عندما يكون طلب شيء ما من الخادم غير ممكن، يتوقع المستخدمون رسالة تخبرهم بالمشكلة بدل انهيار التطبيق وتوقف استجابته. يحب المستخدمون التطبيقات التي تستجيب بسرعة، والتي يمكنهم الاعتماد عليها.
</p>

<h3>
	قابلية التثبيت
</h3>

<p>
	تتميز تطبيقات الويب التقدمية <a href="https://academy.hsoub.com/programming/general/%D9%86%D9%85%D8%A7%D8%B0%D8%AC-%D8%A7%D9%82%D8%AA%D8%B1%D8%A7%D8%AD%D8%A7%D8%AA-%D8%AA%D8%AB%D8%A8%D9%8A%D8%AA-%D8%AA%D8%B7%D8%A8%D9%8A%D9%82%D8%A7%D8%AA-%D8%A7%D9%84%D9%88%D9%8A%D8%A8-%D8%A7%D9%84%D8%AA%D9%82%D8%AF%D9%85%D9%8A%D8%A9-pwa-r1446/" rel="">بقابلية التثبيت </a>وتُشغل في نافذة منفصلة بدلًا من تبويبة المتصفح، ويتم تشغيلها من اختصار في الشاشة الرئيسية أو شريط المهام أو حتى قائمة التطبيقات، ويمكن البحث عنها والانتقال بينها وبين التطبيقات الأخرى كأي تطبيق آخر، وكأنها جزء من التطبيقات العادية.
</p>

<p>
	يحصل تطبيق PWA على إمكانيات جديدة بعد التثبيت، إذ يمكنه تلقي بيانات من تطبيقات أخرى أو جعله تطبيقا افتراضيا لنوع ما من الملفات. تتغير طريقة تفكير المستخدمين حول تطبيق الويب عند تشغيله في نافذة منفصلة.
</p>

<h2>
	تطبيقات الويب مقابل تطبيقات الويب التقدمية
</h2>

<p>
	تطبيقات الويب التقدمية مجرد تطبيقات ويب في الأصل، لكن باستخدام <a href="https://academy.hsoub.com/programming/general/%D9%85%D9%81%D9%87%D9%88%D9%85-service-worker-%D9%88%D8%AA%D8%A3%D8%AB%D9%8A%D8%B1%D9%87-%D9%81%D9%8A-%D8%A3%D8%AF%D8%A7%D8%A1-%D9%88%D8%A8%D9%86%D9%8A%D8%A9-%D9%85%D9%88%D8%A7%D9%82%D8%B9-%D9%88%D8%AA%D8%B7%D8%A8%D9%8A%D9%82%D8%A7%D8%AA-%D8%A7%D9%84%D9%88%D9%8A%D8%A8-r833/" rel="">منجزات خدمة service workers</a> و<a href="https://academy.hsoub.com/programming/html/html5/%D8%AA%D8%B7%D8%A8%D9%8A%D9%82%D8%A7%D8%AA-%D8%A7%D9%84%D9%88%D9%8A%D8%A8-%D8%A7%D9%84%D8%AA%D9%8A-%D8%AA%D8%B9%D9%85%D9%84-%D8%AF%D9%88%D9%86-%D8%A7%D8%AA%D8%B5%D8%A7%D9%84-%E2%80%93-%D8%A7%D9%84%D8%AC%D8%B2%D8%A1-%D8%A7%D9%84%D8%A3%D9%88%D9%84-r441/" rel="">بيان تطبيق الويب manifest</a>. يصبح تطبيق الويب قابلا للتثبيت وموثوقًا، تدريجيا تضاف إمكانات جديدة للمتصفحات، وإن لم تكن الإمكانيات الجديدة متوفرة سيبقى بإمكان المستخدم الحصول على التجربة الأساسية لتطبيق الويب، وهذا يجعل تطبيق الويب التقدمي مرنًا للغاية.
</p>

<p>
	الأرقام لا تخفي نفسها! فحققت الشركات التي أطلقت تطبيقات الويب التقدمية نتائج باهرة. مثلا، شهد تويتر زيادة بنسبة 65٪ لمدة الجلسات، وزيادة بنسبة 75٪ في التغريدات، وانخفاضًا بنسبة 20٪ في معدل الارتداد، بحجم أقل 97٪ من التطبيق الرئيسي.
</p>

<p>
	بعد التحول إلى تطبيقات الويب التقدمية، شهد مؤشر نيكي Nikkei زيادة في عدد زيارات الأعضاء بمعدل 2.3 مرة، واشتراكات أكثر بنسبة 58٪، وزيادة في عدد المستخدمين النشطين كل يوم بنسبة 49٪.
</p>

<p>
	استبدلت هولو Hulu تجربة تطبيق سطح المكتب الخاصة بالنظام الأساسي بتطبيق ويب تقدمي وشهدت زيادة بنسبة 27٪ في عدد المستخدمين العائدين للتطبيق.
</p>

<p>
	توفر لك تطبيقات الويب التقدمية فرصة مميزة لتقديم تجربة ويب يحبها المستخدمون. بإمكانات أكثر، وموثوقية أكبر، بفضل أحدث ميزات الويب، وتتيح تطبيقات الويب التقدمية إمكانية تثبيت تطبيقك لدى أي شخص في أي مكان وعلى أي جهاز بكود واحد.
</p>

<p>
	ترجمة -وبتصرف- للمقال <a href="https://web.dev/what-are-pwas/" rel="external nofollow">What are Progressive Web Apps?‎</a> لصاحبيه Sam Richard و Pete LePage.
</p>

<h2>
	اقرأ أيضًا
</h2>

<ul>
<li>
		<a href="https://academy.hsoub.com/programming/javascript/%D8%AA%D9%88%D9%81%D9%8A%D8%B1-%D8%AA%D8%AC%D8%B1%D8%A8%D8%A9-%D8%AA%D8%AB%D8%A8%D9%8A%D8%AA-%D9%85%D8%AE%D8%B5%D8%B5%D8%A9-%D8%AF%D8%A7%D8%AE%D9%84-%D8%AA%D8%B7%D8%A8%D9%8A%D9%82-%D8%A7%D9%84%D9%88%D9%8A%D8%A8-%D8%A7%D9%84%D8%AA%D9%82%D8%AF%D9%85%D9%8A-pwa-r1445/" rel="">توفير تجربة تثبيت مخصصة داخل تطبيق الويب التقدمي PWA</a>
	</li>
	<li>
		<a href="https://academy.hsoub.com/programming/general/%D8%AA%D8%B4%D8%BA%D9%8A%D9%84-%D8%AA%D8%B7%D8%A8%D9%8A%D9%82%D8%A7%D8%AA-%D8%A7%D9%84%D9%88%D9%8A%D8%A8-%D8%A7%D9%84%D8%AA%D9%82%D8%AF%D9%85%D9%8A%D8%A9-pwa-%D9%81%D9%8A-%D9%88%D8%B6%D8%B9-%D8%A7%D9%86%D9%82%D8%B7%D8%A7%D8%B9-%D8%A7%D9%84%D8%A7%D8%AA%D8%B5%D8%A7%D9%84-r1386/" rel="">تشغيل تطبيقات الويب التقدمية PWA في وضع انقطاع الاتصال</a>
	</li>
	<li>
		<a href="https://academy.hsoub.com/programming/general/%D8%B4%D8%B1%D8%AD-%D9%85%D9%84%D9%81-%D8%A7%D9%84%D8%A8%D9%8A%D8%A7%D9%86-manifest-%D9%84%D8%AA%D8%B7%D8%A8%D9%8A%D9%82-%D8%A7%D9%84%D9%88%D9%8A%D8%A8-%D8%A7%D9%84%D8%AA%D9%82%D8%AF%D9%85%D9%8A-pwa-r1385/" rel="">شرح ملف البيان manifest لتطبيق الويب التقدمي PWA</a>
	</li>
</ul>
]]></description><guid isPermaLink="false">1480</guid><pubDate>Mon, 14 Feb 2022 18:57:48 +0000</pubDate></item><item><title>&#x62A;&#x647;&#x64A;&#x626;&#x629; &#x62A;&#x637;&#x628;&#x64A;&#x642;&#x627;&#x62A; &#x627;&#x644;&#x648;&#x64A;&#x628; &#x627;&#x644;&#x62A;&#x642;&#x62F;&#x645;&#x64A;&#x629; PWA &#x644;&#x627;&#x633;&#x62A;&#x62E;&#x62F;&#x627;&#x645;&#x647;&#x627; &#x643;&#x62A;&#x637;&#x628;&#x64A;&#x642;&#x627;&#x62A; &#x623;&#x646;&#x62F;&#x631;&#x648;&#x64A;&#x62F;</title><link>https://academy.hsoub.com/programming/general/%D8%AA%D9%87%D9%8A%D8%A6%D8%A9-%D8%AA%D8%B7%D8%A8%D9%8A%D9%82%D8%A7%D8%AA-%D8%A7%D9%84%D9%88%D9%8A%D8%A8-%D8%A7%D9%84%D8%AA%D9%82%D8%AF%D9%85%D9%8A%D8%A9-pwa-%D9%84%D8%A7%D8%B3%D8%AA%D8%AE%D8%AF%D8%A7%D9%85%D9%87%D8%A7-%D9%83%D8%AA%D8%B7%D8%A8%D9%8A%D9%82%D8%A7%D8%AA-%D8%A3%D9%86%D8%AF%D8%B1%D9%88%D9%8A%D8%AF-r1447/</link><description><![CDATA[
<p><img src="https://academy.hsoub.com/uploads/monthly_2022_01/61f2419f70597_-----------------------------Android-Apps-Prog.png.e482b137102950a1b197ea04e33365c0.png" /></p>

<p>
	تتميز <a href="https://academy.hsoub.com/programming/general/%D9%85%D8%AF%D8%AE%D9%84-%D8%A5%D9%84%D9%89-%D8%AA%D8%B7%D8%A8%D9%8A%D9%82%D8%A7%D8%AA-%D8%A7%D9%84%D9%88%D9%8A%D8%A8-%D8%A7%D9%84%D8%AA%D9%82%D8%AF%D9%85%D9%8A%D8%A9-pwa-r832/" rel="">تطبيقات الويب التقدميّة</a> Progressive Web Apps (تختصر إلى PWA) بواجهات ويب شبيهة جدًا بواجهات التطبيقات المألوفة للجميع مما يوفر تجربة استخدام عالية الجودة وسريعة وموثوقة وجذابة.
</p>

<p>
	على الرغم من أن <a href="https://academy.hsoub.com/programming/html/html5/%D8%AA%D8%B7%D8%A8%D9%8A%D9%82%D8%A7%D8%AA-%D8%A7%D9%84%D9%88%D9%8A%D8%A8-%D8%A7%D9%84%D8%AA%D9%8A-%D8%AA%D8%B9%D9%85%D9%84-%D8%AF%D9%88%D9%86-%D8%A7%D8%AA%D8%B5%D8%A7%D9%84-%E2%80%93-%D8%A7%D9%84%D8%AC%D8%B2%D8%A1-%D8%A7%D9%84%D8%A3%D9%88%D9%84-r441/" rel="">تطبيقات الويب</a> يُمكن أن توفر تجارب استخدام رائعة وجديدة إلا أن أغلبية المستخدمين تتوقع من هذه التطبيقات واجهات استخدام شبيهة بالواجهات التي اعتادوا عليها أثناء تشغيلهم لمختلف التطبيقات على حواسبهم، وعندها ستكون جاذبية استخدام هذه التطبيقات أعلى من المتوسط وفق معظم المقاييس.
</p>

<p>
	من المعروف أن متجر Play Store هو متجر تطبيقات أندرويد، وغالبًا ما يرغب المطورون بفتح صفحات الويب التقدميّة المُطوّرة من <a href="https://academy.hsoub.com/programming/android/%D9%85%D8%AF%D8%AE%D9%84-%D8%A5%D9%84%D9%89-%D8%A8%D8%B1%D9%85%D8%AC%D8%A9-%D8%AA%D8%B7%D8%A8%D9%8A%D9%82%D8%A7%D8%AA-%D8%A3%D9%86%D8%AF%D8%B1%D9%88%D9%8A%D8%AF-r300/" rel="">تطبيقات أندرويد</a>.
</p>

<p>
	يسمح معيار نشاط الويب الموثوق Trusted Web Activity للمتصفحات بتوفير حاوية متوافقة تمامًا مع منصة الويب التي تُظهر صفحات الويب التقدميّة داخل تطبيق أندرويد. تتوفر هذه الميزة في المتصفح Chrome حاليًا وهي قيد التطوير في المتصفح Firefox Nightly.
</p>

<h2>
	عارض الويب وكوردوفا: حلول متوفرة ولكن قاصرة
</h2>

<p>
	كان من الممكن دومًا تضمين سلوك الويب في تطبيق أندرويد باستخدام تقانات مثل عارض الويب WebView في أندرويد أو أطر العمل الخاصة مثل كوردوفا Cordova.
</p>

<p>
	لا يوفر عارض الويب WebView في أندرويد جميع ميزات منصات الويب الحديثة مثل منتقي جهات الاتصال contact picker وملفات النظام filesystem، إذ أنه لم يُصمم في الأساس ليكون بديلًا عن المتصفح.
</p>

<p>
	أما بالنسبة لبيئة <a href="https://academy.hsoub.com/programming/javascript/cordova/%D8%AA%D8%AC%D9%87%D9%8A%D8%B2-%D8%A8%D9%8A%D8%A6%D8%A9-%D8%A7%D9%84%D8%B9%D9%85%D9%84-%D9%81%D9%8A-%D8%A3%D8%A8%D8%A7%D8%AA%D8%B4%D9%8A-%D9%83%D9%88%D8%B1%D8%AF%D9%88%D9%81%D8%A7-r1263/" rel="">كوردوفا</a>، فعلى الرغم من أنها صُمّمت لتجاوز محدودية عارض الويب إلا أن واجهات برمجة التطبيقات APIs تقتصر على هذه البيئة مما يعني أن المطور يحتاج شيفرة أساسية إضافية لاستخدام واجهات برمجة تطبيقات كوردوفا منفصلة عن شيفرة صفحات الويب التقدميّة اللازمة لعرض الصفحات على متصفحات الويب.
</p>

<p>
	علاوًة على ذلك، قد لا يعمل اكتشاف الميزات في التطبيق كما هو متوقع منه، إضافًة إلى إمكانية ظهور العديد من مشكلات التوافق بين الإصدارات المختلفة أو المصنعين المتعددين لأجهزة أندرويد. مما قد يستغرق وقتًا طويلًا من قبل المطورين لإيجاد حلول بديلة لضمان جودة المنتج النهائي.
</p>

<h2>
	حاوية جديدة لتطبيقات الويب على أندرويد: نشاط الويب الموثوق
</h2>

<p>
	يُمكن للمطورين اليوم تضمين صفحة ويب تقدميّة كنشاط تشغيل launch activity في تطبيق أندرويد باستخدام نشاط الويب الموثوق Trusted Web Activity والذي يُمكّن المتصفح من إخراج صفحة الويب التقدميّة ملء الشاشة مما يضمن التوافقية الكاملة مع ميزات منصة الويب وجميع واجهات برمجة التطبيقات التي يستدعيها المتصفح. يوجد العديد من الأدوات المساعدة مفتوحة المصدر لتسهيل تطوير تطبيق أندرويد يستخدم صفحات الويب التقدميّة.
</p>

<p>
	من الميزات الإضافية لاستخدام حاوية نشاط الويب الموثوق أن هذه الحاوية تتشارك التخزين مع المتصفح مما يعني أن حالات تسجيل الدخول وتفضيلات المستخدم متاحة لكل منهما بشكل سلس عبر التجارب المتتالية للمستخدمين.
</p>

<h3>
	توافقية المتصفحات
</h3>

<p>
	تتوفر هذه الميزة منذ الإصدار رقم 75 للمتصفح Chrome إلا أنها ما زالت قيد التطوير للنسخة القادمة من Firefox.
</p>

<h2>
	معايير الجودة
</h2>

<p>
	يجب على مطور الويب استخدام نشاط الويب الموثوق عندما يريد تضمين محتوى الويب في تطبيق أندرويد، إذ يجب أن يُحقق محتوى الويب في نشاط الويب الموثوق معايير إمكانية <a href="https://academy.hsoub.com/programming/javascript/%D8%AA%D9%88%D9%81%D9%8A%D8%B1-%D8%AA%D8%AC%D8%B1%D8%A8%D8%A9-%D8%AA%D8%AB%D8%A8%D9%8A%D8%AA-%D9%85%D8%AE%D8%B5%D8%B5%D8%A9-%D8%AF%D8%A7%D8%AE%D9%84-%D8%AA%D8%B7%D8%A8%D9%8A%D9%82-%D8%A7%D9%84%D9%88%D9%8A%D8%A8-%D8%A7%D9%84%D8%AA%D9%82%D8%AF%D9%85%D9%8A-pwa-r1445/" rel="">تثبيت صفحات الويب التقدميّة</a>.
</p>

<p>
	بهدف تحقيق توقعات المستخدمين لسلوك تطبيقات أندرويد، أدخلت النسخة 86 من المتصفح Chrome تعديلًا يعدّ الفشل في معالجة أحد السيناريوهات التالية عطلًا:
</p>

<ul>
<li>
		الفشل في التحقق من رابط بروتوكول مشاركة الموارد digital asset links عند تشغيل التطبيق
	</li>
	<li>
		الفشل في إرجاع HTTP 200 عند طلب مورد دون اتصال
	</li>
	<li>
		إعادة HTTP 404 أو خطأ 5xx عند طلب تنقل
	</li>
</ul>
<p>
	يتسبب الوقوع في أحد هذه السيناريوهات في نشاط الويب الموثوق بإظهار عطل للمستخدم في تطبيق أندرويد. يجب على المطور التحقق من الإرشادات الخاصة <a href="https://developer.chrome.com/docs/android/trusted-web-activity/whats-new/#updates-to-the-quality-criteria" rel="external nofollow">guidance</a> للتعامل مع هذه السيناريوهات في عامل النشاط service worker.
</p>

<p>
	يجب أن يُحقق التطبيق المعايير الخاصة بأندرويد مثل سياسة الامتثال <a href="https://play.google.com/about/developer-content-policy/" rel="external nofollow">policy compliance</a>.
</p>

<p>
	تحذير: إذا كان التطبيق مُصمم بشكل أساسي للأطفال تحت سن 13 عامًا، فيجب مراعاة <a href="https://support.google.com/googleplay/android-developer/topic/9877766" rel="external nofollow">سياسة العائلة</a> على متجر Play store والتي يُمكن أن تمنع من استخدام نشاط الويب الموثوق.
</p>

<p>
	يُبين الشكل التالي شارة صفحات الويب التقدميّة والتي تستخدم أداة Lighthouse لإظهار معايير إمكانية التثبيت installability:
</p>

<p style="text-align: center;">
	<a class="ipsAttachLink ipsAttachLink_image" data-fileid="89761" href="https://academy.hsoub.com/uploads/monthly_2022_01/001PWA.png.8a40c8986665cc65af9abe915895d1c3.png" rel=""><img alt="001PWA.png" class="ipsImage ipsImage_thumbnailed" data-fileid="89761" data-unique="2yppf0sb0" src="https://academy.hsoub.com/uploads/monthly_2022_01/001PWA.thumb.png.a950efd50abdc346f4d4ff759191b733.png"></a>
</p>

<h2>
	تحويل تطبيق ويب تقدمي إلى تطبيق أندرويد
</h2>

<p>
	لا يحتاج مطور الويب الذي يرغب في استخدام نشاط الويب الموثوق إلى تعلم تقنيات أو واجهات برمجة تطبيقات جديدة لتحويل صفحات الويب التقدميّة إلى تطبيق أندرويد، إذ يوفر كل من طوق الفقاعات Bubblewrap وباني صفحات الويب التقدميّة PWABuilder الأدوات اللازمة في مكتبة مخصصة وواجهة سطر أوامر (CLI) و<a href="https://academy.hsoub.com/programming/java/%D9%85%D9%82%D8%AF%D9%85%D8%A9-%D8%A5%D9%84%D9%89-%D8%A8%D8%B1%D9%85%D8%AC%D8%A9-%D9%88%D8%A7%D8%AC%D9%87%D8%A7%D8%AA-%D8%A7%D9%84%D9%85%D8%B3%D8%AA%D8%AE%D8%AF%D9%85-%D8%A7%D9%84%D8%B1%D8%B3%D9%88%D9%85%D9%8A%D8%A9-gui-%D9%81%D9%8A-%D8%AC%D8%A7%D9%81%D8%A7-r1070/" rel="">واجهة مستخدم رسومية (GUI)</a>.
</p>

<h3>
	المكتبة Bubblewrap
</h3>

<p>
	يولد المشروع <a href="https://github.com/GoogleChromeLabs/bubblewrap" rel="external nofollow">Bubblewrap</a> تطبيقات أندرويد على شكل مكتبة NodeJS وواجهة سطر أوامر (CLI).
</p>

<p>
	يُمكن توليد مشروع جديد عن طريق تنفيذ الأداة مع تمرير رابط URL لملف بيان الويب <a href="https://academy.hsoub.com/programming/general/%D8%B4%D8%B1%D8%AD-%D9%85%D9%84%D9%81-%D8%A7%D9%84%D8%A8%D9%8A%D8%A7%D9%86-manifest-%D9%84%D8%AA%D8%B7%D8%A8%D9%8A%D9%82-%D8%A7%D9%84%D9%88%D9%8A%D8%A8-%D8%A7%D9%84%D8%AA%D9%82%D8%AF%D9%85%D9%8A-pwa-r1385/" rel="">Web Manifest</a> كما يلي:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_9275_14" style="">
<span class="pln">npx </span><span class="lit">@bubblewrap</span><span class="pun">/</span><span class="pln">cli init </span><span class="pun">--</span><span class="pln">manifest</span><span class="pun">=</span><span class="pln">https</span><span class="pun">:</span><span class="com">//pwa-directory.appspot.com/manifest.json</span></pre>

<p>
	يُمكن للأداة أيضًا بناء المشروع وذلك بتنفيذ الأمر التالي والذي يولد تطبيق أندرويد جاهز للرفع على متجر Play store:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_9275_16" style="">
<span class="pln">npx </span><span class="lit">@bubblewrap</span><span class="pun">/</span><span class="pln">cli build</span></pre>

<p>
	يُصبح الملف <code>app-release-signed.apk</code> متاحًا في مجلد جذر المشروع root بعد تنفيذ الأمر السابق، وهو ما يجب رفعه على المتجر Play store.
</p>

<h3>
	باني صفحات الويب التقدميّة PWABuilder
</h3>

<p>
	يُساعد باني صفحات الويب التقدميّة PWABuilder المطورين على تحويل مواقع الويب الحالية إلى صفحات ويب تقدميّة. يتكامل هذا الباني مع المكتبة Bubblewrap لتوفير واجهة مستخدم رسومية تُغلّف صفحات الويب التقدميّة في تطبيق أندرويد. يُمكن العودة <a href="https://www.davrous.com/2020/02/07/publishing-your-pwa-in-the-play-store-in-a-couple-of-minutes-using-pwa-builder/" rel="external nofollow">لنشرة</a> فريق عمل باني PWABuilder للحصول على تفاصيل أكثر حول توليد الأداة لتطبيق أندرويد.
</p>

<h2>
	التحقق من ملكية تطبيقات الويب التقدمية في تطبيق أندرويد
</h2>

<p>
	لضمان عدم استخدام صفحة ويب تقدميّة أي مطور آخر دون استئذان المطور الأصلي لها يجب إقران تطبيق أندرويد مع صفحات الويب التقدمية باستخدام أداة تُدعى روابط الأصول الرقمية <a href="https://developers.google.com/digital-asset-links/v1/getting-started" rel="external nofollow">Digital Asset Links</a>.
</p>

<p>
	يتولى كل من Bubblewrap و PWABuilder الضبط configuration المطلوب على تطبيق أندرويد إلا أنه يتبقى خطوة وحيدة وهي إضافة الملف <code>assetlinks.json</code> إلى صفحات الويب التقدميّة.
</p>

<p>
	لإنشاء هذا الملف، يحتاج المطور إلى التوقيع SHA-256 للمفتاح المستخدم لتوقيع ملف APK الذي يُنزله المستخدمون.
</p>

<p>
	يُمكن توليد هذا المفتاح بعدة طرق من أسهلها إيجاد المفتاح المتوفر مع ملف APK نفسه الذي ينزله المستخدمون من متجر Play store.
</p>

<p>
	لتجنب إظهار تطبيق معطل للمستخدمين، انشر التطبيق أولًا على قناة اختبار مغلقة <a href="https://support.google.com/googleplay/android-developer/answer/9845334?hl=en-GB&amp;visit_id=637645572811119867-2959133935&amp;rd=1" rel="external nofollow">closed test channel</a> ثم ثبتّه في جهاز اختبار واستخدم أداة <a href="https://play.google.com/store/apps/details?id=dev.conn.assetlinkstool" rel="external nofollow">Peter's Asset Link Tool</a> لإنشاء ملف الأصول assetlinks.json الصحيح الخاص بالتطبيق وإتاحته على <code>‎/.well-known/assetlinks.json</code> في النطاق الذي تحققت من صحته.
</p>

<h2>
	ختامًا
</h2>

<p>
	توفر صفحات الويب التقدميّة تجربة استخدام عالية الجودة ويُعدّ نشاط الويب الموثوق طريقة جديدة لتحقيق ذلك عند استيفاء الحد الأدنى من معايير الجودة.
</p>

<p>
	يُمكنك، إذا كنت في خطواتك الأولى لاستخدام صفحات الويب التقدميّة، قراءة <a href="https://web.dev/progressive-web-apps/" rel="external nofollow">إرشادات</a> إنشاء هذه الصفحات. أما إذا كنت مطورًا لهذه الصفحات فاستخدم أداة Lighthouse للتحقق من أن صفحاتك توافق معايير الجودة المطلوبة. بعدها، استخدم Bubblewrap و PWABuilder لإنشاء تطبيق أندرويد ومن ثم ارفع التطبيق المطور على قناة اختبار مغلقة وأقرنه بصفحات الويب التقدميّة باستخدام <a href="https://play.google.com/store/apps/details?id=dev.conn.assetlinkstool" rel="external nofollow">Peter's Asset Link Tool</a>
</p>

<p>
	في نهاية المطاف انقل تطبيقك المطور من قناة الاختبار إلى الاستخدام للعموم بنشره في متجر التطبيقات.
</p>

<p>
	ترجمة -وبتصرف- للمقال <a href="https://web.dev/using-a-pwa-in-your-android-app/" rel="external nofollow">Using a PWA in your Android app</a> للكاتب: André Cipriani Bandarra.
</p>

<h2>
	اقرأ أيضًا
</h2>

<ul>
<li>
		<a href="https://academy.hsoub.com/design/general/%D9%85%D8%A7-%D9%87%D9%8A-%D8%AA%D8%B7%D8%A8%D9%8A%D9%82%D8%A7%D8%AA-%D8%A7%D9%84%D9%88%D9%8A%D8%A8-%D8%A7%D9%84%D8%AA%D9%82%D8%AF%D9%85%D9%8A%D8%A9-%D9%88%D9%84%D9%85%D8%A7%D8%B0%D8%A7-%D9%8A%D8%AC%D8%A8-%D8%B9%D9%84%D9%89-%D8%A7%D9%84%D9%85%D8%B5%D9%85%D9%85%D9%8A%D9%86-%D8%A7%D9%84%D8%A7%D9%87%D8%AA%D9%85%D8%A7%D9%85-%D8%A8%D9%87%D8%A7%D8%9F-r450/" rel="">ما هي تطبيقات الويب التقدمية ولماذا يجب على المصممين الاهتمام بها؟</a>
	</li>
	<li>
		<a href="https://academy.hsoub.com/programming/general/%D8%AA%D8%B4%D8%BA%D9%8A%D9%84-%D8%AA%D8%B7%D8%A8%D9%8A%D9%82%D8%A7%D8%AA-%D8%A7%D9%84%D9%88%D9%8A%D8%A8-%D8%A7%D9%84%D8%AA%D9%82%D8%AF%D9%85%D9%8A%D8%A9-pwa-%D9%81%D9%8A-%D9%88%D8%B6%D8%B9-%D8%A7%D9%86%D9%82%D8%B7%D8%A7%D8%B9-%D8%A7%D9%84%D8%A7%D8%AA%D8%B5%D8%A7%D9%84-r1386/" rel="">تشغيل تطبيقات الويب التقدمية PWA في وضع انقطاع الاتصال</a>
	</li>
	<li>
		<a href="https://academy.hsoub.com/programming/general/%D9%86%D9%85%D8%A7%D8%B0%D8%AC-%D8%A7%D9%82%D8%AA%D8%B1%D8%A7%D8%AD%D8%A7%D8%AA-%D8%AA%D8%AB%D8%A8%D9%8A%D8%AA-%D8%AA%D8%B7%D8%A8%D9%8A%D9%82%D8%A7%D8%AA-%D8%A7%D9%84%D9%88%D9%8A%D8%A8-%D8%A7%D9%84%D8%AA%D9%82%D8%AF%D9%85%D9%8A%D8%A9-pwa-r1446/" rel="">نماذج اقتراحات تثبيت تطبيقات الويب التقدمية PWA </a>
	</li>
</ul>
]]></description><guid isPermaLink="false">1447</guid><pubDate>Fri, 28 Jan 2022 09:16:30 +0000</pubDate></item><item><title>&#x623;&#x633;&#x627;&#x633;&#x64A;&#x627;&#x62A; &#x62A;&#x62D;&#x62F;&#x64A;&#x62F; &#x627;&#x644;&#x62A;&#x643;&#x644;&#x641;&#x629; &#x627;&#x644;&#x645;&#x627;&#x62F;&#x64A;&#x629; &#x627;&#x644;&#x643;&#x627;&#x645;&#x644;&#x629; &#x644;&#x628;&#x646;&#x627;&#x621; &#x645;&#x648;&#x642;&#x639; &#x648;&#x64A;&#x628;</title><link>https://academy.hsoub.com/programming/general/%D8%A3%D8%B3%D8%A7%D8%B3%D9%8A%D8%A7%D8%AA-%D8%AA%D8%AD%D8%AF%D9%8A%D8%AF-%D8%A7%D9%84%D8%AA%D9%83%D9%84%D9%81%D8%A9-%D8%A7%D9%84%D9%85%D8%A7%D8%AF%D9%8A%D8%A9-%D8%A7%D9%84%D9%83%D8%A7%D9%85%D9%84%D8%A9-%D9%84%D8%A8%D9%86%D8%A7%D8%A1-%D9%85%D9%88%D9%82%D8%B9-%D9%88%D9%8A%D8%A8-r1437/</link><description><![CDATA[
<p><img src="https://academy.hsoub.com/uploads/monthly_2022_01/61df012780703_-------.png.171b1988d75dfb5050d222471f361fa4.png" /></p>

<p>
	يمكن ألّا تنفق شيئًا عند نشر موقع الويب الخاص بك أو يمكن أن تتخطى الميزانية المحددة، ولهذا يمكن أن تتساءل كم سيُكلفك بناء موقع ويب كامل؟ وكيف ستجني ما أنفقته؟
</p>

<p>
	سنستعرض في هذا المقال عملية تطوير موقع ويب بأكمله وحساب التكلفة المادية المتوقعة لكل خطوة، فيمكن ألّا يكون دخولك عالم الويب رخيصًا كما تعتقد.
</p>

<p>
	قبل الشروع في قراءة هذا المقال عليك أن تطلع على <a href="https://academy.hsoub.com/devops/servers/%D8%A7%D9%84%D9%81%D8%B1%D9%82-%D8%A8%D9%8A%D9%86-%D8%B5%D9%81%D8%AD%D8%A9-%D8%A7%D9%84%D9%88%D9%8A%D8%A8-%D9%88%D9%85%D9%88%D9%82%D8%B9-%D8%A7%D9%84%D9%88%D9%8A%D8%A8-%D9%88%D8%AE%D8%A7%D8%AF%D9%85-%D8%A7%D9%84%D9%88%D9%8A%D8%A8-%D9%88%D9%85%D8%AD%D8%B1%D9%83-%D8%A7%D9%84%D8%A8%D8%AD%D8%AB-r572/" rel="">الفرق بين صفحة الويب وخادم الويب</a> وغيرها من المصطلحات، كما عليك أن تكون على دراية بمفهوم <a href="https://academy.hsoub.com/devops/networking/%D9%85%D8%A7-%D9%87%D9%8A-%D8%A3%D8%B3%D9%85%D8%A7%D8%A1-%D8%A7%D9%84%D9%86%D8%B7%D8%A7%D9%82%D8%A7%D8%AA-%D9%81%D9%8A-%D8%B4%D8%A8%D9%83%D8%A9-%D8%A7%D9%84%D8%A5%D9%86%D8%AA%D8%B1%D9%86%D8%AA%D8%9F-r573/" rel="">أسماء النطاقات</a>.
</p>

<h2>
	البرمجيات
</h2>

<p>
	سنتعرف في الفقرات القادمة على بعض البرمجيات الأساسية التي تحتاجها لتطوير موقع ويب والتكلفة المادية لها.
</p>

<h3>
	محررات النصوص
</h3>

<p>
	من المرجح أنك تملك محرر نصوص مثل المفكرة Notepad في ويندوز أو جي-إدت Gedit في لينوكس أو محرر النصوص TextEdit في ماك أو إس. لكن استخدام محرر نصوص يلوّن الشيفرات ويتحقق من صحتها قواعديًا ويساعدك في تنظيمها سيريحك ويسهِّل تطوير المواقع.
</p>

<p>
	يمكنك الحصول على الكثير من محررات النصوص مجانًا مثل:
</p>

<ul>
<li>
		<a href="https://atom.io/" rel="external nofollow">Atom</a>.
	</li>
	<li>
		<a href="http://brackets.io/" rel="external nofollow">Brackets</a>.
	</li>
	<li>
		<a href="http://bluefish.openoffice.nl/" rel="external nofollow">Bluefish</a>.
	</li>
	<li>
		<a href="https://www.barebones.com/products/textwrangler/" rel="external nofollow">TextWrangler</a>.
	</li>
	<li>
		<a href="https://eclipse.org/" rel="external nofollow">Eclipse</a>.
	</li>
	<li>
		<a href="https://netbeans.org/" rel="external nofollow">Netbeans</a>.
	</li>
	<li>
		<a href="https://code.visualstudio.com/" rel="external nofollow">Visual Studio Code</a>.
	</li>
</ul>
<p>
	كما يمكنك اختبار <a href="https://www.sublimetext.com/" rel="external nofollow">Sublime Text</a> المدة التي تشاء لكنه سيظهر لك رسائل تشجعك على شراءه بينما يكلفك <a href="https://www.jetbrains.com/phpstorm/" rel="external nofollow">PhpStorm</a> ما بين 20 إلى 200 دولار وفقًا للخطة التي تحتاجها. يحصل المطورون الأفراد أو مطوري المشاريع مفتوحة المصدر على <a href="https://visualstudio.microsoft.com/vs/express/" rel="external nofollow">Visual Studio Express</a> مجانًا. وعادة ما تحصل على فترة تجريب مجانية للمحررات المدفوعة.
</p>

<p>
	ننصحك كبداية أن تجرب عدة محررات لتقرر ما يناسبك منها. كما ننصحك باستخدام محرر بسيط إن كنت ستكتب ملفات <a href="https://wiki.hsoub.com/HTML" rel="external">HTML</a> و<a href="https://wiki.hsoub.com/CSS" rel="external">CSS</a> و<a href="https://wiki.hsoub.com/JavaScript" rel="external">جافاسكربت</a> بسيطة.
</p>

<p>
	لا يعكس ثمن المحرر جودته بالضرورة، عليك أن تجرب هذا المحرر وتقرر بنفسك إن كان يلبي احتياجاتك. يعدّ محررًا Sublime Text رخيص الثمن لكنه يأتي مع الكثير من الإضافات المجانية التي توسّع قدراته كثيرًا.
</p>

<h3>
	محررات الصور
</h3>

<p>
	من المرجح أن يزوّدك نظام التشغيل الذي تستخدمه بمحرر أو مستعرض صور بسيط مثل Paint في ويندوز وبرنامج Eye of Gnome في أوبونتو وبرنامج Preview في ماك. وبالطبع فهي برمجيات محدودة نسبيًا وسرعان ما تحتاج إلى محررات صور أكثر قوة لإضافة الطبقات والتأثيرات والمجموعات.
</p>

<p>
	يمكن أن تكون هذه المحررات مجانية مثل <a href="https://www.gimp.org/" rel="external nofollow">GIMP</a> أو بتكلفة معقولة أقل من 100 دولار مثل <a href="https://www.paintshoppro.com/" rel="external nofollow">PaintShop Pro</a> أو بتكلفة عالية نسبيًا مثل <a href="https://www.adobe.com/products/photoshop.html" rel="external nofollow">أدوبي فوتوشوب Adobe Photoshop</a>.
</p>

<p>
	اختر أيًا من تلك المحررات فهي تقدم وظائف متشابهة. وبالرغم من أنّ بعضها يشمل الكثير من الميزات، لكنك لن تستخدمها كلها. اطلع على ا<a href="https://academy.hsoub.com/programming/workflow/%D9%85%D8%A7-%D9%87%D9%8A-%D8%A7%D9%84%D8%A3%D8%AF%D9%88%D8%A7%D8%AA-%D8%A7%D9%84%D9%85%D8%B3%D8%AA%D8%AE%D8%AF%D9%85%D8%A9-%D9%81%D9%8A-%D8%A8%D9%86%D8%A7%D8%A1-%D9%85%D9%88%D8%A7%D9%82%D8%B9-%D9%88%D9%8A%D8%A8%D8%9F-r1436/" rel="">لأدوات التي يستخدمها المطورون</a> الآخرون إن كنت ستتبادل المشاريع معهم في مرحلة ما. إذ يمكن لجميع المحررات تصدير المشاريع المنجزة على شكل ملفات بتنسيقات معيارية لكنها تخزّن المشاريع التي لا تزال تحت التطوير بتنسيقات خاصة. تتمتع معظم الصور على الإنترنت بحقوق نشر، لذا عليك التحقق من رخصة استخدام الصورة قبل استخدامها. تزوّدك بعض المواقع مثل <a href="https://pixabay.com/" rel="external nofollow">Pixabay</a> بصور تحمل الرخصة CC0 لذا يمكنك استخدامها وتعديلها ونشرها بشكلها المعدّل لأغراض تجارية.
</p>

<h2>
	محررات الوسائط
</h2>

<p>
	إن أردت <a href="https://academy.hsoub.com/programming/html/html5/%D8%A5%D8%B6%D8%A7%D9%81%D8%A9-%D9%85%D9%82%D8%A7%D8%B7%D8%B9-%D8%A7%D9%84%D9%81%D9%8A%D8%AF%D9%8A%D9%88-%D8%B9%D8%A8%D8%B1-%D8%A7%D9%84%D8%B9%D9%86%D8%B5%D8%B1-%D9%81%D9%8A-html5-r356/" rel="">إضافة مقاطع فيديو</a> أو مقاطع صوتية إلى موقعك، يمكنك تضمين خدمات ويب موجودة مثل يوتيوب YouTube أو ديلي موشن Dailymotion أو فيميو Vimeo أو تضمين مقاطع فيديو خاصة بك (تحقق من تكلفة عرض الحزمة التي سترد لاحقًا في المقال).
</p>

<p>
	يمكنك استخدام برامج مجانية للعمل مع المقاطع الصوتية (مثل <a href="https://www.audacityteam.org/" rel="external nofollow">Audacity</a> و<a href="https://www.wavosaur.com/" rel="external nofollow">Wavosaur</a>) أو مدفوعة بتكاليف يمكن أن تصل لمئات من الدولارات (مثل Sony Sound Forge وAdobe Audition). وكذلك الأمر مع محررات الفيديو إذ يمكنك استخدام المحررات مجانية مثل <a href="http://www.pitivi.org/" rel="external nofollow">PiTiVi</a> و<a href="https://www.openshot.org/" rel="external nofollow">OpenShot</a> <a href="https://academy.hsoub.com/devops/linux/%D9%85%D8%A7-%D9%87%D9%88-%D9%86%D8%B8%D8%A7%D9%85-%D8%A7%D9%84%D8%AA%D8%B4%D8%BA%D9%8A%D9%84-%D9%84%D9%8A%D9%86%D9%83%D8%B3%D8%9F-r451/" rel="">لنظام التشغيل لينوكس</a> وبرنامج <a href="https://www.apple.com/mac/imovie/" rel="external nofollow">iMovie</a> لنظام التشغيل ماك أو إس أو يمكنك استخدام محررات معتدلة التكلفة أقل من 100 دولار مثل Adobe Premiere Elements أو بتكلفة تصل إلى مئات الدولارات (مثل Adobe Premiere Pro وAvid Media Composer وFinal Cut Pro. وغالبًا ما يغطي محرر الفيديو الذي يأتي مع كاميرتك الرقمية كل احتياجاتك.
</p>

<h3>
	أدوات نشر المواقع
</h3>

<p>
	ستحتاج إلى وسيلة لرفع ملفات موقعك من القرص الصلب على حاسوبك إلى خادم الويب، لذلك تساعد بعض أدوات النشر مثل S)FTP client) أو RSync أو Git/GitHub في إنجاز الأمر.
</p>

<p>
	يحتوي كل نظام تشغيل على برنامج عميل S)FTP) كجزء من مدير الملفات مثل Windows Explorer في ويندوز وNautilus وهو مدير ملفات شائع في أنظمة التشغيل لينوكس وMac Finder في ماك أو إس. يختار المطورون عادة برامج S)FTP) مخصصة لاستعراض المجلدات الموجودة على الحاسوب أو الخادم بشكل متجاور وتخزين كلمات مرور الخادم. هناك العديد من الخيارات الموثوقة والمجانية إن أردت أن تثبّت برنامج عميل S)FTP) مثل <a href="https://filezilla-project.org/" rel="external nofollow">FileZilla</a> لكل المنصات و<a href="https://winscp.net/" rel="external nofollow">WinSCP</a> لنظام التشغيل ويندوز و<a href="https://cyberduck.io/" rel="external nofollow">Cyberduck</a> لكل من ويندوز وماك وغيرها الكثير.
</p>

<p>
	إنّ بروتوكول FTP غير آمن بطبيعته لذلك تأكد من استخدام SFTP وهي النسخة الآمنة المشفّرة من FTP التي تتعامل معها معظم مزودات الخدمة هذه الأيام افتراضيًا. يمكنك بالطبع استخدام تقنيات آمنة أخرى مثل Rsync مع <abbr title="Secure Shell | القشرة (أو الصَدَفة) الآمنة">SSH</abbr>.
</p>

<h3>
	المتصفحات
</h3>

<p>
	إما أن يكون لديك بالفعل متصفح أو يمكنك تحميل أي متصفح مجاني مثل فايرفوكس أو كروم.
</p>

<h2>
	الولوج إلى ويب
</h2>

<p>
	سنتعرف الآن على التجهيزات والخدمات الأساسية التي تحتاجها لدخول ويب.
</p>

<h3>
	حاسوب ومودم
</h3>

<p>
	يتطلب بناء ونشر موقع ويب إلى حاسوب بتكلفة تختلف بشدة وفقًا لميزانيك ومكان إقامتك. فإن أردت نشر موقع بسيط ستحتاج إلى حاسوب بسيط قادر على تشغيل محرر ومتصفح ويب وبالتالي ستكون تكلفته قليلة عند هذا المستوى. لكن إن أردت إنتاج تصاميم أكثر تعقيدًا لموقعك تضم صورًا مؤثرة أو أن تنتج مقاطع فيديو أو مقاطع صوتية فستحتاج إلى حاسوب أفضل.
</p>

<p>
	تحتاج أيضًا إلى رفع الملفات إلى خادم بعيد لذلك لا بدّ من وجود مودم Modem. يمكن لمزود خدمة الإنترنت <a href="https://ar.wikipedia.org/wiki/%D9%85%D8%B2%D9%88%D8%AF_%D8%AE%D8%AF%D9%85%D8%A9_%D8%A7%D9%84%D8%A5%D9%86%D8%AA%D8%B1%D9%86%D8%AA" rel="external nofollow">ISP</a> أن يمنحك اتصالًا بالإنترنت مقابل بضعة دولارات شهريًا ولكن يختلف الميزانية وفقًا لمكان إقامتك.
</p>

<h3>
	الولوج إلى مزود خدمة انترنت
</h3>

<p>
	تأكد من أنك تستخدم حزمة اتصال (أو حيز نطاق تراسلي) <a href="https://academy.hsoub.com/devops/networking/%D8%A7%D9%84%D8%B9%D9%88%D8%A7%D9%85%D9%84-%D8%A7%D9%84%D9%85%D8%A4%D8%AB%D8%B1%D8%A9-%D9%81%D9%8A-%D8%A3%D8%AF%D8%A7%D8%A1-%D8%A7%D9%84%D8%B4%D8%A8%D9%83%D8%A7%D8%AA-%D8%A7%D9%84%D8%AD%D8%A7%D8%B3%D9%88%D8%A8%D9%8A%D8%A9-r486/" rel="">bandwidth</a> كافي:
</p>

<ul>
<li>
		يمكن أن يكون الولوج إلى <a href="https://academy.hsoub.com/programming/php/laravel/%D9%83%D9%8A%D9%81-%D8%AA%D9%86%D8%B4%D8%A6-%D9%85%D8%B2%D9%88%D8%AF-%D8%AE%D8%AF%D9%85%D8%A9-service-provider-%D9%81%D9%8A-laravel-r326/" rel="">مزود الخدمة</a> عبر حزمة اتصال منخفضة ملائمًا لدعم موقع ويب بسيط يضم صورًا بأحجام معقولة ونصوصًا وبعض ملفات التنسيق CSS وبعض ملفات جافاسكريبت، وسيكلفك ذلك بضع عشرات من الدولارات شهريًا بما في ذلك أجرة المودم.
	</li>
	<li>
		ستحتاج في المقابل إلى حزمة اتصال عريضة مثل DSL أو خدمة الكابل أو الولوج عبر الألياف الضوئية (فايبر) إن أردت موقعًا أكبر يضم مئات الملفات، أو إن أردت تزويد متابعيك بملفات فيديو أو صوت بأحجام عالية. يمكن ألا يكلفك الأمر أكثر من كلفة الحزمة المنخفضة ويمكن أن تصل التكاليف إلى مئات الدولارات شهريًا لأغراض أكثر احترافية.
	</li>
</ul>
<h2>
	استضافة موقع ويب
</h2>

<p>
	نناقش في الفقرات القادمة ما تحتاجه من خدمات لرفع موقع على ويب وتكلفة هذه الخدمات.
</p>

<h3>
	مفهوم عرض حزمة الاستهلاك
</h3>

<p>
	تتعلق الكلفة التي تتقاضاها مزودات الخدمة لاستضافة موقعك بعرض الحزمة التي يستهلكها الموقع. يعتمد الأمر على عدد الأشخاص الذين يزورون موقعك وعدد روبوتات ويب التي تدخل إلى موقعك لتوثيقه خلال فترة زمنية معينة، بالإضافة إلى المساحة التخزينية التي تستهلكها ملفاتك. لهذا السبب يخزن الأشخاص مقاطع الفيديو الخاصة بهم ضمن خوادم تقدم خدمات مخصصة لهذا الأمر مثل يوتيوب وديلي موشن وفيميو. يمكن أن يقدم لك مزود الخدمة عرضًا يسمح بدخول عدة آلاف من المستخدمين يوميًا وبمقدار تبادل بيانات (عرض حزمة استهلاك) معقول، ولكن يجدر بك الانتباه إلى أن ما ذكرناه سيُفسَّر بصورة مختلفة من مزود خدمة استضافة إلى آخر. وكقاعدة أساسية توقع أن تكلفك استضافة موثوقة لاستخدام شخصي ما بين 10 إلى 50 دولار شهريًا.
</p>

<blockquote class="ipsQuote" data-ipsquote="">
	<div class="ipsQuote_citation">
		اقتباس
	</div>

	<div class="ipsQuote_contents ipsClearfix">
		<p>
			<strong>ملاحظة</strong>: لا شيء يُدعى "عرض حزمة استهلاك لا محدود". إن استهلكت حزمة ضخمة فتوقع أن تدفع مبلغًا ضخمًا.
		</p>
	</div>
</blockquote>

<h3>
	أسماء النطاقات
</h3>

<p>
	لا بد من شراء اسم نطاق خاص بك من خلال مزود خاص (شركة مُسجِّلة Registart أو مسجِّل)، ويمكن أن يكون مزود خدمة الاستضافة هو أيضًا مُسجّلًا (أي الشركة تقدم خدمة حجز النطاقات والاستضافة). سيكلّفك تسجيل اسم نطاق عادةً ما بين 5-15 دولار سنويًا، وتختلف هذه الكلفة للأسباب التالية:
</p>

<ul>
<li>
		<strong>التزامات محلية</strong>: اختيارك لأسماء نطاقات عليا تحمل اسم دولة (مثل <code>uk.</code>) أكثر تكلفة وتختلف من دولة لأخرى.
	</li>
	<li>
		<strong>الخدمات المرتبطة باسم النطاق</strong>: تزودك بعض الشركات المسجِّلة بخدمات مثل الحماية من الإزعاجات عن طريق حجب عنوانك البريدي وعنوان بريدك الإلكتروني خلف عناوينهم الخاصة. فلن يستسطع أحد الوصول إلى عنوانك البريد إلى عن طريق الشركة المسجلّة بينما تحجب بريدك الإلكتروني وفق آلية التقنيع التي يعتمدها المُسجِّل.
	</li>
</ul>
<h3>
	استضافة موقعك بنفسك أو باستخدام خدمات الاستضافة المدفوعة
</h3>

<p>
	بإمكانك <a href="https://academy.hsoub.com/apps/web/%D9%83%D9%8A%D9%81-%D8%AA%D9%86%D8%B4%D8%B1-%D8%B5%D9%81%D8%AD%D8%A9-%D8%A3%D9%88-%D9%85%D9%88%D9%82%D8%B9-%D9%88%D9%8A%D8%A8-%D9%82%D9%85%D8%AA-%D8%A8%D8%AA%D8%B5%D9%85%D9%8A%D9%85%D9%87-%D8%B9%D9%84%D9%89-%D8%A7%D9%84%D8%A5%D9%86%D8%AA%D8%B1%D9%86%D8%AA-r52/" rel="">نشر موقعك</a> بنفسك خطوة خطوة كأن تجهز قاعدة بيانات (عند الحاجة) ونظام إدارة المحتوى <a href="https://academy.hsoub.com/apps/web/10-%D9%85%D8%B9%D8%A7%D9%8A%D9%8A%D8%B1-%D9%84%D8%A7%D8%AE%D8%AA%D9%8A%D8%A7%D8%B1-%D9%86%D8%B8%D8%A7%D9%85-%D8%A5%D8%AF%D8%A7%D8%B1%D8%A9-%D8%A7%D9%84%D9%85%D8%AD%D8%AA%D9%88%D9%89-cms-r170/" rel="">CMS</a> مثل (ووردبريس <a href="https://academy.hsoub.com/apps/web/wordpress/" rel="">Wordpress</a> أو دوت كلير <a href="https://dotclear.org/" rel="external nofollow">Dotclear</a> أو <a href="https://www.spip.net/en_rubrique25.html" rel="external nofollow">spip</a> وغيرها) وترفع قوالب المحتويات الجاهزة أو قوالبك الخاصة.
</p>

<p>
	كما يمكنك استخدام بيئة التشغيل الخاصة بمزود الاستضافة مقابل 10-50 دولار شهريًا، أو أن تشترك مباشرة بمزود استضافة مخصص له نظام إدارة محتوى جاهز مثل ووردبريس Wordpress أو تمبلر <a href="https://www.tumblr.com/" rel="external nofollow">Tumblr</a> أو بلوغر <a href="https://www.blogger.com/" rel="external nofollow">Blogger</a>). لن يكلف هذا الأخير أي شيء حرفيًا، لكنك لن تكون قادرًا على التحكم الكامل بالقوالب وغيرها من الخيارات.
</p>

<h3>
	الاستضافة المجانية مقابل الاستضافة المدفوعة
</h3>

<p>
	يمكن أن يخطر في ببالك أنه لم عليك أن تدفع مقابل خدمة استضافة بالرغم من وجود العديد من عروض الاستضافة المجانية؟ إليك بعض المميزات للاسضافات المدفوعة:
</p>

<ul>
<li>
		لديك حرية أكبر عندما تدفع. سيكون موقعك ملكك، وبإمكانك نقله بسلاسة من مزود خدمة إلى آخر.
	</li>
	<li>
		يمكن أن يضيف مزودي الخدمة المجانية إعلانات إلى محتوى موقعك دون أن تتحكم بذلك.
	</li>
</ul>
<p>
	يمزج البعض بين المقاربتين السابقتين، إذ يستضيفون مثلًا المدونة الرئيسية على مزود استضافة مدفوعة وباسم نطاق مستقل وخاص بالكامل، بينما يرفعون المحتوى الأقل أهمية إلى مزود استضافة مجانية.
</p>

<h2>
	تصميم مواقع ويب والاستضافة الاحترافية عن طريق شركات خاصة
</h2>

<p>
	إن أردت موقع ويب احترافي فيمكن أن ترغب بتوكيل المهمة لوكالة خاصة وبالتالي ستتغير التكلفة بناء على عوامل عدة مثل:
</p>

<ul>
<li>
		هل الموقع بسيط مكون من عدة صفحات نصية؟ أم أنه أكثر تعقيدًا ويتكون من ألف صفحة مثلًا؟
	</li>
	<li>
		هل تريد تحديث محتواه بانتظام؟ أو سيكون موقع ويب ساكن.
	</li>
	<li>
		هل ينبغي ربط الموقع بمنظومة المعلومات الخاصة بشركتك لجمع محتوى معين (مثل البيانات الداخلية)؟
	</li>
	<li>
		هل تريد بعض الميزات الجديدة البرّاقة التي تمثل الموضة الحالية؟ حاليًا يطلب العملاء مواقع من صفحة واحدة ذات مظهر مركب.
	</li>
	<li>
		هل ترغب أن تتولى الوكالة أمر مشاكل المستخدمين أو حل مشاكل تتعلق بتجربة المستخدم <a href="https://academy.hsoub.com/design/user-experience/" rel="">UX</a>؟ كأن تضع لك استراتيجية لتشجيع المستخدمين أو تصميم تجربة لاختيار حل من بين عدة خيارات.
	</li>
</ul>
<p>
	فيما يتعلق بالاستضافة ستتغير التكلفة بحسب عدة عوامل منها:
</p>

<ul>
<li>
		هل تريد خوادم احتياطية في حال توقف الخادم الأساسي عن العمل؟
	</li>
	<li>
		هل تكفي وثوقية أداء 95% أم أنك تحتاج إلى 99% وخدمة مستمرة على مدار الساعة؟
	</li>
	<li>
		هل تريد خادمًا مخصصًا Dedicated Server عال المواصفات فائق التجاوب أم يكفيك خادم مشترك أبطأ؟
	</li>
</ul>
<p>
	اعتمادًا على إجاباتك على كل سؤال سيكلفك الموقع من بضع آلاف وحتى مئات آلاف الدولارات.
</p>

<p>
	اطلعنا في هذا المقال على التكلفة المادية لبناء موقع ويب في كل خطوة من خطوات بنائه حتى نشره، وحان الوقت لتبدأ <a href="https://academy.hsoub.com/design/tips/%D8%AB%D9%85%D8%A7%D9%86%D9%8A%D8%A9-%D9%86%D8%B5%D8%A7%D8%A6%D8%AD-%D9%84%D8%AA%D8%B5%D9%85%D9%8A%D9%85-%D9%85%D9%88%D8%A7%D9%82%D8%B9-%D8%A5%D9%84%D9%83%D8%AA%D8%B1%D9%88%D9%86%D9%8A%D8%A9-%D9%85%D8%AA%D9%88%D8%A7%D9%81%D9%82%D8%A9-%D9%85%D8%B9-%D8%A7%D9%84%D8%A3%D8%AC%D9%87%D8%B2%D8%A9-%D8%A7%D9%84%D9%85%D8%AD%D9%85%D9%88%D9%84%D8%A9-r459/" rel="">تصميم مواقع ويب</a> و<a href="https://academy.hsoub.com/freelance/productivity/%D8%A7%D9%84%D8%B9%D9%86%D8%A7%D9%8A%D8%A9-%D8%A8%D8%A8%D9%8A%D8%A6%D8%A9-%D8%B9%D9%85%D9%84-%D8%A7%D9%84%D8%B9%D8%A7%D9%85%D9%84-%D8%A7%D9%84%D9%85%D8%B3%D8%AA%D9%82%D9%84-r369/" rel="">إعداد بيئة العمل المناسبة لك</a>.
</p>

<p>
	ترجمة -وبتصرف- للمقال <a href="https://developer.mozilla.org/en-US/docs/Learn/Common_questions/How_much_does_it_cost" rel="external nofollow">How much does it cost to do something on the Web</a>.
</p>

<h2>
	اقرأ أيضًا
</h2>

<ul>
<li>
		<a href="https://academy.hsoub.com/programming/general/%D9%85%D9%81%D9%87%D9%88%D9%85-%D8%A7%D9%84%D8%B1%D9%88%D8%A7%D8%A8%D8%B7-%D8%A7%D9%84%D8%AA%D8%B4%D8%B9%D8%A8%D9%8A%D8%A9-%D9%81%D9%8A-%D9%85%D9%88%D8%A7%D9%82%D8%B9-%D8%A7%D9%84%D9%88%D9%8A%D8%A8-r1434/" rel="">مفهوم الروابط التشعبية في مواقع الويب</a>
	</li>
	<li>
		<a href="https://academy.hsoub.com/programming/general/%D9%85%D8%A7-%D9%87%D9%88-%D8%B9%D9%86%D9%88%D8%A7%D9%86-url-%D9%81%D9%8A-%D8%A7%D9%84%D9%88%D9%8A%D8%A8%D8%9F-r1435/" rel="">ما هو عنوان URL في الويب؟</a>
	</li>
	<li>
		<a href="https://academy.hsoub.com/programming/workflow/%D9%85%D8%A7-%D9%87%D9%8A-%D8%A7%D9%84%D8%A3%D8%AF%D9%88%D8%A7%D8%AA-%D8%A7%D9%84%D9%85%D8%B3%D8%AA%D8%AE%D8%AF%D9%85%D8%A9-%D9%81%D9%8A-%D8%A8%D9%86%D8%A7%D8%A1-%D9%85%D9%88%D8%A7%D9%82%D8%B9-%D9%88%D9%8A%D8%A8%D8%9F-r1436/" rel="">ما هي الأدوات المستخدمة في بناء مواقع ويب؟</a>
	</li>
	<li>
		<a href="https://academy.hsoub.com/programming/workflow/%D9%85%D8%A7-%D9%87%D9%8A-%D8%A3%D8%AF%D9%88%D8%A7%D8%AA-%D9%85%D8%B7%D9%88%D8%B1%D9%8A-%D8%A7%D9%84%D9%88%D9%8A%D8%A8-%D8%A7%D9%84%D9%85%D8%AF%D9%85%D8%AC%D8%A9-%D9%81%D9%8A-%D8%A7%D9%84%D9%85%D8%AA%D8%B5%D9%81%D8%AD%D8%A7%D8%AA%D8%9F-r1439/" rel="">ما هي أدوات مطوري الويب المدمجة في المتصفحات؟</a>
	</li>
</ul>
]]></description><guid isPermaLink="false">1437</guid><pubDate>Wed, 26 Jan 2022 17:00:00 +0000</pubDate></item><item><title>&#x646;&#x645;&#x627;&#x630;&#x62C; &#x627;&#x642;&#x62A;&#x631;&#x627;&#x62D;&#x627;&#x62A; &#x62A;&#x62B;&#x628;&#x64A;&#x62A; &#x62A;&#x637;&#x628;&#x64A;&#x642;&#x627;&#x62A; &#x627;&#x644;&#x648;&#x64A;&#x628; &#x627;&#x644;&#x62A;&#x642;&#x62F;&#x645;&#x64A;&#x629; PWA</title><link>https://academy.hsoub.com/programming/general/%D9%86%D9%85%D8%A7%D8%B0%D8%AC-%D8%A7%D9%82%D8%AA%D8%B1%D8%A7%D8%AD%D8%A7%D8%AA-%D8%AA%D8%AB%D8%A8%D9%8A%D8%AA-%D8%AA%D8%B7%D8%A8%D9%8A%D9%82%D8%A7%D8%AA-%D8%A7%D9%84%D9%88%D9%8A%D8%A8-%D8%A7%D9%84%D8%AA%D9%82%D8%AF%D9%85%D9%8A%D8%A9-pwa-r1446/</link><description><![CDATA[
<p><img src="https://academy.hsoub.com/uploads/monthly_2022_01/61f240fcd09a0_-------------------Android-Apps-Progressive-Web-Apps-Patterns-for-promoting-PWA-installation.png.c5f5ccae20f3d652cde55f2ad208a6bc.png" /></p>

<p>
	يُسهّل تثبيت <a href="https://academy.hsoub.com/programming/general/%D9%85%D8%AF%D8%AE%D9%84-%D8%A5%D9%84%D9%89-%D8%AA%D8%B7%D8%A8%D9%8A%D9%82%D8%A7%D8%AA-%D8%A7%D9%84%D9%88%D9%8A%D8%A8-%D8%A7%D9%84%D8%AA%D9%82%D8%AF%D9%85%D9%8A%D8%A9-pwa-r832/" rel="">تطبيقات الويب التقدميّة PWA</a> إيجاده واستخدامه، وعلى الرغم من ترويج المتصفح لتثبيت التطبيق إلا أن بعض المستخدمين لا يدركون أنه يُمكنهم تثبيته، ولذا من المفيد جدًا توفير تجربة داخل التطبيق نفسه للترويج لتثبيت التطبيق.
</p>

<p>
	لن تعرض هذه المقالة قائمة شاملة لجميع نماذج الاقتراح لتثبيت تطبيق الويب التقدمي، إلا أنها ستُقدّم نقطة الانطلاق لطرق الاقتراح المختلفة لا سيما أن الشيفرة التي تُشغّل تدفق التثبيت install flow هي نفسها مهما كان النموذج pattern أو النماذج المستخدمة.<br>
	يُمكن الرجوع إلى المقالة <a href="https://academy.hsoub.com/programming/javascript/%D8%AA%D9%88%D9%81%D9%8A%D8%B1-%D8%AA%D8%AC%D8%B1%D8%A8%D8%A9-%D8%AA%D8%AB%D8%A8%D9%8A%D8%AA-%D9%85%D8%AE%D8%B5%D8%B5%D8%A9-%D8%AF%D8%A7%D8%AE%D9%84-%D8%AA%D8%B7%D8%A8%D9%8A%D9%82-%D8%A7%D9%84%D9%88%D9%8A%D8%A8-%D8%A7%D9%84%D8%AA%D9%82%D8%AF%D9%85%D9%8A-pwa-r1445/" rel="">توفير تجربة تثبيت مخصصة داخل التطبيق</a> للحصول على توثيق هذه الشيفرة.
</p>

<p>
	يُبين الشكل التالي مثلًا زر تثبيت بسيط في تطبيق:
</p>

<p style="text-align: center;">
	<a class="ipsAttachLink ipsAttachLink_image" data-fileid="89743" href="https://academy.hsoub.com/uploads/monthly_2022_01/001install.png.a6643cb30009193e16268da551b8a8e1.png" rel=""><img alt="001install.png" class="ipsImage ipsImage_thumbnailed" data-fileid="89743" data-unique="2rynqfdga" src="https://academy.hsoub.com/uploads/monthly_2022_01/001install.png.a6643cb30009193e16268da551b8a8e1.png" style="width: 350px; height: auto;"></a>
</p>

<h2>
	أفضل ممارسات اقتراح تثبيت التطبيق
</h2>

<p>
	نعرض فيما يلي بعض أفضل الممارسات المُمكنة لاقتراح تثبيت التطبيق، وذلك بغض النظر عن نماذج الاقتراح المستخدمة في <a href="https://academy.hsoub.com/apps/web/%D9%83%D9%8A%D9%81-%D8%AA%D9%86%D8%B4%D8%B1-%D8%B5%D9%81%D8%AD%D8%A9-%D8%A3%D9%88-%D9%85%D9%88%D9%82%D8%B9-%D9%88%D9%8A%D8%A8-%D9%82%D9%85%D8%AA-%D8%A8%D8%AA%D8%B5%D9%85%D9%8A%D9%85%D9%87-%D8%B9%D9%84%D9%89-%D8%A7%D9%84%D8%A5%D9%86%D8%AA%D8%B1%D9%86%D8%AA-r52/" rel="">موقع الويب</a>:
</p>

<ul>
<li>
		لا تضع الاقتراح ضمن تدفق التثبيت بل خارجه. مثلًا: ضع عبارة الاقتراح أسفل <a href="https://academy.hsoub.com/design/user-experience/%D9%83%D9%8A%D9%81-%D8%AA%D8%B7%D9%88%D9%91%D8%B1-%D8%AA%D8%AC%D8%B1%D8%A8%D8%A9-%D8%AA%D8%B3%D8%AC%D9%8A%D9%84-%D8%AF%D8%AE%D9%88%D9%84-%D8%A7%D9%84%D9%85%D8%B3%D8%AA%D8%AE%D8%AF%D9%85-r441/" rel="">نموذج تسجيل الدخول</a> أي تحت زر الإرسال إذ أن استخدام الاقتراح بشكل مُشتت لانتباه المستخدم سيؤدي إلى تخفيض كل من استخدام التطبيق ومعايير التفاعل معه.
	</li>
	<li>
		يجب أن يتمكن المستخدم من إخفاء أو رفض الاقتراح بسهولة، مع ضرورة حفظ تفضيلات المستخدم عند قيامه بذلك لإعادة إظهار ترويج التثبيت حال حصول تغيير ما في سلوك المستخدم مثل تسجيله للدخول أو إتمامه لعملية شراء مثلًا.
	</li>
	<li>
		حاول الجمع بين أكثر من نموذج للترويج مع مراعاة عدم إغراق المستخدم أو إزعاجه مرارًا وتكرارًا بترويج التثبيت.
	</li>
	<li>
		لا تُظهر الاقتراح إلا بعد إطلاق حدث "قبل طلب التثبيت" `beforeinstallprompt`
	</li>
</ul>
<p>
	عند استيفاء معايير معينة ستُظهر <a href="https://academy.hsoub.com/programming/javascript/%D8%B9%D9%84%D8%A7%D9%82%D8%A9-%D8%AC%D8%A7%D9%81%D8%A7%D8%B3%D9%83%D8%B1%D9%8A%D8%A8%D8%AA-%D8%A8%D8%AA%D8%B7%D9%88%D8%B1-%D8%A7%D9%84%D8%A5%D9%86%D8%AA%D8%B1%D9%86%D8%AA-%D9%88%D8%A7%D9%84%D9%85%D8%AA%D8%B5%D9%81%D8%AD%D8%A7%D8%AA-r1310/" rel="">المتصفحات</a> ترويجًا تلقائيًا للمستخدم، مثلًا يعرض المتصفح Chrome زر التثبيت في الصندوق متعدد الاستخدام omnibox.
</p>

<p>
	يعرض الشكل التالي ترويج المتصفح للتثبيت على نظام سطح المكتب (يسار) وعلى الجوّال (يمين):
</p>

<p style="text-align: center;">
	<a class="ipsAttachLink ipsAttachLink_image" data-fileid="89744" href="https://academy.hsoub.com/uploads/monthly_2022_01/002desktop.png.cab6b11887a18ee2e01a6f7799c2ff82.png" rel=""><img alt="002desktop.png" class="ipsImage ipsImage_thumbnailed" data-fileid="89744" data-unique="4wt5nlhr4" src="https://academy.hsoub.com/uploads/monthly_2022_01/002desktop.png.cab6b11887a18ee2e01a6f7799c2ff82.png" style="width: 350px; height: auto;"></a>
</p>

<p>
	يعرض المتصفح Chrome في أندرويد الاقتراح ضمن شريط معلومات صغير. يُمكن حجب هذا السلوك باستخدام التابع "حجب السلوك الافتراضي" <code>preventDefault()‎</code> في الحدث "قبل طلب التثبيت" <code>beforeinstallprompt</code>، أما إذا لم يُستدع هذا التابع فسيُعرض الاقتراح للتطبيق (متوافقًا مع معايير التثبيت في أندرويد) عند أول زيارة للمستخدم للموقع وبعد حوالي تسعين يومًا أيضًا.
</p>

<h2>
	نماذج الاقتراح في واجهات التطبيق
</h2>

<p>
	يُمكن استخدام نماذج الاقتراح لمعظم أنواع صفحات الويب التقدميّة مع إظهارها ضمن أقسام واجهات التطبيق مثل لائحة التنقل site navigation والأشرطة banners، مع ضرورة الانتباه لسياق المستخدم الحالي بهدف عدم إزعاجه أو تشتيته.
</p>

<p>
	تُحقّق المواقع التي تُطلق ترويج التثبيت في الوقت المناسب أكبر عدد من عمليات التثبيت مع تجنبها مضايقة المستخدم غير المهتم بالتثبيت.
</p>

<h3>
	زر تثبيت بسيط
</h3>

<p>
	من أبسط نماذج <a href="https://academy.hsoub.com/design/user-experience/%D8%AA%D8%AD%D9%84%D9%8A%D9%84-%D8%AA%D8%AC%D8%B1%D8%A8%D8%A9-%D8%A7%D9%84%D9%85%D8%B3%D8%AA%D8%AE%D8%AF%D9%85-%D9%88%D9%86%D8%B5%D8%A7%D8%A6%D8%AD-%D9%84%D8%AA%D8%AD%D9%88%D9%8A%D9%84-%D8%A7%D9%84%D8%B2%D9%88%D8%A7%D8%B1-%D8%A5%D9%84%D9%89-%D8%B9%D9%85%D9%84%D8%A7%D8%A1-r678/" rel="">تجربة المستخدم UX</a> تضمين زر "التثبيت" Install أو "الحصول على التطبيق" Get app في المكان المناسب ضمن محتوى الويب. يجب التأكد من أن الزر لا يُعطّل وظائف هامة أخرى وأنه ليس ضمن مسار تفاعل المستخدم مع التطبيق. يُبين الشكل التالي مثالًا لزر بسيط:
</p>

<p style="text-align: center;">
	<a class="ipsAttachLink ipsAttachLink_image" data-fileid="89745" href="https://academy.hsoub.com/uploads/monthly_2022_01/003button.png.5040e8e94abf05b1b5b802e15431f1d5.png" rel=""><img alt="003button.png" class="ipsImage ipsImage_thumbnailed" data-fileid="89745" data-unique="gyww1poaz" src="https://academy.hsoub.com/uploads/monthly_2022_01/003button.png.5040e8e94abf05b1b5b802e15431f1d5.png" style="width: 500px; height: auto;"></a>
</p>

<h3>
	ترويسة ثابتة
</h3>

<p>
	يُمكن وضع زر التثبيت في ترويسة header الموقع، والتي تحوي عادًة العلامة التجارية للموقع والقوائم السريعة. يُمكن أن تكون الترويسة ثابتة <code>position:fixed</code> أم لا، وذلك وفق وظائف الموقع واحتياجات المستخدمين.
</p>

<p>
	يُبين الشكل التالي مثالًا لزر تثبيت في الترويسة:
</p>

<p style="text-align: center;">
	<a class="ipsAttachLink ipsAttachLink_image" data-fileid="89746" href="https://academy.hsoub.com/uploads/monthly_2022_01/004header.png.341217127faf143d54fc05f086bcc900.png" rel=""><img alt="004header.png" class="ipsImage ipsImage_thumbnailed" data-fileid="89746" data-unique="c98g6bso3" src="https://academy.hsoub.com/uploads/monthly_2022_01/004header.png.341217127faf143d54fc05f086bcc900.png" style="width: 500px; height: auto;"></a>
</p>

<p>
	يُسهّل استخدم ترويج التثبيت في الترويسة تجربة استخدام سهلة لاسيما للزبائن المعتادين على التعامل مع الموقع. يجب التأكد من أن عبارة الاقتراح الموضوعة في الترويسة لها الحجم المناسب وتبدو بأهمية أكبر من بقية محتوى الترويسة، مع التحقق من عدم تداخلها معه، ومع الإشارة لأهمية كل بيكسل في الترويسة عادًة.
</p>

<p>
	وفي جميع الأحوال يجب:
</p>

<ul>
<li>
		عدم إظهار زر التثبيت ما لم يُطلق الحدث <code>beforeinstallprompt</code>.
	</li>
	<li>
		تقييم أهمية تثبيت التطبيق للمستخدمين وبالتالي الاستهداف الانتقائي لهم وبحيث يتم الاقتراح للمستخدمين المحتملين فقط.
	</li>
	<li>
		استخدام الترويسة بكفاءة بحيث يُحقّق التوازن بين ترويج التثبيت وبقية الخيارات الهامة الواجب وضعها في الترويسة أيضًا.
	</li>
</ul>
<p>
	يُبين الشكل التالي زر تثبيت مخصص في الترويسة:
</p>

<p style="text-align: center;">
	<a class="ipsAttachLink ipsAttachLink_image" data-fileid="89747" href="https://academy.hsoub.com/uploads/monthly_2022_01/005CustomInstall.png.2628e9cff39c81b3ef6a9c0ba74a7b3a.png" rel=""><img alt="005CustomInstall.png" class="ipsImage ipsImage_thumbnailed" data-fileid="89747" data-unique="iy36rdidl" src="https://academy.hsoub.com/uploads/monthly_2022_01/005CustomInstall.png.2628e9cff39c81b3ef6a9c0ba74a7b3a.png" style="width: 350px; height: auto;"></a>
</p>

<h3>
	قائمة التنقل
</h3>

<p>
	تُعدّ قائمة التنقل navigation menu مناسبة جدًا للترويج لتثبيت التطبيق، لاسيما أن فتح المستخدم لهذه القائمة يدّل بوضوح على تفاعله مع تجربة التطبيق.
</p>

<p>
	يجب التأكد مما يلي:
</p>

<ul>
<li>
		تجنب تعطيل محتوى التنقل المهم وذلك بوضع الاقتراح في أسفل القائمة.
	</li>
	<li>
		العرض الموجز والملائم لأهمية التطبيق للمستخدم وماذا يستفيد المستخدم من تثبيته.
	</li>
</ul>
<p>
	يُبين الشكل التالي زر ترويج التثبيت في أسفل قائمة التنقل:
</p>

<p style="text-align: center;">
	<a class="ipsAttachLink ipsAttachLink_image" data-fileid="89748" href="https://academy.hsoub.com/uploads/monthly_2022_01/006navigation.png.b67eca4b3d837c0e2f325a07bef3be72.png" rel=""><img alt="006navigation.png" class="ipsImage ipsImage_thumbnailed" data-fileid="89748" data-unique="del0486bu" src="https://academy.hsoub.com/uploads/monthly_2022_01/006navigation.thumb.png.1407a2f78d3c0602f9d50023407bd213.png" style="width: 300px; height: auto;"></a>
</p>

<h3>
	صفحة الهبوط
</h3>

<p>
	تُعدّ <a href="https://academy.hsoub.com/design/general/9-%D9%85%D8%A8%D8%A7%D8%AF%D8%A6-%D9%84%D8%AA%D8%B5%D9%85%D9%8A%D9%85-%D8%B5%D9%81%D8%AD%D8%A9-%D9%87%D8%A8%D9%88%D8%B7-%D8%A7%D8%AD%D8%AA%D8%B1%D8%A7%D9%81%D9%8A%D8%A9-r74/" rel="">صفحة الهبوط landing page</a> من الأمكنة المناسبة لوضع ترويج التثبيت، إذ أنها تُستخدم أصلًا للترويج للمنتجات والخدمات المختلفة.
</p>

<p>
	بالطبع، يجب عرض أهداف الموقع أولًا ومن ثم اقتراح تثبيت التطبيق.
</p>

<p>
	يجب التأكد دومًا مما يلي:
</p>

<ul>
<li>
		إظهار الميزات الأكثر أهمية للتطبيق والتركيز على <a href="https://academy.hsoub.com/marketing/search-engine-optimisation/%D8%A7%D8%AE%D8%AA%D9%8A%D8%A7%D8%B1-%D8%A7%D9%84%D9%83%D9%84%D9%85%D8%A7%D8%AA-%D8%A7%D9%84%D9%85%D9%81%D8%AA%D8%A7%D8%AD%D9%8A%D8%A9-%D8%A7%D9%84%D9%85%D9%86%D8%A7%D8%B3%D8%A8%D8%A9-%D9%84%D9%85%D9%88%D9%82%D8%B9%D9%83-%D8%A7%D9%84%D8%A5%D9%84%D9%83%D8%AA%D8%B1%D9%88%D9%86%D9%8A-r492/" rel="">الكلمات المفتاحية</a> التي قادت المستخدمين لصفحة الهبوط.
	</li>
	<li>
		استخدام شيئًا ملفتًا للنظر مع توضيح قيمة وأهمية التطبيق.
	</li>
	<li>
		وضع الاقتراح في الأقسام التي يتصفحها المستخدمون ويمضون أغلب الوقت فيها .
	</li>
</ul>
<p>
	يُبين الشكل التالي مثالًا لترويج التثبيت على صفحة هبوط:
</p>

<p style="text-align: center;">
	<a class="ipsAttachLink ipsAttachLink_image" data-fileid="89749" href="https://academy.hsoub.com/uploads/monthly_2022_01/007landing.png.5aee31236665a117963d057b27b7486f.png" rel=""><img alt="007landing.png" class="ipsImage ipsImage_thumbnailed" data-fileid="89749" data-unique="wxwspxef1" src="https://academy.hsoub.com/uploads/monthly_2022_01/007landing.thumb.png.c9939082a02d19d70da729ab98c0153a.png" style="width: 300px; height: auto;"></a>
</p>

<h3>
	شريط التثبيت
</h3>

<p>
	تُعدّ أشرطة التثبيت installation banners مكانًا مناسبًا لوضع ترويج التثبيت لاسيما أن معظم المستخدمين تعاملوا معها سابقًا وبالتالي تكون تجربتها مألوفة لهم. يجب الانتباه أيضًا لعدم إزعاج أو تشتيت المستخدم عند استخدام الاقتراح على شريط التثبيت.
</p>

<p>
	يجب التأكد مما يلي:
</p>

<ul>
<li>
		<p>
			عدم إظهار الاقتراح ما لم يقم المستخدم بإظهار بعض الاهتمام بالموقع، فإذا أخفى المستخدم الشريط فلا يجب إظهاره ثانيًة ما لم يبرهن المستخدم على رفع مستوى تفاعله مع الموقع كأن يُسجل فيه أو يُكمل عملية شراء منه.
		</p>
	</li>
	<li>
		<p>
			تقديم الشرح الكافي والمختصر في الشريط لأهمية تثبيت التطبيق، كأن يُشار إلى المساحة البسيطة التي يُمكن أن يتطلبها التطبيق على الأنظمة المختلفة iOS / Android وأنه سيُثبت فورًا دون الحاجة لإعادة التوجيه لأي متجر.
		</p>
	</li>
</ul>
<p>
	يُبين الشكل التالي شريط قابل للإخفاء في أعلى الصفحة:
</p>

<p style="text-align: center;">
	<a class="ipsAttachLink ipsAttachLink_image" data-fileid="89750" href="https://academy.hsoub.com/uploads/monthly_2022_01/008installbanner.png.267e019189169d8662b265b25776de87.png" rel=""><img alt="008installbanner.png" class="ipsImage ipsImage_thumbnailed" data-fileid="89750" data-unique="rb90c5y6w" src="https://academy.hsoub.com/uploads/monthly_2022_01/008installbanner.thumb.png.e46ca695a033f6ae7a48677674caa0d4.png" style="width: 300px; height: auto;"></a>
</p>

<h3>
	واجهة مستخدم مؤقتة
</h3>

<p>
	تُعلّم الواجهة المؤقتة Temporary UI (مثل نموذج تصميم الشريط الخفيف <a href="https://material.io/components/snackbars/" rel="external nofollow">Snackbar</a>) المستخدم بإجراء ما وتسمح له بإتمامه بسهولة. يمتاز استخدام هذه الواجهة لترويج التثبيت بأنه لا يُقاطع تفاعل المستخدم الذي يُمكنه تجاهلها وبالتالي تُخفى الواجهة تلقائيًا.
</p>

<p>
	يُبين الشكل التالي استخدام واجهة مؤقتة لإظهار إمكانية التثبيت:
</p>

<p style="text-align: center;">
	<a class="ipsAttachLink ipsAttachLink_image" data-fileid="89751" href="https://academy.hsoub.com/uploads/monthly_2022_01/009snackbar.png.e199cc5ceecff5054bcf1fa54dd47c76.png" rel=""><img alt="009snackbar.png" class="ipsImage ipsImage_thumbnailed" data-fileid="89751" data-unique="d0drqmabf" src="https://academy.hsoub.com/uploads/monthly_2022_01/009snackbar.png.e199cc5ceecff5054bcf1fa54dd47c76.png" style="width: 400px; height: auto;"></a>
</p>

<p>
	يُستحسن عرض الواجهة المؤقتة بعد التأكد من تفاعل المستخدم مع التطبيق، إذ يؤدي ظهور هذه الواجهة حال تحميل التطبيق أو خارج سياق تجربة الاستخدام إلى إرباك المستخدم الذي سيلجأ، بعدها، لرفض كل ما يظهر له. على الأخص، لا يجب إظهار الواجهة المؤقته للمستخدمين الجدد قبل الحصول على مؤشرات اهتمامهم بالتطبيق كتكرار الزيارات أو تسجيل الدخول.
</p>

<p>
	يجب التأكد مما يلي:
</p>

<ul>
<li>
		عرض الواجهة المؤقتة لفترة تتراوح بين 4 و 7 ثوانٍ لإتاحة الوقت الكافي للمستخدمين للتفاعل معها دون أي إعاقة لعملهم.
	</li>
	<li>
		تجنب عرض الواجهة المؤقتة على واجهات مؤقتة أخرى مثل الأشرطة banners.
	</li>
	<li>
		عدم استخدام الواجهات المؤقتة قبل التأكد من اهتمام المستخدم مثل تكراره للزيارات أو تسجيله في الموقع أو أي تفاعل مشابهه مع الموقع.
	</li>
</ul>
<p>
	يُبين الشكل التالي استخدام واجهة مؤقته لإظهار إمكانية التثبيت:
</p>

<p style="text-align: center;">
	<a class="ipsAttachLink ipsAttachLink_image" data-fileid="89752" href="https://academy.hsoub.com/uploads/monthly_2022_01/010snackbar2.png.cbe83b07fdbd30eb97f6ecac9fcb5a35.png" rel=""><img alt="010snackbar2.png" class="ipsImage ipsImage_thumbnailed" data-fileid="89752" data-unique="pvz7j1igw" src="https://academy.hsoub.com/uploads/monthly_2022_01/010snackbar2.png.cbe83b07fdbd30eb97f6ecac9fcb5a35.png" style="width: 350px; height: auto;"></a>
</p>

<h2>
	بعد التفاعل
</h2>

<p>
	يُعدّ إنهاء المستخدم لعملية تفاعل فرصة مناسبة لترويج التثبيت. مثلًا: بعد إتمامه لعملية شراء على <a href="https://academy.hsoub.com/design/general/%D8%AF%D9%84%D9%8A%D9%84%D9%83-%D9%84%D8%AA%D8%B5%D9%85%D9%8A%D9%85-%D9%85%D8%AA%D8%AC%D8%B1-%D9%88%D9%85%D9%88%D9%82%D8%B9-%D8%AA%D8%AC%D8%A7%D8%B1%D8%A9-%D8%A5%D9%84%D9%83%D8%AA%D8%B1%D9%88%D9%86%D9%8A%D8%A9-%D8%B9%D9%84%D9%89-%D8%B4%D8%A8%D9%83%D8%A9-%D8%A7%D9%84%D8%A5%D9%86%D8%AA%D8%B1%D9%86%D8%AA-r439/" rel="">موقع تجارة الكترونية</a> حيث يدل ذلك على اهتمام المستخدم بمحتوى الموقع وبأنه سيتفاعل مع خدماته مرًة أخرى.
</p>

<p>
	يُبين الشكل التالي إظهار ترويج تثبيت بعد إتمام المستخدم لعملية شراء:
</p>

<p style="text-align: center;">
	<a class="ipsAttachLink ipsAttachLink_image" data-fileid="89753" href="https://academy.hsoub.com/uploads/monthly_2022_01/011conversion.png.13efe7dcf1b634b762e059ce83994c26.png" rel=""><img alt="011conversion.png" class="ipsImage ipsImage_thumbnailed" data-fileid="89753" data-unique="gqxxnj36p" src="https://academy.hsoub.com/uploads/monthly_2022_01/011conversion.png.13efe7dcf1b634b762e059ce83994c26.png" style="width: 400px; height: auto;"></a>
</p>

<h3>
	إتمام تسلسل تنقل في الموقع أو الخروج منه
</h3>

<p>
	من المناسب إظهار ترويج التثبيت بعد انتهاء المستخدم من عملية معينة تستلزم مجموعة تنقلات في الموقع كعمليات الشراء أو الحجز.
</p>

<p>
	يجب التأكد مما يلي:
</p>

<ul>
<li>
		تضمين الاقتراح المناسب طبقًا لارتباط التطبيق بالعمليات المُنفذّة من قبل المستخدم والمحتمل استفادتهم من التطبيق.
	</li>
	<li>
		إظهار العروض المتاحة بشكل واضح.
	</li>
	<li>
		إبعاد الاقتراح عن تسلسل عمليات المستخدم اللازمة لإتمام عملية تحويل مما قد يؤثر سلبًا على إتمامه للعملية. لاحظ في المثال التالي وضع عبارة طلب الدفع من المستخدم أعلى إعلان ترويج التثبيت:
	</li>
</ul>
<p style="text-align: center;">
	<a class="ipsAttachLink ipsAttachLink_image" data-fileid="89754" href="https://academy.hsoub.com/uploads/monthly_2022_01/012promotion.png.95c3414fa28c2cc7d18c834b4af8a934.png" rel=""><img alt="012promotion.png" class="ipsImage ipsImage_thumbnailed" data-fileid="89754" data-unique="lpadp4nan" src="https://academy.hsoub.com/uploads/monthly_2022_01/012promotion.thumb.png.09d4b7d20cb1159656bad0d50cb5c9f5.png" style="width: 300px; height: auto;"></a>
</p>

<h3>
	تسلسل التسجيل والدخول والخروج
</h3>

<p>
	يُعدّ الاقتراح في هذه الحالات حالة خاصة من نمط الاقتراح بعد إتمام تسلسل تنقل إلا أنه يُمكن أن يكون أكثر وضوحًا.
</p>

<p>
	يفتح المستخدمون المهتمون بالموقع صفحات التسجيل Sign up والدخول Sign in والخروج Sign out عادًة وحيث أُظهرت أهمية تثبيت التطبيق لهم سابقًا. علاوًة على ذلك، لا تحوي هذه الصفحات عادًة محتوى مفيد ولذا يكون من المناسب وضع الاقتراح فيها لاسيما أنه لن يعرقل تنقلات المستخدم.
</p>

<p>
	يجب التأكد مما يلي:
</p>

<ul>
<li>
		تجنب تعطيل تنقلات المستخدم داخل نموذج التسجيل لاسيما إذا احتوى على عدة خطوات إذ يكون من الأجدر انتظار المستخدم لغاية إتمامه لعملية التسجيل.
	</li>
	<li>
		اقتراح ميزات التطبيق المناسبة للمستخدمين المسجلين.
	</li>
	<li>
		وضع زر ترويج إضافي في صفحة تسجيل الدخول للتطبيق.
	</li>
</ul>
<p>
	يُبين الشكل التالي زر تثبيت مخصص في صفحة التسجيل:
</p>

<p style="text-align: center;">
	<a class="ipsAttachLink ipsAttachLink_image" data-fileid="89755" href="https://academy.hsoub.com/uploads/monthly_2022_01/013signup.png.003f2485cffe5dfa5721a14be9f91509.png" rel=""><img alt="013signup.png" class="ipsImage ipsImage_thumbnailed" data-fileid="89755" data-unique="rxe1fw00b" src="https://academy.hsoub.com/uploads/monthly_2022_01/013signup.thumb.png.cd9bc4c8cbd194db844293e679313b56.png" style="width: 300px; height: auto;"></a>
</p>

<h2>
	نماذج الاقتراح المُضمّنة
</h2>

<p>
	تدمج نماذج الاقتراح المُضمّنة Inline promotional patterns عروض الاقتراح مع محتوى الموقع، مما يجعل الاقتراح فيه أكثر ملائمة من وضعه في واجهات المستخدم. وبشكل عام يجب المقايضة والموازنة بين إظهار الاقتراح بما يكفي ليُلاحظه المستخدمون المهتمون والإكثار من إظهاره مما يؤدي لتردي جودة تجربة المستخدم.
</p>

<h3>
	خلال نشر المحتوى
</h3>

<p>
	يُمكن إظهار الاقتراح ما بين عمليات نشر المحتوى In-feed الجديد مثل المقالات الجديدة أو بطاقات المعلومات.
</p>

<p>
	يجب التركيز على ميزات ووظائف التطبيق المفيدة للمستخدمين لاسيما أن الهدف هو التوضيح للمستخدمين كيفية الوصول للمحتوى المفيد لهم بسهولة.
</p>

<p>
	يجب التأكد مما يلي:
</p>

<ul>
<li>
		الحدّ قدر الإمكان من تكرار الاقتراح لتجنب إزعاج المستخدمين.
	</li>
	<li>
		منح المستخدمين إمكانية رفض الاقتراح.
	</li>
	<li>
		حفظ تفضيلات المستخدم (رفضه للترويج).
	</li>
</ul>
<p>
	يُبين الشكل التالي إظهار ترويج خلال تغذية المحتوى:
</p>

<p style="text-align: center;">
	<a class="ipsAttachLink ipsAttachLink_image" data-fileid="89756" href="https://academy.hsoub.com/uploads/monthly_2022_01/014feed.png.f2f597f6af3b2e657856a75ca0b96214.png" rel=""><img alt="014feed.png" class="ipsImage ipsImage_thumbnailed" data-fileid="89756" data-unique="qyphotayp" src="https://academy.hsoub.com/uploads/monthly_2022_01/014feed.thumb.png.147f3f03fc55d7f936fe7fb83b9ddb04.png" style="width: 300px; height: auto;"></a>
</p>

<p>
	ترجمة -وبتصرف- للمقال <a href="https://web.dev/promote-install/" rel="external nofollow">Patterns for promoting PWA installation</a> للمؤلفين: Penny McLachlan و Mustafa Kurtuldu.
</p>

<h2>
	اقرأ أيضًا
</h2>

<ul>
<li>
		<a href="https://academy.hsoub.com/design/general/%D9%85%D8%A7-%D9%87%D9%8A-%D8%AA%D8%B7%D8%A8%D9%8A%D9%82%D8%A7%D8%AA-%D8%A7%D9%84%D9%88%D9%8A%D8%A8-%D8%A7%D9%84%D8%AA%D9%82%D8%AF%D9%85%D9%8A%D8%A9-%D9%88%D9%84%D9%85%D8%A7%D8%B0%D8%A7-%D9%8A%D8%AC%D8%A8-%D8%B9%D9%84%D9%89-%D8%A7%D9%84%D9%85%D8%B5%D9%85%D9%85%D9%8A%D9%86-%D8%A7%D9%84%D8%A7%D9%87%D8%AA%D9%85%D8%A7%D9%85-%D8%A8%D9%87%D8%A7%D8%9F-r450/" rel="">ما هي تطبيقات الويب التقدمية ولماذا يجب على المصممين الاهتمام بها؟</a>
	</li>
	<li>
		<a href="https://academy.hsoub.com/programming/general/%D8%AA%D8%B4%D8%BA%D9%8A%D9%84-%D8%AA%D8%B7%D8%A8%D9%8A%D9%82%D8%A7%D8%AA-%D8%A7%D9%84%D9%88%D9%8A%D8%A8-%D8%A7%D9%84%D8%AA%D9%82%D8%AF%D9%85%D9%8A%D8%A9-pwa-%D9%81%D9%8A-%D9%88%D8%B6%D8%B9-%D8%A7%D9%86%D9%82%D8%B7%D8%A7%D8%B9-%D8%A7%D9%84%D8%A7%D8%AA%D8%B5%D8%A7%D9%84-r1386/" rel="">تشغيل تطبيقات الويب التقدمية PWA في وضع انقطاع الاتصال</a>
	</li>
	<li>
		<a href="https://academy.hsoub.com/programming/general/%D8%B4%D8%B1%D8%AD-%D9%85%D9%84%D9%81-%D8%A7%D9%84%D8%A8%D9%8A%D8%A7%D9%86-manifest-%D9%84%D8%AA%D8%B7%D8%A8%D9%8A%D9%82-%D8%A7%D9%84%D9%88%D9%8A%D8%A8-%D8%A7%D9%84%D8%AA%D9%82%D8%AF%D9%85%D9%8A-pwa-r1385/" rel="">شرح ملف البيان manifest لتطبيق الويب التقدمي PWA</a>
	</li>
	<li>
		<a href="https://academy.hsoub.com/programming/general/%D8%AA%D9%87%D9%8A%D8%A6%D8%A9-%D8%AA%D8%B7%D8%A8%D9%8A%D9%82%D8%A7%D8%AA-%D8%A7%D9%84%D9%88%D9%8A%D8%A8-%D8%A7%D9%84%D8%AA%D9%82%D8%AF%D9%85%D9%8A%D8%A9-pwa-%D9%84%D8%A7%D8%B3%D8%AA%D8%AE%D8%AF%D8%A7%D9%85%D9%87%D8%A7-%D9%83%D8%AA%D8%B7%D8%A8%D9%8A%D9%82%D8%A7%D8%AA-%D8%A3%D9%86%D8%AF%D8%B1%D9%88%D9%8A%D8%AF-r1447/" rel="">تهيئة تطبيقات الويب التقدمية PWA لاستخدامها كتطبيقات أندرويد</a>
	</li>
</ul>
]]></description><guid isPermaLink="false">1446</guid><pubDate>Tue, 25 Jan 2022 16:00:00 +0000</pubDate></item><item><title>&#x623;&#x633;&#x627;&#x633;&#x64A;&#x627;&#x62A; &#x639;&#x646;&#x648;&#x627;&#x646; URL &#x648;&#x623;&#x646;&#x648;&#x627;&#x639;&#x647;</title><link>https://academy.hsoub.com/programming/general/%D8%A3%D8%B3%D8%A7%D8%B3%D9%8A%D8%A7%D8%AA-%D8%B9%D9%86%D9%88%D8%A7%D9%86-url-%D9%88%D8%A3%D9%86%D9%88%D8%A7%D8%B9%D9%87-r1435/</link><description><![CDATA[
<p><img src="https://academy.hsoub.com/uploads/monthly_2022_01/61ded7b307d10_----URL---.png.5b3555f2d20f36ed09291e27d741be3c.png" /></p>

<p>
	يُعد عنوان URL بالإضافة إلى النص التشعبي <a href="https://wiki.hsoub.com/HTML" rel="external">Hypertext</a> وبروتوكول <a href="https://academy.hsoub.com/programming/general/%D9%85%D8%AF%D8%AE%D9%84-%D8%A5%D9%84%D9%89-http-r73/" rel="">HTTP</a> أحد المفاهيم المفتاحية للويب فهو الآلية التي تستخدمها المتصفحات <a href="https://ar.wikipedia.org/wiki/%D9%85%D8%AA%D8%B5%D9%81%D8%AD_%D9%88%D9%8A%D8%A8" rel="external nofollow">browsers</a> للوصول أي مورد موجود في الويب.
</p>

<p>
	عنوان URL هو مجرّد عنوان فريد لمورد على الويب، نظريًا يدل كل عنوان URL صحيح على مورد فريد ومحدد كصفحة HTML أو ملف CSS أو صورة أو غيرها من الموارد، ولكن في واقع هناك بعض الاستثناءات، وأكثرها شيوعًا عنوان URL يشير إلى مورد لم يعد موجودًا أو تغيّر موقعه. وطالما أن المورد يُمثّل بعنوان URL والخادم هو من يتعامل مع عنوان URL فلذلك تقع على عاتق مالك الخادم مهمة إدارة الموارد وعناوين URL المرتبطة بها بعناية.
</p>

<p>
	سنتعرف في هذا المقال على تفاصيل عنوان URL وكيفية عمل هذه العناوين على الويب.
</p>

<p>
	ننصحك قبل الشروع في إكمال قراءة المقال أن تطلع على مقال <a href="https://academy.hsoub.com/devops/networking/%D9%83%D9%8A%D9%81-%D8%AA%D8%B9%D9%85%D9%84-%D8%B4%D8%A8%D9%83%D8%A9-%D8%A7%D9%84%D8%A5%D9%86%D8%AA%D8%B1%D9%86%D8%AA%D8%9F-r571/" rel="">كيف تعمل شبكة الإنترنت؟</a> وأن يكون <a href="https://academy.hsoub.com/programming/general/%D9%85%D9%81%D9%87%D9%88%D9%85-%D8%A7%D9%84%D8%B1%D9%88%D8%A7%D8%A8%D8%B7-%D8%A7%D9%84%D8%AA%D8%B4%D8%B9%D8%A8%D9%8A%D8%A9-%D9%81%D9%8A-%D9%85%D9%88%D8%A7%D9%82%D8%B9-%D8%A7%D9%84%D9%88%D9%8A%D8%A8-r1434/" rel="">مفهوم الروابط التشعبية</a> واضحًا بالنسبة لك.
</p>

<h2>
	تشريح عنوان URL
</h2>

<p>
	إليك بعض الأمثلة عن عناوين URL:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_9843_9" style="">
<span class="pln">https</span><span class="pun">:</span><span class="com">//developer.mozilla.org</span><span class="pln">
https</span><span class="pun">:</span><span class="com">//developer.mozilla.org/en-US/docs/Learn/</span><span class="pln">
https</span><span class="pun">:</span><span class="com">//developer.mozilla.org/en-US/search?q=URL</span></pre>

<p>
	يمكن كتابة أيًا من تلك العناوين في شريط العنوان في <a href="https://academy.hsoub.com/programming/javascript/%D8%A3%D9%81%D8%B9%D8%A7%D9%84-%D8%A7%D9%84%D9%85%D8%AA%D8%B5%D9%81%D8%AD-%D8%A7%D9%84%D8%A7%D9%81%D8%AA%D8%B1%D8%A7%D8%B6%D9%8A%D8%A9-%D9%84%D9%84%D8%A3%D8%AD%D8%AF%D8%A7%D8%AB-%D9%88%D8%B6%D8%A8%D8%B7%D9%87%D8%A7-%D8%B9%D8%A8%D8%B1-%D8%AC%D8%A7%D9%81%D8%A7%D8%B3%D9%83%D8%B1%D8%A8%D8%AA-r1143/" rel="">المتصفح</a> لتحميل الصفحة أو المورد المرتبط به.
</p>

<p>
	يتكون عنوان URL من أجزاء مختلفة بعضها إلزامي وبعضها اختياري. لاحظ الأجزاء المظللة في العنوان التالي والتي تُعد الأكثر أهمية في عنوان URL:
</p>

<p style="text-align: center;">
	<a class="ipsAttachLink ipsAttachLink_image" data-fileid="89015" href="https://academy.hsoub.com/uploads/monthly_2022_01/01_url_full.png.330139eb8a5233cabaa3f8469425d201.png" rel=""><img alt="01_url_full.png" class="ipsImage ipsImage_thumbnailed" data-fileid="89015" data-unique="sccpe83wa" src="https://academy.hsoub.com/uploads/monthly_2022_01/01_url_full.thumb.png.048f55b30b67f2deb67d322413ad52ae.png"></a>
</p>

<p>
	لتوضيح الفكرة يمكن أن نشبّه عنوان URL بعنوان بريدي نمطي، إذ يمثل المخطط Scheme الخدمة البريدية التي تريد استخدامها، ويمثل اسم النطاق Domain name اسم المدينة أو البلدة، وستعمل المنفذ Port عمل الرمز البريدي، وسيمثل المسار Path البناء الذي ينبغي تسليم البريد إليه. أما المعاملات Parameters فستمثل أي معلومات إضافية كرقم الشقة وستمثل المرساة Anchor مستلم الرسالة الفعلي الذي وجَّهت رسالتك إليه.
</p>

<blockquote class="ipsQuote" data-ipsquote="">
	<div class="ipsQuote_citation">
		اقتباس
	</div>

	<div class="ipsQuote_contents ipsClearfix">
		<p>
			<strong>ملاحظة</strong>: هنالك بعض الأجزاء والقواعد الإضافية لعناوين URL، ولكن لا علاقة لمستخدمي الويب أو مطوريه بها. لذلك لا تهتم لأمرها لأنك لن تحتاجها لتبني وتستخدم عناوين URL صحيحة.
		</p>
	</div>
</blockquote>

<h3>
	بروتوكول عنوان URL
</h3>

<p style="text-align: center;">
	<a class="ipsAttachLink ipsAttachLink_image" data-fileid="89016" href="https://academy.hsoub.com/uploads/monthly_2022_01/02_url_scheme.png.9ede789ec164e3579f66c4155eec304b.png" rel=""><img alt="02_url_scheme.png" class="ipsImage ipsImage_thumbnailed" data-fileid="89016" data-unique="6art5c1gz" src="https://academy.hsoub.com/uploads/monthly_2022_01/02_url_scheme.png.9ede789ec164e3579f66c4155eec304b.png" style="width: 500px; height: auto;"></a>
</p>

<p>
	وهو القسم الأول من URL ويشير إلى البروتوكول الذي ينبغي استخدامه لطلب مورد معين من الخادم (البروتوكول هو طريقة لإعداد آلية لتبادل البيانات ونقلها عبر شبكة من الحواسيب). يُستخدم عادة برتوكولي HTTP و HTTPS (النسخة الآمنة) في مواقع الويب ولا بد من مخاطبة صفحات الويب باستخدام أحدهما. مع ذلك تدرك المتصفحات تمامًا كيف تتعامل مع بروتوكولات Schemes أخرى مثل <code>:mailto</code> (لفتح واجهة بريد إلكتروني) فلا تتفاجأ إن رأيت بروتوكولات أخرى.
</p>

<h3>
	التصريح Authority
</h3>

<p style="text-align: center;">
	<a class="ipsAttachLink ipsAttachLink_image" data-fileid="89017" href="https://academy.hsoub.com/uploads/monthly_2022_01/03_url_authority.png.2cb47e86c734ac0622997930711080a3.png" rel=""><img alt="03_url_authority.png" class="ipsImage ipsImage_thumbnailed" data-fileid="89017" data-unique="gffk0yt6v" src="https://academy.hsoub.com/uploads/monthly_2022_01/03_url_authority.thumb.png.096b46dc9f3f71f3bf74d98ee8a9e651.png" style="width: 500px; height: auto;"></a>
</p>

<p>
	يأتي بعد البروتوكول التصريح ويفصل بينهما النمط <code>//:</code>. يتضمن التصريح في حال وجوده اسم النطاق (<code>www.example.com</code> مثلًا) ورقم المنفذ (<code>80</code> مثلًا) يفصل بينهما الرمز <code>:</code>.
</p>

<ul>
<li>
		يشير <a href="https://academy.hsoub.com/devops/servers/dns/%D9%86%D8%B5%D8%A7%D8%A6%D8%AD-%D8%A3%D8%B3%D8%A7%D8%B3%D9%8A%D8%A9-%D8%AA%D8%B2%D9%88%D9%91%D9%8E%D8%AF-%D8%A8%D9%87%D8%A7-%D9%82%D8%A8%D9%84-%D8%B4%D8%B1%D8%A7%D8%A1-%D9%86%D8%B7%D8%A7%D9%82-%D8%AC%D8%AF%D9%8A%D8%AF-r447/" rel="">النطاق</a> Domain إلى خادم الويب الذي يُرسل إليه الطلب ويكون عادة على شكل اسم، كما يمكن استخدام عنوان آي بي لكن استخدامه نادر وغير ملائم في معظم الأحيان.
	</li>
	<li>
		يشير المنفذ Port إلى البوابة المستخدمة للوصول إلى المورد. يُحذف المنفذ عادة عند استخدام الخادم المنافذ المعيارية للبروتوكول HTTP، إذ يستخدم المنفذ 80 لبروتوكول HTTP والمنفذ 443 لبروتوكول HTTPS عند منح الإذن بالوصول إلى المورد. ما عدا ذلك لا بد من كتابة المنفذ المستخدم.
	</li>
</ul>
<blockquote class="ipsQuote" data-ipsquote="">
	<div class="ipsQuote_citation">
		اقتباس
	</div>

	<div class="ipsQuote_contents ipsClearfix">
		<p>
			<strong>ملاحظة</strong>: تفصل النقطتين المتعامدتين <code>:</code> في النمط <code>//:</code> بين البروتوكول والقسم الذي يليه من URL بينما يشير النمط <code>//</code> أن القسم التالي هو حصرًا التصريح.
		</p>
	</div>
</blockquote>

<p>
	في بعض الحالات لا يستخدم URL قسم التصريح كما هو الحال في واجهات البريد الإلكتروني (<code>mailto:foobar</code>). إذ يحتوي URL مخططًا فقط دون تصريح، لذلك لن تجد النمط <code>//</code>، وإنما ستجد فقط النقطتين المتعامدتين التي تعمل فقط كفاصل بين المخطط وعنوان البريد الإلكتروني.
</p>

<h3>
	المسار إلى مورد
</h3>

<p style="text-align: center;">
	<a class="ipsAttachLink ipsAttachLink_image" data-fileid="89018" href="https://academy.hsoub.com/uploads/monthly_2022_01/04_url_path.png.2aca46610e156959f8eb15e77dda6572.png" rel=""><img alt="04_url_path.png" class="ipsImage ipsImage_thumbnailed" data-fileid="89018" data-unique="fk0bmg72t" src="https://academy.hsoub.com/uploads/monthly_2022_01/04_url_path.thumb.png.ba8a5ed78f9d1a8c3f4ee7b69741a5e1.png" style="width: 500px; height: auto;"></a>
</p>

<p>
	ويمثل الطريق للوصول إلى مورد موجود على <a href="https://academy.hsoub.com/devops/servers/%D8%AF%D9%84%D9%8A%D9%84-%D8%A5%D8%B9%D8%AF%D8%A7%D8%AF-%D8%AE%D8%A7%D8%AF%D9%85-%D9%88%D9%8A%D8%A8-%D9%85%D8%AD%D9%84%D9%8A-%D8%AE%D8%B7%D9%88%D8%A9-%D8%A8%D8%AE%D8%B7%D9%88%D8%A9-r422/" rel="">خادم ويب</a> (<code>path/to/myfile.html/‎</code> مثلًا). مثَّلت هذه المسارات في بدايات الويب الموقع الفيزيائي لملف على خادم، لكنه حاليًا مجرد اختصار يتعامل معه الخادم بطريقة معينة للوصول إلى المورد وغالبًا لا يشير إلى المكان الحقيقي لوجود المورد.
</p>

<h3>
	المعاملات
</h3>

<p style="text-align: center;">
	<a class="ipsAttachLink ipsAttachLink_image" data-fileid="89019" href="https://academy.hsoub.com/uploads/monthly_2022_01/05_url_parameters.png.0fd1fd127540a3244e31c84dda43aab3.png" rel=""><img alt="05_url_parameters.png" class="ipsImage ipsImage_thumbnailed" data-fileid="89019" data-unique="3tpoi0vsv" src="https://academy.hsoub.com/uploads/monthly_2022_01/05_url_parameters.png.0fd1fd127540a3244e31c84dda43aab3.png" style="width: 500px; height: auto;"></a>
</p>

<p>
	وهي قائمة من العناصر الثنائية على شكل"مفتاح/قيمة" يفصل بينها الرمز <code>&amp;</code> مثل القائمة <code>key1=value1&amp;key2=value2</code> كما في الصورة السابقة. يمكن لخادم ويب استخدام هذه المعاملات في تنفيذ عمليات إضافية قبل أن يعيد المورد المطلوب. لكل خادم ويب قواعده الخاصة المتعلقة بمعالجة المعاملات، ومن الأفضل دومًا أن تسأل مالك الخادم عن طريقة تعامل خادمه مع المعاملات.
</p>

<h3>
	المربط
</h3>

<p style="text-align: center;">
	<a class="ipsAttachLink ipsAttachLink_image" data-fileid="89020" href="https://academy.hsoub.com/uploads/monthly_2022_01/06_url_anchor.png.af0b6478f83481f063e0e8d9b6db2e2c.png" rel=""><img alt="06_url_anchor.png" class="ipsImage ipsImage_thumbnailed" data-fileid="89020" data-unique="39m6lljzt" src="https://academy.hsoub.com/uploads/monthly_2022_01/06_url_anchor.png.af0b6478f83481f063e0e8d9b6db2e2c.png" style="width: 500px; height: auto;"></a>
</p>

<p>
	يمثل المربط <code>#</code> (ويشار إليه المرساة أحيانًا) طريقة للاشارة إلى جزء معين من المورد نفسه، وتشبه فكرته فكرة "الاشارة المرجعية" داخل المورد نفسه. فلو كان المورد ملف HTML مثلًا، سينتقل المتصفح إلى النقطة التي يُعرّفها المربط "#"، وفي حال كان المربط يشير إلى نقطة زمنية معينة من ملفات الصوتية أو الفيديو سيحاول المتصفح الانتقال إلى الزمن الذي يحدده المربط. وتجدر الإشارة هنا، إلى أن القسم الذي يقع بعد الرمز "#" (ويُدعى "مُعرِّف القطعة Fragment Identifier") لن يُرسل أبدًا إلى الخادم مع الطلب.
</p>

<h2>
	كيف تستخدم URL
</h2>

<p>
	بإمكانك كتابة أي URL ضمن شريط العنوان في المتصفح لتحضر المورد الذي يمثله، لكن هذا الاستخدام ما هو إلا رأس الهرم فقط!
</p>

<p>
	تستخدم لغة <a href="https://wiki.hsoub.com/HTML" rel="external">HTML</a> عناوين URL بكثرة لكي:
</p>

<ul>
<li>
		تنشئ روابطًا مع مستندات أخرى باستخدام العنصر <code>&lt;a&gt;</code>.
	</li>
	<li>
		تربط مستندًا مع موارده عبر عناصر متعددة مثل <code>&lt;link&gt;</code> أو <code>&lt;script&gt;</code>.
	</li>
	<li>
		تعرض الوسائط مثل الصور (باستخدام العنصر <code>&lt;img&gt;</code>) والفيديو (باستخدام العنصر <code>&lt;video&gt;</code>) والملفات الصوتية (باستخدام العنصر<code>&lt;audio&gt;</code>).
	</li>
	<li>
		تعرض ملفات HTML أخرى باستخدام العنصر <code>&lt;iframe&gt;</code>.
	</li>
</ul>
<blockquote class="ipsQuote" data-ipsquote="">
	<div class="ipsQuote_citation">
		اقتباس
	</div>

	<div class="ipsQuote_contents ipsClearfix">
		<p>
			<strong>ملاحظة</strong>: عندما تحدد URL لإحضار مورد يُعدُّ جزءًا من صفحة (كالحالة التي نستخدم فيها العناصر <code>&lt;script&gt;</code> و<code>&lt;audio&gt;</code>و<code>&lt;img&gt;</code> و<code>&lt;video&gt;</code> وما شابه) عليك عمومًا استخدام البروتوكولين HTTP وHTTPS باستثناء عدة حالات خاصة منها استخدام البروتوكول <code>data:‎</code> (<a href=")" rel="">راجع URL للبيانات</a>. لا يُعد استخدام FTP آمنًا لذلك توقفت المتصفحات الحديثة عن دعمه.
		</p>
	</div>
</blockquote>

<p>
	تستخدم التقنيات الأخرى مثل <a href="https://wiki.hsoub.com/CSS" rel="external">CSS</a> و<a href="https://wiki.hsoub.com/JavaScript" rel="external">JavaScript</a> عناوين URL بكثرة أيضًا، وهذه التقنيات هي ما تشكل الويب في الواقع.
</p>

<h2>
	عناوين URL المطلقة والنسبية
</h2>

<p>
	تُعد الأمثلة التي أوردناها سابقًا عن عنوان URL عناوينًا مطلقة Absolute URLs، لكن لا يزال هناك نمط آخر وهي العناوين النسبية Relative URLs ولا بدّ من الإشارة إلى الفوارق بينهما بشيء من التفصيل.
</p>

<p>
	تعتمد الأجزاء التي ينبغي استخدامها من عنوان URL والأخرى التي يمكن إهمالها على السياق الذي يستخدم فيه عنوان URL. فمثلًا في شريط عنوان متصفحك لا يوجب أي سياق محدد لعناوين URL لهذا لا بدّ من كتابة URL بشكله الكامل (أو المطلق) كما فعلنا في الأمثلة السابقة. لا حاجة بالطبع في حالة المتصفح أن تذكر البروتوكول لأن المتصفح يستخدم البروتوكول HTTP افتراضيًا، ولا نذكر أيضًا المنفذ الذي نحتاجه إلا في الحالة التي نتصل فيها مع الخادم عبر منفذ غير اعتيادي، ولكن لا بد من كتابة بقية أجزاء عنوان URL.
</p>

<p>
	عندما يُستخدم عنوان URL داخل مستند كصفحة HTML ستختلف الأمور قليلًا. إذ يمتلك المتصفح في هذه الحالة عنوان URL الخاص بالمستند ككل، وبالتالي سيتمكن من استخدام معلوماته لإكمال الأجزاء الناقصة لعنوان URL الموجود داخل المستند. يمكن التمييز بين عنوان URL المطلق والنسبي بالنظر فقط إلى جزء المسار، فإذا بدأ عنوان URL بالرمز <code>/</code> فسيحضر المتصفح المورد من أعلى عنوان جذري للخادم دون الحاجة إلى المكان الذي يشير إليه المستند.
</p>

<p>
	لنلق نظرة على بعض الأمثلة لتوضيح الأمر.
</p>

<h2>
	أمثلة عن عناوين URL مطلقة
</h2>

<p>
	يُعد العنوان الآتي مطلقًا أو كاملًا
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_5932_9" style="">
<span class="pln"> https</span><span class="pun">:</span><span class="com">//developer.mozailla.org/docs/learn</span></pre>

<p>
	بينما يعد العنوان التالي غير كامل إذ سيستخدم هذا العنوان البروتوكول الضمني للمستند الذي يتضمن عنوان URL.
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_5932_11" style="">
<span class="pln">developer</span><span class="pun">.</span><span class="pln">mozilla</span><span class="pun">.</span><span class="pln">org</span><span class="pun">/</span><span class="pln">en</span><span class="pun">-</span><span class="pln">us</span><span class="pun">/</span><span class="pln">docs</span><span class="pun">/</span><span class="typ">Learn</span><span class="com">//</span></pre>

<p>
	أما العنوان الآتي فهو اسم نطاق ضمني، وهي الحالة الأكثر استخدامًا لعناوين URL المطلقة داخل مستندات HTML.
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_5932_13" style="">
<span class="str">/en-us/</span><span class="pln">docs</span><span class="pun">/</span><span class="pln">learn</span><span class="pun">/</span></pre>

<p>
	يستخدم المتصفح في هذه الحالة نفس البروتوكول واسم النطاق المستخدمان في تحميل المستند الذي يحتوي على عنوان URL <strong>لاحظ</strong> أنه لا يمكن حذف اسم النطاق دون حذف البروتوكول أيضًا.
</p>

<h2>
	أمثلة عن عناوين URL نسبية
</h2>

<p>
	لتفهم الأمثلة التالية بطريقة صحيحة، سنفترض أن عناوين URL ستُستدعى من داخل المستند الموجود على عنوان URL التالي:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_9843_20" style="">
<span class="pln"> https</span><span class="pun">:</span><span class="com">//developer.mozilla.org/en-us/docs/Learn</span></pre>

<p>
	يستخدم العنوان "<code>Skills/Infrastructure/Understanding_URLs"</code> فكرة الموارد الفرعية، فطالما أنّ عنوان URL لم يبدأ بالرمز <code>/</code> سيحاول المتصفح أن يجد المستند في مجلد فرعي ضمن المجلد الذي يحتوي المورد الحالي أي سنرغب في مثالنا في الوصول إلى عنوان URL التالي:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_570_11" style="">
<span class="pln">https</span><span class="pun">:</span><span class="com">//developer.mozilla.org/en-us/docs/Learn/Skills/Infrastructure/Understanding_URLs.</span></pre>

<p>
	بينما يستخدم العنوان "<code>‎../CSS/display"</code> فكرة التراجع إلى الخلف في مسار الشجرة، ونستخدم في هذه الحالة النمط <code>/..</code> الموروث من نظام ملفات يونكس لكي نخبر المتصفح أن ينتقل إلى المجلد الأعلى مباشرة.<br>
	أي أننا نريد هنا الوصول إلى عنوان URL التالي:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_570_13" style="">
<span class="pln">https</span><span class="pun">:</span><span class="com">//developer.mozilla.org/en-US/docs/Learn/../CSS/display</span></pre>

<p>
	والذي يمكن اختصاره إلى:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_570_15" style="">
<span class="pln">https</span><span class="pun">:</span><span class="com">//developer.mozilla.org/en-US/docs/CSS/display</span></pre>

<h2>
	عناوين URL الدلالية
</h2>

<p>
	بالرغم من الصبغة التقنية الواضحة لهذا النوع، إلا أن عناوين URL الدلالية Semantic URLs هي طريقة دخول إلى موقع ويب معين يمكن للبشر فهمها. أي يمكن أن يحفظها المستخدم بسهولة ويدخلها بنفسه في شريط عنوان المتصفح، وطالما أنّ المستخدمين هم مركز اهتمام الويب، فمن أفضل الممارسات التي ينبغي نشرها هي بناء ما يُدعى عناوين URL واضحة ومقروءة Clean URL، وهي عناوين تستخدم كلمات في صلب موضوع محتوى العناوين يمكن لأي شخص فهمها دون أن تكون لديه أي فكرة تقنية عن كيفية إنجاز الأمر.
</p>

<p>
	لا علاقة بالطبع للدلالات اللغوية بالحواسيب، فلربما بدت لك عناوين URL كخليط من الرموز العشوائية، لكن هناك إيجابيات عدة لكتابة URL مقروء من قبل المستخدم منها:
</p>

<ul>
<li>
		سهولة تعديلها.
	</li>
	<li>
		تجعل الكثير من النقاط أكثر وضوحًا للمستخدم مثل الموقع الذي يتواجد فيه وما الذي يفعله في هذا الموقع أو ما الذي يقرأه أو يتفاعل معه على الويب.
	</li>
	<li>
		يمكن لعناوين URL المقروءة أن تحسن ترتيب وتصنيف الصفحات في محركات البحث.
	</li>
</ul>
<p>
	ترجمة -وبتصرف- للمقال <a href="https://developer.mozilla.org/en-US/docs/Learn/Common_questions/What_is_a_URL" rel="external nofollow">What is a URL</a>.
</p>

<h2>
	اقرأ أيضًا
</h2>

<ul>
<li>
		<a href="https://academy.hsoub.com/devops/servers/%D9%85%D8%A7-%D9%87%D9%88-%D8%AE%D8%A7%D8%AF%D9%85-%D8%A7%D9%84%D9%88%D9%8A%D8%A8%D8%9F-r574/" rel="">ما هو خادم الويب؟</a>
	</li>
	<li>
		<a href="https://academy.hsoub.com/programming/workflow/%D9%85%D8%A7-%D9%87%D9%8A-%D8%A7%D9%84%D8%A3%D8%AF%D9%88%D8%A7%D8%AA-%D8%A7%D9%84%D9%85%D8%B3%D8%AA%D8%AE%D8%AF%D9%85%D8%A9-%D9%81%D9%8A-%D8%A8%D9%86%D8%A7%D8%A1-%D9%85%D9%88%D8%A7%D9%82%D8%B9-%D9%88%D9%8A%D8%A8%D8%9F-r1436/" rel="">ما هي الأدوات المستخدمة في بناء مواقع ويب؟</a>
	</li>
	<li>
		<a href="https://academy.hsoub.com/programming/workflow/%D9%85%D8%A7-%D9%87%D9%8A-%D8%A3%D8%AF%D9%88%D8%A7%D8%AA-%D9%85%D8%B7%D9%88%D8%B1%D9%8A-%D8%A7%D9%84%D9%88%D9%8A%D8%A8-%D8%A7%D9%84%D9%85%D8%AF%D9%85%D8%AC%D8%A9-%D9%81%D9%8A-%D8%A7%D9%84%D9%85%D8%AA%D8%B5%D9%81%D8%AD%D8%A7%D8%AA%D8%9F-r1439/" rel="">ما هي أدوات مطوري الويب المدمجة في المتصفحات؟</a>
	</li>
	<li>
		<a href="https://academy.hsoub.com/devops/networking/%D9%85%D8%A7-%D9%87%D9%8A-%D8%A3%D8%B3%D9%85%D8%A7%D8%A1-%D8%A7%D9%84%D9%86%D8%B7%D8%A7%D9%82%D8%A7%D8%AA-%D9%81%D9%8A-%D8%B4%D8%A8%D9%83%D8%A9-%D8%A7%D9%84%D8%A5%D9%86%D8%AA%D8%B1%D9%86%D8%AA%D8%9F-r573/" rel="">ما هي أسماء النطاقات في شبكة الإنترنت؟</a>
	</li>
</ul>
]]></description><guid isPermaLink="false">1435</guid><pubDate>Tue, 18 Jan 2022 16:00:00 +0000</pubDate></item><item><title>&#x645;&#x641;&#x647;&#x648;&#x645; &#x627;&#x644;&#x631;&#x648;&#x627;&#x628;&#x637; &#x627;&#x644;&#x62A;&#x634;&#x639;&#x628;&#x64A;&#x629; &#x641;&#x64A; &#x645;&#x648;&#x627;&#x642;&#x639; &#x627;&#x644;&#x648;&#x64A;&#x628;</title><link>https://academy.hsoub.com/programming/general/%D9%85%D9%81%D9%87%D9%88%D9%85-%D8%A7%D9%84%D8%B1%D9%88%D8%A7%D8%A8%D8%B7-%D8%A7%D9%84%D8%AA%D8%B4%D8%B9%D8%A8%D9%8A%D8%A9-%D9%81%D9%8A-%D9%85%D9%88%D8%A7%D9%82%D8%B9-%D8%A7%D9%84%D9%88%D9%8A%D8%A8-r1434/</link><description><![CDATA[
<p><img src="https://academy.hsoub.com/uploads/monthly_2022_01/61decc1866636_------.png.eba16669c5b9474153d83d9d25ad8634.png" /></p>

<p>
	يُعد مفهوم الروابط التشعبية (تُدعى معظم الأحيان "روابط" فقط) مفهومًا جوهريًا ساهم في تأسيس الويب. فإن أردنا شرح هذا المفهوم لابد من العودة إلى أكثر الأساسيات بساطة في <a href="https://academy.hsoub.com/devops/networking/%D9%85%D8%B9%D9%85%D8%A7%D8%B1%D9%8A%D8%A9-%D8%A7%D9%84%D8%B4%D8%A8%D9%83%D8%A9-%D8%A7%D9%84%D8%AD%D8%A7%D8%B3%D9%88%D8%A8%D9%8A%D8%A9-%D9%88%D8%B4%D8%A8%D9%83%D8%A9-%D8%A7%D9%84%D8%A5%D9%86%D8%AA%D8%B1%D9%86%D8%AA-network-architecture-r484/" rel="">معمارية الويب</a>.
</p>

<p>
	تحدث تيم بيرنرز-لي مخترع الويب عام 1989 عن الأعمدة الثلاث التي تستند إليها الويب:
</p>

<ol>
<li>
		محدد موقع المورد <a href="https://academy.hsoub.com/marketing/performance-marketing/analytics/%D8%A8%D9%86%D9%8A%D8%A9-%D9%85%D8%B3%D8%A7%D8%B1%D8%A7%D8%AA-%D8%A7%D9%84%D8%B5%D9%81%D8%AD%D8%A7%D8%AA-url-%D9%88%D8%A3%D9%87%D9%85%D9%8A%D8%AA%D9%87%D8%A7-%D9%81%D9%8A-%D8%B9%D9%85%D9%84%D9%8A%D8%A9-%D8%AA%D8%AD%D9%84%D9%8A%D9%84-%D8%B2%D9%8A%D8%A7%D8%B1%D8%A7%D8%AA-%D8%A7%D9%84%D9%85%D9%88%D9%82%D8%B9-r159/" rel="">URL</a>: هو نظام عنونة يحدد مكان وجود ملفات الويب.
	</li>
	<li>
		<a href="https://ar.wikipedia.org/wiki/%D8%A8%D8%B1%D9%88%D8%AA%D9%88%D9%83%D9%88%D9%84_%D9%86%D9%82%D9%84_%D8%A7%D9%84%D9%86%D8%B5_%D8%A7%D9%84%D9%81%D8%A7%D8%A6%D9%82" rel="external nofollow">HTTP</a> (بروتوكول نقل النصوص التشعبية): بروتوكول نقل يستخدم لإيجاد الملفات عندما يعطي عنوانها بشكل URL.
	</li>
	<li>
		لغة <a href="https://wiki.hsoub.com/HTML" rel="external">HTML</a>: وهي لغة توصيفية لإنشاء صفحات الويب وتطبيقات الويب وتسمح بتضمين الروابط التشعبية داخل الصفحات.
	</li>
</ol>
<p>
	تدل الأعمدة الثلاث أن كل ما هو موجود على الويب مرتبط بالمستندات وكيفية الوصول إليها، لأن الغرض الأساسي من الويب هو الوصول إلى الملفات النصية وقراءتها والتنقل بينها. لكن تطور الويب مع الزمن مكّن المستخدمين من الوصول إلى الصور والفيديوهات والبيانات الثنائية وبالكاد أثرت هذه التغيرات على الأعمدة الثلاث التي ترتكز عليها ويب.
</p>

<p>
	لم يكن سهلًا الوصول إلى المستندات والتنقل بينها قبل وجود الويب بالرغم من أن عناوين URL بشكلها المفهوم للمستخدم سهلت الأمر. إلا أنه من الصعب كتابة أو تذكر عنوان طويل كلما أردت الوصول إلى مستند، ولهذا السبب ظهرت الروابط التشعبية Hyperlinks التي أحدثت نقلة ثورية في تقانة الويب. إذ يمكن للروابط أن تقرن أي نص بعنوان URL ولن يبقى على المستخدم سوى النقر على الرابط ليصل مباشرة إلى المستند المطلوب.
</p>

<p>
	تُميَّز الروابط التشعبية عن النص المحيط بها بلونها الأزرق والخط الذي يُرى أسفلها. انقر أو المس الرابط حتى تنتقل إلى محتوى الرابط، أو يمكنك الضغط على الزر "TAB" إن كنت تستخدم لوحة المفاتيح حتى يُحدَّد الرابط (يصل تركيز الدخل إليه) ثم يمكنك النقر على الزر "ENTER" أو "SPACE" للولوج إلى محتوى الرابط.
</p>

<p style="text-align: center;">
	<a class="ipsAttachLink ipsAttachLink_image" data-fileid="89007" href="https://academy.hsoub.com/uploads/monthly_2022_01/01_basic_display_link_in_webpage.png.33293d985e779745d577ca2a43108d09.png" rel=""><img alt="01_basic_display_link_in_webpage.png" class="ipsImage ipsImage_thumbnailed" data-fileid="89007" data-unique="o1dv9nlgo" src="https://academy.hsoub.com/uploads/monthly_2022_01/01_basic_display_link_in_webpage.png.33293d985e779745d577ca2a43108d09.png"></a>
</p>

<p>
	أحدثت الروابط التشعبية نقلة نوعية جعلت الويب أكثر فائدة ونجاحًا. سنناقش في بقية المقال الأنواع المختلفة للروابط وفائدتها في التصميم الحديث للويب.
</p>

<p>
	سنطلع في هذا المقال على الروابط التشعبية Hyperlinks، وسنتعرف على عملها وأهميتها في تقانة الويب. ننصحك قبل قراءة المقال بأن تطلع على مقال <a href="https://academy.hsoub.com/devops/networking/%D9%83%D9%8A%D9%81-%D8%AA%D8%B9%D9%85%D9%84-%D8%B4%D8%A8%D9%83%D8%A9-%D8%A7%D9%84%D8%A5%D9%86%D8%AA%D8%B1%D9%86%D8%AA%D8%9F-r571/" rel="">كيف تعمل شبكة الإنترنت؟</a> وأن يكون <a href="https://academy.hsoub.com/devops/servers/%D8%A7%D9%84%D9%81%D8%B1%D9%82-%D8%A8%D9%8A%D9%86-%D8%B5%D9%81%D8%AD%D8%A9-%D8%A7%D9%84%D9%88%D9%8A%D8%A8-%D9%88%D9%85%D9%88%D9%82%D8%B9-%D8%A7%D9%84%D9%88%D9%8A%D8%A8-%D9%88%D8%AE%D8%A7%D8%AF%D9%85-%D8%A7%D9%84%D9%88%D9%8A%D8%A8-%D9%88%D9%85%D8%AD%D8%B1%D9%83-%D8%A7%D9%84%D8%A8%D8%AD%D8%AB-r572/" rel="">الفرق بين صفحة الويب وموقع الويب وخادم الويب ومحرك البحث</a> واضحًا بالنسبة لك.
</p>

<h2>
	أنواع الروابط
</h2>

<p>
	الرابط، كما أشرنا سابقًا، هو سلسلة نصية مرتبطة بعنوان URL، يستخدم لتسهيل الانتقال من مستند إلى آخر. لكن هناك بعض الفوارق البسيطة التي لا بدّ من عرضها.
</p>

<ul>
<li>
		<strong>رابط داخلي Internal Link</strong>: وهو رابط بين صفحتي ويب تنتميان إلى نفس الموقع. وبالطبع لن تجد موقع ويب ليس فيه هذا النوع من الروابط (ما عدا الموقع وحيد الصفحة).
	</li>
	<li>
		<strong>رابط خارجي External link</strong>: وهو رابط بين صفحة ويب على موقعك وصفحة ويب على موقع آخر. بدون هذا النوع من الروابط ليس هناك ويب على الإطلاق لأنها في الواقع شبكة من <a href="https://academy.hsoub.com/design/general/%D9%87%D9%8A%D9%83%D9%84%D8%A9-%D9%88%D8%AA%D9%88%D8%B2%D9%8A%D8%B9-%D9%85%D8%AD%D8%AA%D9%88%D9%89-%D8%B5%D9%81%D8%AD%D8%A7%D8%AA-%D8%A7%D9%84%D9%88%D9%8A%D8%A8-r43/" rel="">صفحات الويب</a> المترابطة. يستخدم هذا النوع لتزويد الزائر بمعلومات إضافية إلى جانب المحتوى الذي تقدمه صفحة الويب.
	</li>
	<li>
		<strong>رابط وارد Incoming Link</strong>: وهو رابط من صفحة خارج موقعك إلى صفحة في موقعك، وهي الحالة المعاكسة للرابط الخارجي. وليس ضروريًا بالطبع ربط صفحتك بكل صفحة خارجية تضع رابطًا لموقعك.
	</li>
</ul>
<p>
	ركّز على الروابط الداخلية عندما تبني موقع ويب لأنها تسهّل استخدام الموقع، وحاول أن توازن في عدد الروابط المستخدمة، فلا تكثر من الروابط ولا تجعلها قليلة في نفس الوقت. سنتحدث لاحقًا عن تصميم آليات التنقل داخل مواقع الويب، ولكن وكقاعدة عامة يمكن اعتمادها، حيثما تنشئ صفحة ويب في موقعك لا بدّ من وجود رابط واحد على الأقل بين الصفحة الجديدة وإحدى الصفحات الموجودة مسبقًا. لكن بالمقابل ستأتي هذه القاعدة بنتائج عكسية عندما يزيد عدد الصفحات في الموقع عن العشرة. لأنه لا يمكن ربط كل الصفحات مع بعضها بعضًا.
</p>

<p>
	لا تعر اهتمامًا كبيرًا للروابط الداخلية والخارجية إن كنت في بداية طريقك في تصميم المواقع، لكن سترى أن وجودها لاحقًا هام جدًا إن أردت من محركات البحث العثور على صفحات موقعك.
</p>

<h2>
	المرابط
</h2>

<p>
	تربط معظم الروابط بين صفحتي ويب، بينما تربط المرابط Anchors (وتدعى مراسي أيضًا) بين قسمين من مستند واحد. عندما تفتح مربطًا ما سينتقل المتصفح إلى جزء آخر من المستند الحالي بدلًا من تحميل مستند جديد أي سيُشير إلى مكان معين ضمن نفس المستند. ولا تختلف طريقة استخدام المربط عن الروابط الأخرى.
</p>

<p style="text-align: center;">
	<a class="ipsAttachLink ipsAttachLink_image" data-fileid="89008" href="https://academy.hsoub.com/uploads/monthly_2022_01/02_Anchor_link.png.f13e70fc232e1cd5e6093c00c5946648.png" rel=""><img alt="02_Anchor_link.png" class="ipsImage ipsImage_thumbnailed" data-fileid="89008" data-unique="v339kiwkk" src="https://academy.hsoub.com/uploads/monthly_2022_01/02_Anchor_link.png.f13e70fc232e1cd5e6093c00c5946648.png"></a>
</p>

<h2>
	الروابط ومحركات البحث
</h2>

<p>
	للروابط أهمية كبيرة للمستخدم ولمحركات البحث، فكلما وصل محرك بحث إلى صفحة جديدة سيفهرس الموقع الذي يحتويها بالتنقل عبر <a href="https://academy.hsoub.com/devops/networking/%D8%A7%D9%84%D8%B1%D9%88%D8%A7%D8%A8%D8%B7-%D8%A7%D9%84%D9%85%D8%A8%D8%A7%D8%B4%D8%B1%D8%A9-direct-links-%D9%81%D9%8A-%D8%A7%D9%84%D8%B4%D8%A8%D9%83%D8%A7%D8%AA-%D8%A7%D9%84%D8%AD%D8%A7%D8%B3%D9%88%D8%A8%D9%8A%D8%A9-r487/" rel="">الروابط</a> الموجودة ضمن هذه الصفحة. لا تلاحق محركات البحث الروابط لتكتشف فقط الصفحات المختلفة للموقع، بل لتستخدم العبارات النصية للرابط في تحديد معايير البحث الملائمة للوصول إلى هذه الصفحة.
</p>

<p>
	تؤثر الروابط على سهولة الوصول إلى صفحتك عبر محركات البحث، لكن المشكلة تكمن في صعوبة تحديد ما يفعله محرك البحث (لأن معظم محركات البحث تخفي طريقة تصنيفها الدقيقة لكي لا يساء استخدامها للاحتيال على هذه المحرك). تحاول معظم الشركات أن تتصدر مواقعها نتائج محركات البحث، وسنطلعك على بعض ما نعرفه عن الآلية تقييم محرك البحث لموقع الويب:
</p>

<ul>
<li>
		يؤثر النص المرئي للرابط على معايير البحث التي تتطابق مع عنوان URL.
	</li>
	<li>
		يرفع ترتيب ظهور موقعك في <a href="https://academy.hsoub.com/marketing/search-engine-optimisation/%D8%AA%D8%AD%D8%B3%D9%8A%D9%86-%D8%AA%D8%B1%D8%AA%D9%8A%D8%A8-%D8%A7%D9%84%D9%85%D9%88%D8%A7%D9%82%D8%B9-%D9%81%D9%8A-%D9%86%D8%AA%D8%A7%D8%A6%D8%AC-%D8%A7%D9%84%D8%A8%D8%AD%D8%AB-%D8%A8%D8%A7%D9%84%D9%86%D8%B3%D8%A8%D8%A9-%D9%84%D9%84%D8%B4%D8%B1%D9%83%D8%A7%D8%AA-r466/" rel="">نتائج محركات البحث</a> عند وجود عدد كبير من الروابط الواردة إلى موقعك.
	</li>
	<li>
		تؤثر الروابط الخارجية على ترتيب كلٍ من الصفحتين المصدر والهدف، ولكن لا نعرف تحديدًا مقدار هذا التأثير.
	</li>
</ul>
<blockquote class="ipsQuote" data-ipsquote="">
	<div class="ipsQuote_citation">
		اقتباس
	</div>

	<div class="ipsQuote_contents ipsClearfix">
		<p>
			<strong>ملاحظة</strong>: تحسين محركات البحث <a href="https://academy.hsoub.com/marketing/search-engine-optimisation/" rel="">SEO</a> اختصارًا لمصطلح Search Engine Optimization أو كما يشاع تسميته (سيو)، وهي دراسة كيفية تحسين ترتيب ظهور موقع ويب في نتائج محركات البحث، ويُعد <a href="https://academy.hsoub.com/marketing/search-engine-optimisation/4-%D9%86%D8%B5%D8%A7%D8%A6%D8%AD-%D9%84%D8%B9%D9%85%D9%84-%D8%AD%D9%85%D9%84%D8%A9-%D8%A8%D9%86%D8%A7%D8%A1-%D8%B1%D9%88%D8%A7%D8%A8%D8%B7-%D9%86%D8%A7%D8%AC%D8%AD%D8%A9-r107/" rel="">تحسين الروابط</a> في موقع ويب أحد تقنيات السيو المفيدة.
		</p>
	</div>
</blockquote>

<p>
	قد ترغب الآن بإعداد بعض صفحات الويب وتزويدها بالروابط، لذلك لا بد من زيادة خلفيتك المعرفية النظرية بالروابط أولًا، ولذا ننصحك بمعرفة ما هي عناوين URL.
</p>

<p>
	ترجمة -وبتصرف- للمقال <a href="https://developer.mozilla.org/en-US/docs/Learn/Common_questions/What_are_hyperlinks" rel="external nofollow">What are hyperlinks</a>
</p>

<h2>
	اقرأ أيضًا
</h2>

<ul>
<li>
		<a href="https://academy.hsoub.com/devops/networking/%D8%AA%D8%B7%D8%A8%D9%8A%D9%82%D8%A7%D8%AA-%D8%A7%D9%84%D8%B4%D8%A8%D9%83%D8%A7%D8%AA-%D8%A7%D9%84%D8%AD%D8%A7%D8%B3%D9%88%D8%A8%D9%8A%D8%A9-%D8%B4%D8%A8%D9%83%D8%A9-%D8%A7%D9%84%D9%88%D9%8A%D8%A8-%D8%A7%D9%84%D8%B9%D8%A7%D9%84%D9%85%D9%8A%D8%A9-r548/" rel="">تطبيقات الشبكات الحاسوبية: شبكة الويب العالمية</a>
	</li>
	<li>
		<a href="https://academy.hsoub.com/devops/networking/%D8%AA%D8%B7%D8%A8%D9%8A%D9%82%D8%A7%D8%AA-%D8%A7%D9%84%D8%B4%D8%A8%D9%83%D8%A7%D8%AA-%D8%A7%D9%84%D8%AD%D8%A7%D8%B3%D9%88%D8%A8%D9%8A%D8%A9-%D8%AE%D8%AF%D9%85%D8%A7%D8%AA-%D8%A7%D9%84%D9%88%D9%8A%D8%A8-r549/" rel="">تطبيقات الشبكات الحاسوبية: خدمات الويب</a>
	</li>
	<li>
		<a href="https://academy.hsoub.com/devops/servers/%D9%85%D8%A7-%D9%87%D9%88-%D8%AE%D8%A7%D8%AF%D9%85-%D8%A7%D9%84%D9%88%D9%8A%D8%A8%D8%9F-r574/" rel="">ما هو خادم الويب؟</a>
	</li>
	<li>
		<a href="https://academy.hsoub.com/programming/workflow/%D9%85%D8%A7-%D9%87%D9%8A-%D8%A7%D9%84%D8%A3%D8%AF%D9%88%D8%A7%D8%AA-%D8%A7%D9%84%D9%85%D8%B3%D8%AA%D8%AE%D8%AF%D9%85%D8%A9-%D9%81%D9%8A-%D8%A8%D9%86%D8%A7%D8%A1-%D9%85%D9%88%D8%A7%D9%82%D8%B9-%D9%88%D9%8A%D8%A8%D8%9F-r1436/" rel="">ما هي الأدوات المستخدمة في بناء مواقع ويب؟</a>
	</li>
</ul>
]]></description><guid isPermaLink="false">1434</guid><pubDate>Thu, 13 Jan 2022 15:00:00 +0000</pubDate></item><item><title>&#x645;&#x627; &#x647;&#x64A; &#x627;&#x644;&#x648;&#x627;&#x62C;&#x647;&#x629; &#x627;&#x644;&#x628;&#x631;&#x645;&#x62C;&#x64A;&#x629; API</title><link>https://academy.hsoub.com/programming/general/%D9%85%D8%A7-%D9%87%D9%8A-%D8%A7%D9%84%D9%88%D8%A7%D8%AC%D9%87%D8%A9-%D8%A7%D9%84%D8%A8%D8%B1%D9%85%D8%AC%D9%8A%D8%A9-api-r1645/</link><description><![CDATA[
<p><img src="https://academy.hsoub.com/uploads/monthly_2022_08/api.png.363aeae1ba655c82d25dff1bf5790a2b.png" /></p>

<p>
	سنتعرف في هذا الفيديو على مفهوم الواجهة البرمجية للتطبيق Application Programming Interface أو اختصارًا <a href="https://academy.hsoub.com/programming/general/%D9%85%D8%A7-%D9%87%D9%8A-%D9%88%D8%A7%D8%AC%D9%87%D8%A9-%D8%A7%D9%84%D8%A8%D8%B1%D9%85%D8%AC%D9%8A%D8%A9-%D9%84%D9%84%D8%AA%D8%B7%D8%A8%D9%8A%D9%82%D8%A7%D8%AA-api%D8%9F-r1512/" rel=""><abbr title="Application Programming Interface | واجهة برمجية">API</abbr></a>، كما سنتعرف على كيفية بناء مواقع الويب والتطبيقات الحديثة في يومنا هذا بالاعتماد على الواجهات البرمجية ونجيب على سؤال مهم وهو كيف ترتبط الواجهة الأمامية مع الواجهة الخلفية لتطبيق الويب أو الموقع الإلكتروني.
</p>

<p style="text-align: center;">
	<iframe allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture" allowfullscreen="" frameborder="0" height="480" src="https://www.youtube.com/embed/dPNCFdoXdec" title="ما هي الواجهة البرمجية API" width="853"></iframe>
</p>

<p>
	بعد أن تعرفت على الواجهة البرمجية للتطبيق <abbr title="Application Programming Interface | واجهة برمجية">API</abbr>، يمكنك الاشتراك <a href="https://academy.hsoub.com/learn/php-web-application-development/" rel="">بدورة PHP</a> المقدمة من أكاديمية حسوب التي تقدم شرحًا مفصلًا حول تطوير الواجهات البرمجية APIs، لتتمكن من فهم واحتراف استعمالها وكيفية التعامل معها.
</p>
]]></description><guid isPermaLink="false">1645</guid><pubDate>Mon, 20 Dec 2021 15:00:00 +0000</pubDate></item><item><title>&#x62F;&#x631;&#x627;&#x633;&#x629; &#x62D;&#x627;&#x644;&#x629; &#x628;&#x631;&#x645;&#x62C;&#x64A;&#x629;</title><link>https://academy.hsoub.com/programming/general/%D8%AF%D8%B1%D8%A7%D8%B3%D8%A9-%D8%AD%D8%A7%D9%84%D8%A9-%D8%A8%D8%B1%D9%85%D8%AC%D9%8A%D8%A9-r1392/</link><description><![CDATA[
<p><img src="https://academy.hsoub.com/uploads/monthly_2021_12/61aa0085eb8a5_--.png.f7a5ce2a7c9613f81761ce78e2b296a9.png" /></p>
<p>
	سنتطرق في هذا المقال إلى برنامج عدّ الكلمات الذي كتبناه من قبل، وسننشئ برنامجًا يحاكي برنامج <code>wc</code> في يونكس، من حيث حساب عدد الأسطر والكلمات والمحارف التي في ملف ما، ثم نتعمق أكثر في هذا لنخرج عدد الجمل وأجزاء الجمل clauses والفقرات أيضًا، وسنتابع تطوير هذا البرنامج مرحلةً تلو الأخرى، وسنزيد من إمكانياته تدريجيًا، ثم ننقله إلى <a href="https://academy.hsoub.com/programming/general/%D8%A7%D9%84%D8%A8%D8%B1%D9%85%D8%AC%D8%A9-%D8%A8%D8%A7%D8%B3%D8%AA%D8%AE%D8%AF%D8%A7%D9%85-%D8%A7%D9%84%D9%88%D8%AD%D8%AF%D8%A7%D8%AA-r1333/" rel="">وحدة module</a> ليكون قابلًا لإعادة الاستخدام بأن نجعله <a href="https://academy.hsoub.com/programming/java/%D9%85%D9%81%D9%87%D9%88%D9%85-%D8%A7%D9%84%D9%83%D8%A7%D8%A6%D9%86%D8%A7%D8%AA-objects-%D9%88%D8%A7%D9%84%D8%A8%D8%B1%D9%85%D8%AC%D8%A9-%D9%83%D8%A7%D8%A6%D9%86%D9%8A%D8%A9-%D8%A7%D9%84%D8%AA%D9%88%D8%AC%D9%87-oop-r966/" rel="">كائني التوجه object oriented</a> لتحقيق أقصى حد ممكن من الإمكانيات، ثم نغلفه أخيرًا في <a href="https://academy.hsoub.com/design/user-interface/%D9%82%D9%88%D8%A7%D8%B9%D8%AF-%D8%AA%D8%B5%D9%85%D9%8A%D9%85-%D8%A7%D9%84%D9%88%D8%A7%D8%AC%D9%87%D8%A7%D8%AA-r552/" rel="">واجهة رسومية</a> لسهولة الاستخدام، ورغم أننا سنستخدم <a href="https://academy.hsoub.com/programming/python/%D8%A7%D9%84%D9%85%D8%B1%D8%AC%D8%B9-%D8%A7%D9%84%D8%B4%D8%A7%D9%85%D9%84-%D8%A5%D9%84%D9%89-%D8%AA%D8%B9%D9%84%D9%85-%D9%84%D8%BA%D8%A9-%D8%A8%D8%A7%D9%8A%D8%AB%D9%88%D9%86-r735/" rel="">بايثون</a> في هذا البرنامج إلا أنه يمكن كتابة نسخ منه باستخدام <a href="https://wiki.hsoub.com/JavaScript" rel="external">جافاسكربت</a> أو VBScript بإجراء بعض التعديلات.
</p>

<p>
	ويمكن إضافة مزايا أخرى لهذا البرنامج، لكننا سنتركها للقارئ للتدريب، من تلك المزايا:
</p>

<ul>
	<li>
		حساب فهرس FOG للنصوص، والذي يوضح مدى تعقيد النص، ويُعرَّف بأنه:
	</li>
</ul>

<p>
	 
</p>

<pre class="ipsCode prettyprint lang-c prettyprinted" id="ips_uid_9828_16" style=""><span class="pun">(متوسط</span><span class="pln"> </span><span class="pun">عدد</span><span class="pln"> </span><span class="pun">الكلمات</span><span class="pln"> </span><span class="pun">للجملة</span><span class="pln"> </span><span class="pun">الواحدة)</span><span class="pln"> </span><span class="pun">+</span><span class="pln"> </span><span class="pun">(نسبة</span><span class="pln"> </span><span class="pun">الكلمات</span><span class="pln"> </span><span class="pun">الأكثر</span><span class="pln"> </span><span class="pun">من</span><span class="pln"> </span><span class="lit">5</span><span class="pln"> </span><span class="pun">أحرف)</span><span class="pln"> </span><span class="pun">*</span><span class="pln"> </span><span class="lit">0.4</span><span class="pln">
</span></pre>

<ul>
	<li>
		حساب عدد الكلمات الفريدة المستخدمة، ومرات تكرارها.
	</li>
	<li>
		إنشاء نسخة جديدة تحلل ملفات RTF.
	</li>
</ul>

<h2>
	حساب عدد الأسطر والكلمات والحروف
</h2>

<p>
	إذا نظرنا إلى عداد الكلمات السابق:
</p>

<pre class="ipsCode prettyprint lang-py prettyprinted" id="ips_uid_9828_20" style=""><span class="kwd">import</span><span class="pln"> string
</span><span class="kwd">def</span><span class="pln"> numwords</span><span class="pun">(</span><span class="pln">s</span><span class="pun">):</span><span class="pln">
    lst </span><span class="pun">=</span><span class="pln"> string</span><span class="pun">.</span><span class="pln">split</span><span class="pun">(</span><span class="pln">s</span><span class="pun">)</span><span class="pln">
    </span><span class="kwd">return</span><span class="pln"> len</span><span class="pun">(</span><span class="pln">lst</span><span class="pun">)</span><span class="pln">

</span><span class="kwd">with</span><span class="pln"> open</span><span class="pun">(</span><span class="str">"menu.txt"</span><span class="pun">,</span><span class="str">"r"</span><span class="pun">)</span><span class="pln"> </span><span class="kwd">as</span><span class="pln"> inp</span><span class="pun">:</span><span class="pln">
   total </span><span class="pun">=</span><span class="pln"> </span><span class="lit">0</span><span class="pln">
   </span><span class="com"># accumulate totals for each line</span><span class="pln">
   </span><span class="kwd">for</span><span class="pln"> line </span><span class="kwd">in</span><span class="pln"> inp</span><span class="pun">.</span><span class="pln">readlines</span><span class="pun">():</span><span class="pln">
      total </span><span class="pun">+=</span><span class="pln"> numwords</span><span class="pun">(</span><span class="pln">line</span><span class="pun">)</span><span class="pln">

</span><span class="kwd">print</span><span class="pun">(</span><span class="pln"> </span><span class="str">"File had %d words"</span><span class="pln"> </span><span class="pun">%</span><span class="pln"> total </span><span class="pun">)</span></pre>

<p>
	فسنجد أننا بحاجة إلى إضافة عدد الأسطر والأحرف، وعدد الأسطر سهل لأننا نكرر على كل سطر، لذا سنحتاج إلى متغير يتزايد مع كل تكرار على الحلقة التكرارية، أما عدد الأحرف فسيكون أصعب قليلًا، لأننا نستطيع التكرار على قائمة الكلمات مضيفين أطوالها في متغير آخر.
</p>

<p>
	كما ينبغي أن نجعل البرنامج عام الأغراض بقراءة اسم الملف من سطر الأوامر، أو نطلب من المستخدم أن يزودنا بالاسم إذا لم يكن متاحًا، كما يمكن قراءته من مجرى الدخل القياسي standard input، وهو ما يفعله برنامج <code>wc</code>.
</p>

<p>
	سيبدو <code>wc.py</code> النهائي كما يلي:
</p>

<pre class="ipsCode prettyprint lang-css prettyprinted" id="ips_uid_9828_24" style=""><span class="kwd">import</span><span class="pln"> sys</span><span class="pun">,</span><span class="pln"> </span><span class="kwd">string</span><span class="pln">

</span><span class="com"># احصل على اسم الملف من سطر الأوامر أو المستخدم</span><span class="pln">
</span><span class="kwd">if</span><span class="pln"> len</span><span class="pun">(</span><span class="pln">sys</span><span class="pun">.</span><span class="pln">argv</span><span class="pun">)</span><span class="pln"> </span><span class="pun">!=</span><span class="pln"> </span><span class="lit">2</span><span class="pun">:</span><span class="pln">
   name </span><span class="pun">=</span><span class="pln"> input</span><span class="pun">(</span><span class="str">"Enter the file name: "</span><span class="pun">)</span><span class="pln">
</span><span class="kwd">else</span><span class="pun">:</span><span class="pln">
   name </span><span class="pun">=</span><span class="pln"> sys</span><span class="pun">.</span><span class="pln">argv</span><span class="pun">[</span><span class="lit">1</span><span class="pun">]</span><span class="pln">

</span><span class="com"># اضبط العدادات على الصفر. هذا ينشئ المتغيرات </span><span class="pln">
</span><span class="com"># words - lines - chars = 0, 0, 0</span><span class="pln">

</span><span class="kwd">with</span><span class="pln"> open</span><span class="pun">(</span><span class="pln">name</span><span class="pun">,</span><span class="str">"r"</span><span class="pun">)</span><span class="pln"> </span><span class="kwd">as</span><span class="pln"> inp</span><span class="pun">:</span><span class="pln">
   </span><span class="kwd">for</span><span class="pln"> line </span><span class="kwd">in</span><span class="pln"> inp</span><span class="pun">:</span><span class="pln">
      lines </span><span class="pun">+=</span><span class="pln"> </span><span class="lit">1</span><span class="pln">
      </span><span class="com"># Break into a list of words and count them</span><span class="pln">
      lst </span><span class="pun">=</span><span class="pln"> line</span><span class="pun">.</span><span class="pln">split</span><span class="pun">()</span><span class="pln">
      words </span><span class="pun">+=</span><span class="pln"> len</span><span class="pun">(</span><span class="pln">lst</span><span class="pun">)</span><span class="pln">
      chars </span><span class="pun">+=</span><span class="pln"> len</span><span class="pun">(</span><span class="pln">line</span><span class="pun">)</span><span class="pln"> </span><span class="com"># Use original line which includes spaces etc.</span><span class="pln">

</span><span class="kwd">print</span><span class="pun">(</span><span class="pln"> </span><span class="str">"%s has %d lines, %d words and %d characters"</span><span class="pln"> </span><span class="pun">%</span><span class="pln"> </span><span class="pun">(</span><span class="pln">name</span><span class="pun">,</span><span class="pln"> lines</span><span class="pun">,</span><span class="pln"> words</span><span class="pun">,</span><span class="pln"> chars</span><span class="pun">)</span><span class="pln"> </span><span class="pun">)</span></pre>

<p>
	يستطيع من يستخدم برنامج <code>wc</code> في يونكس تمرير اسم ملف بمحارف بديلة wildcards؛ للحصول على إحصائيات لجميع الملفات المطابقة إضافةً إلى المجموع الكلي، أما برنامجنا فيتعامل مع اسم ملف واحد فقط، فإذا أردت توسيع ذلك إلى محارف البدل فألق نظرةً على الوحدة <a href="https://docs.python.org/3/library/glob.html" rel="external nofollow"><code>glob</code></a>، وابن قائمةً من الأسماء، ثم كرر على قائمة الملفات، وستحتاج إلى عدادات مؤقتة لكل ملف، ثم عدادات تراكمية للمجموع الكلي، أو استخدم قاموسًا.
</p>

<h2>
	عد الجمل بدلًا من الأسطر
</h2>

<p>
	إذا أردنا توسيع هذا البرنامج ليشمل عد الجمل والكلمات بدلًا من "مجموعات المحارف"، فنكرر أولًا على الملف لاستخراج الأسطر إلى قائمة، ثم نكرر على كل سطر لنستخرج الكلمات إلى قائمة أخرى، ثم نعالج بعد ذلك كل "كلمة" لحذف المحارف الدخيلة عليها.
</p>

<p>
	لكن توجد طريقة أبسط، بأن نجمع السطور ونحلل محارف الترقيم لعد الجمل وأجزاء الجمل وغيرها، من خلال تعريف الجملة أو جزء الجملة بحسب عناصر الترقيم، لنجرب ذلك في شيفرة وهمية:
</p>

<pre class="ipsCode prettyprint lang-c prettyprinted" id="ips_uid_9828_26" style=""><span class="pun">لكل</span><span class="pln"> </span><span class="pun">سطر</span><span class="pln"> </span><span class="pun">في</span><span class="pln"> </span><span class="pun">الملف:</span><span class="pln">
   </span><span class="pun">زِد</span><span class="pln"> </span><span class="pun">عدد</span><span class="pln"> </span><span class="pun">الأسطر</span><span class="pln"> </span><span class="pun">بمقدار</span><span class="pln"> </span><span class="pun">واحد</span><span class="pln">
   </span><span class="pun">إذا</span><span class="pln"> </span><span class="pun">كان</span><span class="pln"> </span><span class="pun">السطر</span><span class="pln"> </span><span class="pun">فارغًا:</span><span class="pln">
      </span><span class="pun">زِد</span><span class="pln"> </span><span class="pun">عدد</span><span class="pln"> </span><span class="pun">الفقرات</span><span class="pln">
   </span><span class="pun">عد</span><span class="pln"> </span><span class="pun">نهايات</span><span class="pln"> </span><span class="pun">أجزاء</span><span class="pln"> </span><span class="pun">الفقرات</span><span class="pln">
   </span><span class="pun">عد</span><span class="pln"> </span><span class="pun">نهايات</span><span class="pln"> </span><span class="pun">الجمل.</span><span class="pln">

</span><span class="pun">أنشئ</span><span class="pln"> </span><span class="pun">تقريرًا</span><span class="pln"> </span><span class="pun">بالفقرات</span><span class="pln"> </span><span class="pun">واأسطر</span><span class="pln"> </span><span class="pun">والجمل</span><span class="pln"> </span><span class="pun">وأجزاء</span><span class="pln"> </span><span class="pun">الجمل</span><span class="pln"> </span><span class="pun">والمجموعات</span><span class="pln"> </span><span class="pun">والكلمات.</span></pre>

<p>
	لنحول الآن الشيفرة الوهمية إلى شيفرة حقيقية، وسنستخدم التعابير النمطية في حلنا، لذا ينبغي مراجعة مقال <a href="https://academy.hsoub.com/programming/general/%D8%A7%D9%84%D8%AA%D8%B9%D8%A7%D8%A8%D9%8A%D8%B1-%D8%A7%D9%84%D9%86%D9%85%D8%B7%D9%8A%D8%A9-%D9%81%D9%8A-%D8%A7%D9%84%D8%A8%D8%B1%D9%85%D8%AC%D8%A9-r1374/" rel="">التعابير النمطية في البرمجة</a> من نفس السلسلة، للاطلاع عليها ودراستها:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_9828_28" style=""><span class="kwd">import</span><span class="pln"> re</span><span class="pun">,</span><span class="pln">sys

</span><span class="pun">#</span><span class="pln"> </span><span class="pun">استخدم</span><span class="pln"> </span><span class="pun">التعابير</span><span class="pln"> </span><span class="pun">النمطية</span><span class="pln"> </span><span class="pun">للعثور</span><span class="pln"> </span><span class="pun">على</span><span class="pln"> </span><span class="pun">الأجزاء</span><span class="pln">
sentenceStops </span><span class="pun">=</span><span class="pln"> </span><span class="str">".?!"</span><span class="pln">
clauseStops </span><span class="pun">=</span><span class="pln"> sentenceStops </span><span class="pun">+</span><span class="pln"> </span><span class="str">",;:\-"</span><span class="pln"> </span><span class="pun">#</span><span class="pln"> escape </span><span class="str">'-'</span><span class="pln"> to avoid range effect
sentenceRE </span><span class="pun">=</span><span class="pln"> re</span><span class="pun">.</span><span class="pln">compile</span><span class="pun">(</span><span class="str">"[%s]"</span><span class="pln"> </span><span class="pun">%</span><span class="pln"> sentenceStops</span><span class="pun">)</span><span class="pln">
clauseRE </span><span class="pun">=</span><span class="pln"> re</span><span class="pun">.</span><span class="pln">compile</span><span class="pun">(</span><span class="str">"[%s]"</span><span class="pln"> </span><span class="pun">%</span><span class="pln"> clauseStops</span><span class="pun">)</span><span class="pln">

</span><span class="pun">#</span><span class="pln"> </span><span class="pun">احصل</span><span class="pln"> </span><span class="pun">على</span><span class="pln"> </span><span class="pun">اسم</span><span class="pln"> </span><span class="pun">الملف</span><span class="pln"> </span><span class="pun">من</span><span class="pln"> </span><span class="pun">سطر</span><span class="pln"> </span><span class="pun">الأوامر</span><span class="pln"> </span><span class="pun">أو</span><span class="pln"> </span><span class="pun">من</span><span class="pln"> </span><span class="pun">المستخدم</span><span class="pln">
</span><span class="kwd">if</span><span class="pln"> len</span><span class="pun">(</span><span class="pln">sys</span><span class="pun">.</span><span class="pln">argv</span><span class="pun">)</span><span class="pln"> </span><span class="pun">!=</span><span class="pln"> </span><span class="lit">2</span><span class="pun">:</span><span class="pln">
   name </span><span class="pun">=</span><span class="pln"> input</span><span class="pun">(</span><span class="str">"Enter the file name: "</span><span class="pun">)</span><span class="pln">
</span><span class="kwd">else</span><span class="pun">:</span><span class="pln">
   name </span><span class="pun">=</span><span class="pln"> sys</span><span class="pun">.</span><span class="pln">argv</span><span class="pun">[</span><span class="lit">1</span><span class="pun">]</span><span class="pln">

</span><span class="pun">#</span><span class="pln"> </span><span class="pun">اضبط</span><span class="pln"> </span><span class="pun">العدادات</span><span class="pln"> </span><span class="pun">الآن</span><span class="pln">
lines</span><span class="pun">,</span><span class="pln"> words</span><span class="pun">,</span><span class="pln"> chars </span><span class="pun">=</span><span class="pln"> </span><span class="lit">0</span><span class="pun">,</span><span class="pln"> </span><span class="lit">0</span><span class="pun">,</span><span class="pln"> </span><span class="lit">0</span><span class="pln">
sentences</span><span class="pun">,</span><span class="pln">clauses </span><span class="pun">=</span><span class="pln"> </span><span class="lit">0</span><span class="pun">,</span><span class="pln"> </span><span class="lit">0</span><span class="pln">
paras </span><span class="pun">=</span><span class="pln"> </span><span class="lit">1</span><span class="pln">  </span><span class="pun">#</span><span class="pln"> assume always at least </span><span class="lit">1</span><span class="pln"> para

</span><span class="pun">#</span><span class="pln"> </span><span class="pun">عالج</span><span class="pln"> </span><span class="pun">الملف</span><span class="pln">
</span><span class="kwd">with</span><span class="pln"> open</span><span class="pun">(</span><span class="pln">name</span><span class="pun">,</span><span class="str">"r"</span><span class="pun">)</span><span class="pln"> as inp</span><span class="pun">:</span><span class="pln">
   </span><span class="kwd">for</span><span class="pln"> line in inp</span><span class="pun">:</span><span class="pln">
      lines </span><span class="pun">+=</span><span class="pln"> </span><span class="lit">1</span><span class="pln">
      </span><span class="kwd">if</span><span class="pln"> line</span><span class="pun">.</span><span class="pln">strip</span><span class="pun">()</span><span class="pln"> </span><span class="pun">==</span><span class="pln"> </span><span class="str">""</span><span class="pun">:</span><span class="pln"> </span><span class="pun">#</span><span class="pln"> empty line
         paras </span><span class="pun">+=</span><span class="pln"> </span><span class="lit">1</span><span class="pln">
      words </span><span class="pun">+=</span><span class="pln"> len</span><span class="pun">(</span><span class="pln">line</span><span class="pun">.</span><span class="pln">split</span><span class="pun">())</span><span class="pln">
      chars </span><span class="pun">+=</span><span class="pln"> len</span><span class="pun">(</span><span class="pln">line</span><span class="pun">.</span><span class="pln">strip</span><span class="pun">())</span><span class="pln">
      sentences </span><span class="pun">+=</span><span class="pln"> len</span><span class="pun">(</span><span class="pln">sentenceRE</span><span class="pun">.</span><span class="pln">findall</span><span class="pun">(</span><span class="pln">line</span><span class="pun">))</span><span class="pln">
      clauses </span><span class="pun">+=</span><span class="pln"> len</span><span class="pun">(</span><span class="pln">clauseRE</span><span class="pun">.</span><span class="pln">findall</span><span class="pun">(</span><span class="pln">line</span><span class="pun">))</span><span class="pln">

</span><span class="pun">#</span><span class="pln"> </span><span class="pun">اعرض</span><span class="pln"> </span><span class="pun">النتائج</span><span class="pln">
output </span><span class="pun">=</span><span class="pln"> </span><span class="str">'''</span><span class="pln">
</span><span class="typ">The</span><span class="pln"> file </span><span class="pun">%</span><span class="pln">s contains</span><span class="pun">:</span><span class="pln">
        </span><span class="pun">%</span><span class="pln">d\t characters
        </span><span class="pun">%</span><span class="pln">d\t words
        </span><span class="pun">%</span><span class="pln">d\t lines in
        </span><span class="pun">%</span><span class="pln">d\t paragraphs </span><span class="kwd">with</span><span class="pln">
        </span><span class="pun">%</span><span class="pln">d\t sentences and
        </span><span class="pun">%</span><span class="pln">d\t clauses</span><span class="pun">.</span><span class="pln">
</span><span class="str">'''</span><span class="pln"> </span><span class="pun">%</span><span class="pln"> </span><span class="pun">(</span><span class="pln">name</span><span class="pun">,</span><span class="pln"> chars</span><span class="pun">,</span><span class="pln"> words</span><span class="pun">,</span><span class="pln"> lines</span><span class="pun">,</span><span class="pln"> paras</span><span class="pun">,</span><span class="pln"> sentences</span><span class="pun">,</span><span class="pln"> clauses</span><span class="pun">)</span><span class="pln">
print</span><span class="pun">(</span><span class="pln"> output </span><span class="pun">)</span></pre>

<p>
	هناك عدة نقاط ينبغي الانتباه إليها في الشيفرة السابقة:
</p>

<ul>
	<li>
		نستخدم التعابير النمطية هنا لتحسين كفاءة عمليات البحث، رغم إمكانية استخدام عمليات بحث بسيطة عن السلاسل النصية، لكن كنا سنحتاج حينئذ إلى البحث عن كل محرف ترقيم على حدة، وتزيد التعابير النمطية هنا من كفاءة البرنامج، من خلال إيجاد جميع العناصر التي نريدها في بحث واحد، لكن من ناحية أخرى يسهل حدوث الأخطاء فيها، فقد نسينا أثناء محاولتنا الأولى لكتابة الشيفرة أن نهرب المحرف <code>-</code>، فرآه التعبير النمطي مجالًا range، لذا عومل أي عدد في الملف على أنه فاصل لجزء من جملة، واستغرق الأمر كثيرًا حتى عرضنا المشكلة على مجتمع <a href="https://academy.hsoub.com/files/15-%D8%A7%D9%84%D8%A8%D8%B1%D9%85%D8%AC%D8%A9-%D8%A8%D9%84%D8%BA%D8%A9-%D8%A8%D8%A7%D9%8A%D8%AB%D9%88%D9%86/" rel="">بايثون</a> للعثور على الخطأ، فلما أضفنا محرف <code>"</code> حٌلت المشكلة، كما صرَّفنا التعبيرات مسبقًا precompiled، مما حسّن من الأداء أكثر من استخدام نفس التعبير عدة مرات، كما نلاحظ استخدام التابع <code>findall</code> للحصول على جميع التطابقات في سطر باستدعاء واحد.
	</li>
	<li>
		تظهر كفاءة هذا البرنامج في أنه ينفذ ما نريده بالضبط، وإن كان أقل كفاءةً من منظور إمكانية إعادة الاستخدام، لعدم وجود دوال يمكن استدعاؤها من برامج أخرى.
	</li>
	<li>
		ليست اختبارات الجمل مثاليةً، لأن العناوين المختصرة -مثل "Mr.‎"- ستُحسب جملةً، لأنها تحتوي على محرف النقطة، ونستطيع تحسين التعبير النمطي ليبحث عن النقطة متبوعةً بمسافة واحدة أو أكثر، ثم متبوعةً بحرف إنجليزي كبير، لكن ذلك لن يحل مشكلة "Mr.‎" لأنها تُتبع عادةً بمسافة ثم كلمة بحرف كبير، وهذا يوضح مدى صعوبة معالجة اللغات الطبيعية بكفاءة، فإذا احتجنا حقًا إلى مثل هذا البحث في الممارسة العملية فهناك وحدات متاحة على الإنترنت مصممة خصيصًا لذلك.
	</li>
</ul>

<p>
	سنتناول النقطة الثانية المتعلقة بإمكانية إعادة الاستخدام أثناء دراسة الحالة التي بين أيدينا، وننظر في المشاكل المتعلقة بتحليل النصوص بتفصيل أكثر، رغم أننا لن ننتج محلل نصوص مثاليًا في النهاية، حيث تحتاج هذه المهمة مهارات أكبر من التي نتوقعها من مبرمج مبتدئ.
</p>

<h2>
	تحويل البرنامج إلى وحدة
</h2>

<p>
	إذا أردنا تحويل البرنامج الذي كتبناه إلى وحدة فيجب أن نتبع بعض مبادئ التصميم الأساسية، فنضع الجزء الأكبر من الشيفرة في دوال ليستطيع مستخدمو الوحدة الوصول إليها، ثم ننقل شيفرة البدء التي تحصل على اسم الملف إلى جزء منفصل من الشيفرة؛ لا يُنفَّذ عند استيراد الوحدة، وأخيرًا سنترك التعريفات العامة global definitions متغيرات على مستوى الوحدة ليستطيع المستخدمون تغيير قيمها إذا أرادوا.
</p>

<p>
	لننقل كتلة المعالجة الأساسية الآن إلى دالة نسميها <code>analyze()‎</code>، وسنمرر كائن ملف معامِلًا إليها، وستعيد الدالة قائمةً من قيم العد في صف tuple، وستبدو الشيفرة كما يلي:
</p>

<pre class="ipsCode prettyprint lang-py prettyprinted" id="ips_uid_9828_36" style=""><span class="com">#############################</span><span class="pln">
</span><span class="com"># Module: grammar</span><span class="pln">
</span><span class="com"># Created: A.J. Gauld, 2010/12/02</span><span class="pln">
</span><span class="com"># Modified: A.J. Gauld, 2018/01/12</span><span class="pln">
</span><span class="com"># </span><span class="pln">
</span><span class="com"># Function:</span><span class="pln">
</span><span class="str">'''
Provides facilities to count words, lines, characters,
paragraphs, sentences and 'clauses' in text files.
It assumes that sentences end with [.!?] and paragraphs 
have a blank line between them. A 'clause' is simply 
a segment of sentence separated by punctuation. The 
sentence and clause searches are regular expression 
based and the user can change the regex used. Can also 
be run as a program.'''</span><span class="pln">
</span><span class="com">#############################</span><span class="pln">

</span><span class="kwd">import</span><span class="pln"> re</span><span class="pun">,</span><span class="pln"> sys

</span><span class="com"># اضبط المتغيرات العامة</span><span class="pln">
paras </span><span class="pun">=</span><span class="pln"> </span><span class="lit">1</span><span class="pln"> </span><span class="com"># We will assume at least 1 paragraph!</span><span class="pln">
lines</span><span class="pun">,</span><span class="pln"> sentences</span><span class="pun">,</span><span class="pln"> clauses</span><span class="pun">,</span><span class="pln"> words</span><span class="pun">,</span><span class="pln"> chars </span><span class="pun">=</span><span class="pln"> </span><span class="lit">0</span><span class="pun">,</span><span class="lit">0</span><span class="pun">,</span><span class="lit">0</span><span class="pun">,</span><span class="lit">0</span><span class="pun">,</span><span class="lit">0</span><span class="pln">
sentenceMarks </span><span class="pun">=</span><span class="pln"> </span><span class="str">'.?!'</span><span class="pln">
clauseMarks </span><span class="pun">=</span><span class="pln"> </span><span class="str">'&amp;();:,/\-'</span><span class="pln"> </span><span class="pun">+</span><span class="pln"> sentenceMarks
sentenceRE </span><span class="pun">=</span><span class="pln"> </span><span class="kwd">None</span><span class="pln">  </span><span class="com"># set via a function call</span><span class="pln">
clauseRE </span><span class="pun">=</span><span class="pln"> </span><span class="kwd">None</span><span class="pln">
format </span><span class="pun">=</span><span class="pln"> </span><span class="str">'''
The file %s contains:
        %d\t characters
        %d\t words
        %d\t lines in
        %d\t paragraphs with
        %d\t sentences and
        %d\t clauses.
'''</span><span class="pln"> 


</span><span class="com">############################</span><span class="pln">
</span><span class="com"># عرّف الدوال التي ستنفذ العمل</span><span class="pln">

</span><span class="com"># بإعادة تصريف التعبير النمطي إذا setCounterREs تسمح لنا </span><span class="pln">
</span><span class="com"># غيرنا قائمة الأجزاء</span><span class="pln">
</span><span class="kwd">def</span><span class="pln"> setCounterREs</span><span class="pun">():</span><span class="pln">
    </span><span class="str">"compiles global regexs from global punctuation sets"</span><span class="pln">
    </span><span class="kwd">global</span><span class="pln"> sentenceRE</span><span class="pun">,</span><span class="pln"> clauseRE
    sentenceRE </span><span class="pun">=</span><span class="pln"> re</span><span class="pun">.</span><span class="pln">compile</span><span class="pun">(</span><span class="str">'[%s]'</span><span class="pln"> </span><span class="pun">%</span><span class="pln"> sentenceMarks</span><span class="pun">)</span><span class="pln">
    clauseRE </span><span class="pun">=</span><span class="pln"> re</span><span class="pun">.</span><span class="pln">compile</span><span class="pun">(</span><span class="str">'[%s]'</span><span class="pln"> </span><span class="pun">%</span><span class="pln"> clauseMarks</span><span class="pun">)</span><span class="pln">

</span><span class="com"># تصفير العدادات analyze() تستدعي </span><span class="pln">
</span><span class="kwd">def</span><span class="pln"> resetCounters</span><span class="pun">():</span><span class="pln">
    </span><span class="str">" reset global counter variables to initial values "</span><span class="pln">
    chars</span><span class="pun">,</span><span class="pln"> words</span><span class="pun">,</span><span class="pln"> lines</span><span class="pun">,</span><span class="pln"> sentences</span><span class="pun">,</span><span class="pln"> clauses </span><span class="pun">=</span><span class="pln"> </span><span class="lit">0</span><span class="pun">,</span><span class="lit">0</span><span class="pun">,</span><span class="lit">0</span><span class="pun">,</span><span class="lit">0</span><span class="pun">,</span><span class="lit">0</span><span class="pln">
    paras </span><span class="pun">=</span><span class="pln"> </span><span class="lit">1</span><span class="pln">


</span><span class="com"># لشيفرة التعريفات، إذ توفر تقريرًا نصيًا بسيطًا reportStats توجَّه  </span><span class="pln">
</span><span class="kwd">def</span><span class="pln"> reportStats</span><span class="pun">(</span><span class="pln">theFile</span><span class="pun">):</span><span class="pln">
    </span><span class="str">" prints out results from global results "</span><span class="pln">
    </span><span class="kwd">print</span><span class="pun">(</span><span class="pln"> format </span><span class="pun">%</span><span class="pln"> </span><span class="pun">(</span><span class="pln">theFile</span><span class="pun">.</span><span class="pln">name</span><span class="pun">,</span><span class="pln"> chars</span><span class="pun">,</span><span class="pln"> words</span><span class="pun">,</span><span class="pln"> lines</span><span class="pun">,</span><span class="pln">
                     paras</span><span class="pun">,</span><span class="pln"> sentences</span><span class="pun">,</span><span class="pln"> clauses</span><span class="pun">)</span><span class="pln"> </span><span class="pun">)</span><span class="pln">

</span><span class="com"># هي الدالة الأساسية التي تعالج الملف analyze()</span><span class="pln">
</span><span class="kwd">def</span><span class="pln"> analyze</span><span class="pun">(</span><span class="pln">theFile</span><span class="pun">):</span><span class="pln">
    </span><span class="str">''' analyze(aFile) -&gt; None

    Analyzes the input file object putting results in global variables
    '''</span><span class="pln">
    </span><span class="kwd">global</span><span class="pln"> chars</span><span class="pun">,</span><span class="pln">words</span><span class="pun">,</span><span class="pln">lines</span><span class="pun">,</span><span class="pln">paras</span><span class="pun">,</span><span class="pln">sentences</span><span class="pun">,</span><span class="pln">clauses
    </span><span class="com"># مصرَّفًا بالفعل REs تحقق إن كان </span><span class="pln">
    </span><span class="kwd">if</span><span class="pln"> </span><span class="kwd">not</span><span class="pln"> </span><span class="pun">(</span><span class="pln">sentenceRE </span><span class="kwd">and</span><span class="pln"> clauseRE</span><span class="pun">):</span><span class="pln"> 
        setCounterREs</span><span class="pun">()</span><span class="pln">
    resetCounters</span><span class="pun">()</span><span class="pln">
    </span><span class="kwd">for</span><span class="pln"> line </span><span class="kwd">in</span><span class="pln"> theFile</span><span class="pun">:</span><span class="pln">
        lines </span><span class="pun">+=</span><span class="pln"> </span><span class="lit">1</span><span class="pln">
        </span><span class="kwd">if</span><span class="pln"> line</span><span class="pun">.</span><span class="pln">strip</span><span class="pun">()</span><span class="pln"> </span><span class="pun">==</span><span class="pln"> </span><span class="str">""</span><span class="pun">:</span><span class="pln"> </span><span class="com"># empty line</span><span class="pln">
            paras </span><span class="pun">+=</span><span class="pln"> </span><span class="lit">1</span><span class="pln">
        words </span><span class="pun">+=</span><span class="pln"> len</span><span class="pun">(</span><span class="pln">line</span><span class="pun">.</span><span class="pln">split</span><span class="pun">())</span><span class="pln">
        chars </span><span class="pun">+=</span><span class="pln"> len</span><span class="pun">(</span><span class="pln">line</span><span class="pun">.</span><span class="pln">strip</span><span class="pun">())</span><span class="pln">
        sentences </span><span class="pun">+=</span><span class="pln"> len</span><span class="pun">(</span><span class="pln">sentenceRE</span><span class="pun">.</span><span class="pln">findall</span><span class="pun">(</span><span class="pln">line</span><span class="pun">))</span><span class="pln">
        clauses </span><span class="pun">+=</span><span class="pln"> len</span><span class="pun">(</span><span class="pln">clauseRE</span><span class="pun">.</span><span class="pln">findall</span><span class="pun">(</span><span class="pln">line</span><span class="pun">))</span><span class="pln">


</span><span class="com"># اسمح بتشغيلها إذا استُدعيت من سطر الأوامر</span><span class="pln">
</span><span class="com">#'__main__' على '__name__' يُضبط متغير</span><span class="pln">
</span><span class="kwd">if</span><span class="pln"> __name__ </span><span class="pun">==</span><span class="pln"> </span><span class="str">"__main__"</span><span class="pun">:</span><span class="pln">
    </span><span class="kwd">if</span><span class="pln"> len</span><span class="pun">(</span><span class="pln">sys</span><span class="pun">.</span><span class="pln">argv</span><span class="pun">)</span><span class="pln"> </span><span class="pun">!=</span><span class="pln"> </span><span class="lit">2</span><span class="pun">:</span><span class="pln">
        </span><span class="kwd">print</span><span class="pun">(</span><span class="pln"> </span><span class="str">"Usage: python grammar.py &lt;filename&gt;"</span><span class="pln"> </span><span class="pun">)</span><span class="pln">
        sys</span><span class="pun">.</span><span class="pln">exit</span><span class="pun">()</span><span class="pln">
    </span><span class="kwd">else</span><span class="pun">:</span><span class="pln">
        </span><span class="kwd">with</span><span class="pln"> open</span><span class="pun">(</span><span class="pln">sys</span><span class="pun">.</span><span class="pln">argv</span><span class="pun">[</span><span class="lit">1</span><span class="pun">],</span><span class="str">"r"</span><span class="pun">)</span><span class="pln"> </span><span class="kwd">as</span><span class="pln"> aFile</span><span class="pun">:</span><span class="pln">
            analyze</span><span class="pun">(</span><span class="pln">aFile</span><span class="pun">)</span><span class="pln">
            reportStats</span><span class="pun">(</span><span class="pln">aFile</span><span class="pun">)</span></pre>

<p>
	إن أول ما نلاحظه هنا هو التعليقات التي في الأعلى، وهذا سلوك شائع لإعطاء فكرة عامة لمن يقرأ الملف عن محتوياته وكيفية استخدامه، كما أن معلومات الإصدار التي تشمل المؤلف والتاريخ مهمة عند موازنة النتائج مع شخص آخر قد يستخدم إصدارًا أحدث، ونلاحظ أن وصف الوحدة هو سلسلة نصية غير مخصصة لمتغير ما، وتذكر أن هذا ينشئ سلسلة توثيق documentation string في بايثون، يمكن الاطلاع عليها باستخدام الدالة <code>help</code>، كما لدينا سلاسل توثيق على كل تعريف دالة مستقلة، ولن نضيف تعليقات كثيرةً في الأمثلة الأخرى، رغم أننا سنعرض بعض الأنماط الأخرى من التعليقات والتوثيقات، لأن النص الأساسي يصف ما يحدث، فهذا المثال يوضح ما يمكن أن نوفره.
</p>

<p>
	أما الجزء الأخير فهو خاصية في بايثون تستدعي أي وحدة محمَّلة في سطر الأوامر <code>"__main__"</code>، نستطيع تجريب المتغير الخاص والمضمَّن <code>__name__</code>، حيث نعرف أن الوحدة ستُستورد وتشغَّل، لذا ننفذ شيفرة التشغيل driver code داخل الكتلة <code>if</code>.
</p>

<p>
	تتضمن شيفرة التعريف تلك إرشادًا حول كيفية تشغيل الملف إذا لم يتوفر اسم ملف، أو إذا توفرت أسماء ملفات كثيرة، فتسأل المستخدم عن اسم الملف باستخدام <code>input()‎</code>، ونلاحظ أن الدالة <code>analyze()‎</code> تستخدم دوال الضبط لضمان ضبط العدادات والتعابير العادية ضبطًا صحيحًا قبل أن تبدأ، مما يفيد المستخدم عند استدعاء analyze عدة مرات، خاصةً بعد تغيير التعابير النمطية المستخدمة في عد الجمل وأجزائها.
</p>

<p>
	كما نلاحظ استخدام <code>global</code> لضمان ضبط المتغيرات على مستوى الوحدة بواسطة الدوال، ومن دونها كنا سننشئ متغيرات محليةً ليس لها تأثير على متغيرات الوحدة.
</p>

<h3>
	استخدام الوحدة grammar
</h3>

<p>
	بعد أن أنشأنا وحدةً نستطيع استخدامها مثل برنامج في سطر أوامر النظام، كما فعلنا من قبل عن طريق ما يلي:
</p>

<pre class="ipsCode prettyprint lang-c prettyprinted" id="ips_uid_9828_39" style=""><span class="pln">C</span><span class="pun">:</span><span class="pln">\&gt; python grammar</span><span class="pun">.</span><span class="pln">py spam</span><span class="pun">.</span><span class="pln">txt</span></pre>

<p>
	إلا أننا نستطيع استيراد الوحدة إلى برنامج آخر أو في محث بايثون، شرط أن نكون قد حفظنا الوحدة في موقع تستطيع <a href="https://wiki.hsoub.com/Python" rel="external">بايثون</a> أن تراه.
</p>

<p>
	لنجرِ الآن بعض الاختبارات على ملف اختبارات اسمه <code>spam.txt</code>، والذي يعطي الناتج التالي:
</p>

<pre class="ipsCode prettyprint lang-py prettyprinted" id="ips_uid_9828_43" style=""><span class="typ">This</span><span class="pln"> </span><span class="kwd">is</span><span class="pln"> a file called spam</span><span class="pun">.</span><span class="pln"> </span><span class="typ">It</span><span class="pln"> has
</span><span class="lit">3</span><span class="pln"> lines</span><span class="pun">,</span><span class="pln"> </span><span class="lit">2</span><span class="pln"> sentences </span><span class="kwd">and</span><span class="pun">,</span><span class="pln"> hopefully</span><span class="pun">,</span><span class="pln"> 
</span><span class="lit">5</span><span class="pln"> clauses</span><span class="pun">.</span></pre>

<p>
	أي هذا ملف اسمه spam، فيه 3 أسطر وجملتين وخمسة أجزاء جمل.
</p>

<p>
	لنشغل بايثون الآن ونجرب:
</p>

<pre class="ipsCode prettyprint lang-py prettyprinted" id="ips_uid_9828_45" style=""><span class="pun">&gt;&gt;&gt;</span><span class="pln"> </span><span class="kwd">import</span><span class="pln"> grammar
</span><span class="pun">&gt;&gt;&gt;</span><span class="pln"> grammar</span><span class="pun">.</span><span class="pln">setCounterREs</span><span class="pun">()</span><span class="pln">
</span><span class="pun">&gt;&gt;&gt;</span><span class="pln"> txtFile </span><span class="pun">=</span><span class="pln"> open</span><span class="pun">(</span><span class="str">"spam.txt"</span><span class="pun">)</span><span class="pln">
</span><span class="pun">&gt;&gt;&gt;</span><span class="pln"> grammar</span><span class="pun">.</span><span class="pln">analyze</span><span class="pun">(</span><span class="pln">txtFile</span><span class="pun">)</span><span class="pln">
</span><span class="pun">&gt;&gt;&gt;</span><span class="pln"> grammar</span><span class="pun">.</span><span class="pln">reportStats</span><span class="pun">(</span><span class="pln">txtFile</span><span class="pun">)</span><span class="pln">
</span><span class="typ">The</span><span class="pln"> file spam</span><span class="pun">.</span><span class="pln">txt contains</span><span class="pun">:</span><span class="pln">
        </span><span class="lit">80</span><span class="pln">       characters
        </span><span class="lit">16</span><span class="pln">       words
        </span><span class="lit">3</span><span class="pln">        lines </span><span class="kwd">in</span><span class="pln">
        </span><span class="lit">1</span><span class="pln">        paragraphs </span><span class="kwd">with</span><span class="pln">
        </span><span class="lit">2</span><span class="pln">        sentences </span><span class="kwd">and</span><span class="pln">
        </span><span class="lit">5</span><span class="pln">        clauses</span><span class="pun">.</span><span class="pln">

</span><span class="pun">&gt;&gt;&gt;</span><span class="pln"> txtFile</span><span class="pun">.</span><span class="pln">close</span><span class="pun">()</span><span class="pln">
</span><span class="pun">&gt;&gt;&gt;</span><span class="pln"> txtFile </span><span class="pun">=</span><span class="pln"> open</span><span class="pun">(</span><span class="str">'spam.txt'</span><span class="pun">)</span><span class="pln">
</span><span class="pun">&gt;&gt;&gt;</span><span class="pln"> grammar</span><span class="pun">.</span><span class="pln">resetCounters</span><span class="pun">()</span><span class="pln">
</span><span class="pun">&gt;&gt;&gt;</span><span class="pln">  </span><span class="com"># redefine sentences as ending in vowels!</span><span class="pln">
</span><span class="pun">&gt;&gt;&gt;</span><span class="pln"> grammar</span><span class="pun">.</span><span class="pln">sentenceMarks </span><span class="pun">=</span><span class="pln"> </span><span class="str">'aeiou'</span><span class="pln">
</span><span class="pun">&gt;&gt;&gt;</span><span class="pln"> grammar</span><span class="pun">.</span><span class="pln">setCounterREs</span><span class="pun">()</span><span class="pln">
</span><span class="pun">&gt;&gt;&gt;</span><span class="pln"> grammar</span><span class="pun">.</span><span class="pln">analyze</span><span class="pun">(</span><span class="pln">txtFile</span><span class="pun">)</span><span class="pln">
</span><span class="pun">&gt;&gt;&gt;</span><span class="pln"> </span><span class="kwd">print</span><span class="pun">(</span><span class="pln"> grammar</span><span class="pun">.</span><span class="pln">sentences </span><span class="pun">)</span><span class="pln">
</span><span class="lit">21</span><span class="pln">
</span><span class="pun">&gt;&gt;&gt;</span><span class="pln"> txtFile</span><span class="pun">.</span><span class="pln">close</span><span class="pun">()</span></pre>

<p>
	نلاحظ أنه يفضل استخدام <code>open/cloSe</code> على الملف عند استخدام المحث التفاعلي بدلًا من استخدام <code>with</code>، لأن with ستؤخر التنفيذ حتى نكتب جميع عمليات الملف التي ستكون داخل الكتلة <code>with</code>، أما استخدام <code>open</code> صراحةً فسيمكننا من تنفيذ كل أمر تنفيذًا منفصلًا.
</p>

<p>
	نستطيع الآن أن نرى أن إعادة تعريف أجزاء الجمل قد غيرت عدد الجمل تغييرًا جذريًا، ولا شك أن التعريف الجديد غريب لكنه يظهر أن الوحدة قابلة للاستخدام والتخصيص، ونلاحظ أننا كنا نستطيع طباعة عدد الجمل مباشرةً، دون الحاجة إلى استخدام الدالة <code>reportStats()‎</code>، وهذا يظهر قيمة <a href="https://academy.hsoub.com/design/general/%D9%85%D8%A8%D8%A7%D8%AF%D8%A6-%D8%A7%D9%84%D8%AA%D8%B5%D9%85%D9%8A%D9%85-%D9%85%D8%A7-%D8%A7%D9%84%D9%88%D8%A7%D8%AC%D8%A8-%D8%B9%D9%85%D9%84%D9%87-%D8%B9%D9%86%D8%AF%D9%85%D8%A7-%D9%84%D8%A7-%D9%8A%D8%B3%D8%AA%D8%AE%D8%AF%D9%85-%D8%A3%D8%AD%D8%AF-%D8%A7%D9%84%D9%85%D9%8A%D8%B2%D8%A9-%D8%A7%D9%84%D8%AE%D8%A7%D8%B5%D8%A9-%D8%A8%D9%83-r391/" rel="">مبدأ مهم في التصميم</a>، وهو فصل البيانات عن العرض display، فلما فصلنا عرض البيانات عن حسابها صارت وحدتنا أكثر مرونةً للمستخدمين.
</p>

<p>
	ولننهي مشروعنا نعيد صياغة وحدة القواعد grammar لتستخدم تقنيات كائنية التوجه، ثم نضيف واجهةً رسوميةً بسيطةً، وسنرى خلال ذلك كيف يعطينا المنظور الكائني وحدات أكثر مرونةً للمستخدم، وقابلةً للتوسيع أيضًا.
</p>

<h2>
	الأصناف والكائنات
</h2>

<p>
	من أكبر المشاكل التي يواجهها من يستخدم وحدتنا الاعتماد على المتغيرات العامة، مما يعني أنها تستطيع تحليل ملف واحد في كل مرة، وسيؤدي تحليل أكثر من ملف إلى تغيير القيم العامة، فإذا نقلنا هذه المتغيرات العامة إلى صنف class، فسنستطيع إنشاء عدة نسخ من الصنف -واحد لكل ملف-، وستحصل كل نسخة على مجموعتها الخاصة من المتغيرات، وإذا جعلنا التوابع دقيقةً بما يكفي فيمكن إنشاء بنية يسهل من خلالها -على منشئ نوع جديد من كائن المستند- تعديل معايير البحث ليوافق احتياجات النوع الجديد، فإذا رفضنا جميع وسوم <a href="https://wiki.hsoub.com/HTML" rel="external">HTML</a> من قائمة الكلمات مثلًا فيمكن معالجة ملفات HTML إضافةً إلى ملفات <a href="https://wiki.hsoub.com/Arduino/asciichart" rel="external">آسكي ASCII</a> الخالصة.
</p>

<p>
	أدت محاولتنا الأولى في هذا إلى إنشاء الصنف Document لتمثيل الملف الذي نعالجه:
</p>

<pre class="ipsCode prettyprint lang-html prettyprinted" id="ips_uid_9828_56" style=""><span class="pln">#! /usr/local/bin/python
################################
# Module: document.py
# Author: A.J. Gauld
# Date:   2010/12/10
# Version: 3.1
################################
'''
Provides 2 classes for parsing text/files.
A Generic Document class for plain ASCII text,
and an HTMLDocument for HTML files.

 Primary services available include 
    - analyze(),
    - reportStats().
'''

import sys,re

class Document:
    sentenceMarks = '?!.'
    clauseMarks = '&amp;()/\-;:,' + sentenceMarks

    def __init__(self, filename):
        self.filename = filename
        self.setREs()
        self.resetCounters()

    def resetCounters(self):
        self.paras = 1
        self.lines = self.getLines()
        self.sentences, self.clauses, self.words, self.chars = 0,0,0,0

    def setREs(self):
        self.sentenceRE = re.compile('[%s]' % Document.sentenceMarks)
        self.clauseRE = re.compile('[%s]' % Document.clauseMarks)

    def getLines(self):
        with open(self.filename)as infile:
            lines = infile.readlines()
        return lines

    def analyze(self):
        self.resetCounters()
        for line in self.lines:
            self.sentences += len(self.sentenceRE.findall(line))
            self.clauses += len(self.clauseRE.findall(line))
            self.words += len(line.split())
            self.chars += len(line.strip())
            if line.strip() == "":
                self.paras += 1

    def formatResults(self):
        format = '''
        The file %s contains:
        %d\t characters
        %d\t words
        %d\t lines in
        %d\t paragraphs with
        %d\t sentences and
        %d\t clauses.
        ''' 
        return format % (self.filename, self.chars,
                         self.words, len(self.lines), 
                         self.paras, self.sentences, self.clauses)

class TextDocument(Document):
    pass

class HTMLDocument(Document):
    pass


if __name__ == "__main__":
       if len(sys.argv) == 2:
           doc = Document(sys.argv[1])
           doc.analyze()
           print( doc.formatResults() )
       else:
           print( "Usage: python document3.py  </span><span class="tag">&lt;file&gt;</span><span class="pln">" )
           print( "Failed to analyze file" )</span></pre>

<p>
	نلاحظ استخدام متغيرات الصنف في بداية تعريفه، لتخزين محددات الجمل وأجزائها، حيث تُشارَك متغيرات الصنف بين جميع نسخه، لذا فهي مكان ممتاز لتخزين المعلومات المشتركة، ويمكن الوصول إليها باستخدام اسم الصنف كما فعلنا هنا، أو باستخدام <code>self</code>، ونفضل استخدام اسم الصنف لأنه يبرز حقيقة أن هذه المتغيرات لصنف.
</p>

<p>
	لا زلنا بحاجة إلى <code>resetCounters()‎</code> للمرونة في التعامل مع أنواع المستندات الأخرى، رغم أننا نخزن المتغيرات الآن داخل الصنف، فعلى الأرجح أننا سنستخدم مجموعة عدادات أخرى عند تحليل ملفات HTML -مثل عدد الوسوم-، ونستطيع التعامل مع أي نوع من المستندات تقريبًا إذا جمعنا <code>resetCounters()‎</code> مع <code>formatResults()‎</code>، ووفرنا تابع <code>analyze()‎</code> جديد، أما التوابع الأخرى فهي أكثر استقرارًا، لأن قراءة أسطر الملف أمر قياسي بغض النظر عن نوعه، وضبط التعبيرين النمطيين فرصة جيدة للتدرب، فإذا لم نكن بحاجة إلى ذلك فلا نفعله.
</p>

<p>
	لدينا الآن وظائف مماثلة لنسخة وحدتنا الخاصة لكننا عبرنا عنها في صنف، ونريد أن نستغل الأسلوب الكائني من خلال فك أجزاء من صنفنا كي لا يحتوي المستوى الأساسي أو <code>Document</code> المجرد إلا على أجزاء عامة، وسننقل الأجزاء الخاصة بمعالجة النصوص إلى الصنف <code>TextDocument</code> أكثر تحديدًا، وتُعرف هذه العملية <a href="https://wiki.hsoub.com/Refactoring" rel="external">بإعادة التصميم (Refactoring)</a> في أوساط البرمجة الاحترافية، وسنرى كيفية تنفيذ ذلك فيما يلي.
</p>

<h2>
	المستند النصي
</h2>

<p>
	المستندات النصية مألوفة، لكننا يجب أن نتريث لنوضح الغرض من موازنة المستند النصي بالمفهوم العام للمستندات، تتكون المستندات النصية من محارف مرتبة في سطور، تحتوي مجموعات من الأحرف مرتبةً في كلمات تفصل بينها مسافات وعلامات ترقيم أخرى، وإذا جمعنا تلك الأسطر في مجموعات فسيتكون لدينا فقرات يُفصل بينها بأسطر فارغة.
</p>

<p>
	والمستند الافتراضي -يُطلق عليه vanilla document أو مستند الفانيليا أحيانًا في إشارة إلى نكهة المثلجات الافتراضية- يتكون من أسطر من المحارف التي لا نعرف عن صياغتها إلا القليل، لذا يجب أن يكون صنفنا <code>Document</code> الأساسي قادرًا على فتح الملف وقراءة محتوياته إلى قائمة من الأسطر، وربما يعيد عدد المحارف والأسطر مثلًا، كما يوفر توابع خطافيةً hook methods فارغةً للأصناف الفرعية الخاصة بالمستند لاستخدامها، لاحظ أن نص آسكي هو أحد أقدم وأبسط الطرق للتعبير عن النصوص، إلا أن الأبجديات التي أضيفت إليه وإضافة اليونيكود قد جعلته معقدًا.
</p>

<p>
	وفقًا لما شرحناه في الفقرات السابقة يجب أن يبدو الصنف Document كما يلي:
</p>

<pre class="ipsCode prettyprint lang-css prettyprinted" id="ips_uid_9828_59" style=""><span class="com">#############################</span><span class="pln">
</span><span class="com"># Module: document</span><span class="pln">
</span><span class="com"># Created: A.J. Gauld, 2010/12/15</span><span class="pln">
</span><span class="com"># Version 3</span><span class="pln">
</span><span class="com"># Function:</span><span class="pln">
</span><span class="str">''' Provides abstract Document class to count lines, characters
and provide hook methods for subclasses to use to process 
more specific document types'''</span><span class="pln">
</span><span class="com">#############################</span><span class="pln">

</span><span class="kwd">import</span><span class="pln"> sys</span><span class="pun">,</span><span class="pln">re

</span><span class="kwd">class</span><span class="pln"> </span><span class="typ">Document</span><span class="pun">:</span><span class="pln">
   </span><span class="kwd">def</span><span class="pln"> __init__</span><span class="pun">(</span><span class="kwd">self</span><span class="pun">,</span><span class="pln">filename</span><span class="pun">):</span><span class="pln">
       </span><span class="kwd">self</span><span class="pun">.</span><span class="pln">filename </span><span class="pun">=</span><span class="pln"> filename
       </span><span class="kwd">self</span><span class="pun">.</span><span class="pln">lines </span><span class="pun">=</span><span class="pln"> </span><span class="kwd">self</span><span class="pun">.</span><span class="pln">getLines</span><span class="pun">()</span><span class="pln">
       </span><span class="kwd">self</span><span class="pun">.</span><span class="pln">chars </span><span class="pun">=</span><span class="pln"> sum</span><span class="pun">(</span><span class="pln"> </span><span class="pun">[</span><span class="pln">len</span><span class="pun">(</span><span class="pln">L</span><span class="pun">)</span><span class="pln"> </span><span class="kwd">for</span><span class="pln"> L </span><span class="kwd">in</span><span class="pln"> </span><span class="kwd">self</span><span class="pun">.</span><span class="pln">lines</span><span class="pun">]</span><span class="pln"> </span><span class="pun">)</span><span class="pln">
       </span><span class="kwd">self</span><span class="pun">.</span><span class="pln">_initSeparators</span><span class="pun">()</span><span class="pln">

   </span><span class="kwd">def</span><span class="pln"> getLines</span><span class="pun">(</span><span class="kwd">self</span><span class="pun">):</span><span class="pln">
       f </span><span class="pun">=</span><span class="pln"> open</span><span class="pun">(</span><span class="kwd">self</span><span class="pun">.</span><span class="pln">filename</span><span class="pun">,</span><span class="str">'r'</span><span class="pun">)</span><span class="pln">
       lines </span><span class="pun">=</span><span class="pln"> f</span><span class="pun">.</span><span class="pln">readlines</span><span class="pun">()</span><span class="pln">
       f</span><span class="pun">.</span><span class="pln">close</span><span class="pun">()</span><span class="pln">
       </span><span class="kwd">return</span><span class="pln"> lines

   </span><span class="com"># قائمة بالتوابع الخطافية التي يجب تغييرها</span><span class="pln">
   </span><span class="kwd">def</span><span class="pln"> formatResults</span><span class="pun">(</span><span class="kwd">self</span><span class="pun">):</span><span class="pln">
   </span><span class="kwd">return</span><span class="pln"> </span><span class="str">"%s contains $d lines and %d characters"</span><span class="pln"> </span><span class="pun">%</span><span class="pln"> </span><span class="pun">(</span><span class="pln">len</span><span class="pun">(</span><span class="kwd">self</span><span class="pun">.</span><span class="pln">lines</span><span class="pun">),</span><span class="pln">
                                                      </span><span class="kwd">self</span><span class="pun">.</span><span class="pln">chars</span><span class="pun">)</span><span class="pln">
   </span><span class="kwd">def</span><span class="pln"> _initSeparators</span><span class="pun">(</span><span class="kwd">self</span><span class="pun">):</span><span class="pln"> </span><span class="kwd">pass</span><span class="pln"> 
   </span><span class="kwd">def</span><span class="pln"> analyze</span><span class="pun">(</span><span class="kwd">self</span><span class="pun">):</span><span class="pln"> </span><span class="kwd">pass</span></pre>

<p>
	نلاحظ أن التابع <code>‎_initSeparators</code> يحوي شرطةً سفليةً قبل اسمه، حيث يستخدم هذا الاصطلاح مبرمجو بايثون للإشارة أن هذا التابع لا يُستدعى إلا من داخل توابع الصنف، وليس مخصصًا ليصل إليه مستخدمو الكائن، ويسمى مثل هذا التابع أحيانًا في بعض اللغات الأخرى بالتابع المحمي protected أو الخاص private.
</p>

<p>
	كما نلاحظ أننا استخدمنا الدالة <code>sum()‎</code> لحساب عدد المحارف، وهي تعيد مجموع قائمة من الأعداد، والقائمة في حالتنا هي قائمة أطوال الأسطر في الملف المنتج بواسطة <code>list comprehension</code>.
</p>

<p>
	لم نوفر خيارًا قابلًا للتشغيل باستخدام <code>if __name__ == etc</code> لأن هذا الصنف مجرد abstract.
</p>

<p>
	يجب أن يبدو المستند النصي الآن كما يلي:
</p>

<pre class="ipsCode prettyprint lang-css prettyprinted" id="ips_uid_9828_61" style=""><span class="kwd">class</span><span class="pln"> </span><span class="typ">TextDocument</span><span class="pun">(</span><span class="typ">Document</span><span class="pun">):</span><span class="pln">
   </span><span class="kwd">def</span><span class="pln"> __init__</span><span class="pun">(</span><span class="kwd">self</span><span class="pun">,</span><span class="pln">filename</span><span class="pun">):</span><span class="pln">
       </span><span class="kwd">super</span><span class="pun">().</span><span class="pln">__init__</span><span class="pun">(</span><span class="pln">filename</span><span class="pun">)</span><span class="pln">
       </span><span class="kwd">self</span><span class="pun">.</span><span class="pln">paras </span><span class="pun">=</span><span class="pln"> </span><span class="lit">1</span><span class="pln">
       </span><span class="kwd">self</span><span class="pun">.</span><span class="pln">words</span><span class="pun">,</span><span class="pln"> </span><span class="kwd">self</span><span class="pun">.</span><span class="pln">sentences</span><span class="pun">,</span><span class="pln"> </span><span class="kwd">self</span><span class="pun">.</span><span class="pln">clauses </span><span class="pun">=</span><span class="pln"> </span><span class="lit">0</span><span class="pun">,</span><span class="lit">0</span><span class="pun">,</span><span class="lit">0</span><span class="pln">

   </span><span class="com"># غيّر الخطاطيف الآن   </span><span class="pln">
   </span><span class="kwd">def</span><span class="pln"> formatResults</span><span class="pun">(</span><span class="kwd">self</span><span class="pun">):</span><span class="pln">
       format </span><span class="pun">=</span><span class="pln"> </span><span class="str">'''
       The file %s contains:
             %d\t characters
             %d\t words
             %d\t lines in
             %d\t paragraphs with
             %d\t sentences and
             %d\t clauses.
       '''</span><span class="pln"> 
       </span><span class="kwd">return</span><span class="pln"> format </span><span class="pun">%</span><span class="pln"> </span><span class="pun">(</span><span class="kwd">self</span><span class="pun">.</span><span class="pln">filename</span><span class="pun">,</span><span class="pln"> </span><span class="kwd">self</span><span class="pun">.</span><span class="pln">chars</span><span class="pun">,</span><span class="pln">
                       </span><span class="kwd">self</span><span class="pun">.</span><span class="pln">words</span><span class="pun">,</span><span class="pln"> len</span><span class="pun">(</span><span class="kwd">self</span><span class="pun">.</span><span class="pln">lines</span><span class="pun">),</span><span class="pln"> 
                       </span><span class="kwd">self</span><span class="pun">.</span><span class="pln">paras</span><span class="pun">,</span><span class="pln"> </span><span class="kwd">self</span><span class="pun">.</span><span class="pln">sentences</span><span class="pun">,</span><span class="pln"> </span><span class="kwd">self</span><span class="pun">.</span><span class="pln">clauses</span><span class="pun">)</span><span class="pln">

   </span><span class="kwd">def</span><span class="pln"> _initSeparators</span><span class="pun">(</span><span class="kwd">self</span><span class="pun">):</span><span class="pln">
       sentenceMarks </span><span class="pun">=</span><span class="pln"> </span><span class="str">"[.!?]"</span><span class="pln">
       clauseMarks </span><span class="pun">=</span><span class="pln"> </span><span class="str">"[.!?,&amp;:;-]"</span><span class="pln">
       </span><span class="kwd">self</span><span class="pun">.</span><span class="pln">sentenceRE </span><span class="pun">=</span><span class="pln"> re</span><span class="pun">.</span><span class="pln">compile</span><span class="pun">(</span><span class="pln">sentenceMarks</span><span class="pun">)</span><span class="pln">
       </span><span class="kwd">self</span><span class="pun">.</span><span class="pln">clauseRE </span><span class="pun">=</span><span class="pln"> re</span><span class="pun">.</span><span class="pln">compile</span><span class="pun">(</span><span class="pln">clauseMarks</span><span class="pun">)</span><span class="pln">

   </span><span class="kwd">def</span><span class="pln"> analyze</span><span class="pun">(</span><span class="kwd">self</span><span class="pun">):</span><span class="pln">
       </span><span class="kwd">for</span><span class="pln"> line </span><span class="kwd">in</span><span class="pln"> </span><span class="kwd">self</span><span class="pun">.</span><span class="pln">lines</span><span class="pun">:</span><span class="pln">
          </span><span class="kwd">self</span><span class="pun">.</span><span class="pln">sentences </span><span class="pun">+=</span><span class="pln"> len</span><span class="pun">(</span><span class="kwd">self</span><span class="pun">.</span><span class="pln">sentenceRE</span><span class="pun">.</span><span class="pln">findall</span><span class="pun">(</span><span class="pln">line</span><span class="pun">))</span><span class="pln">
          </span><span class="kwd">self</span><span class="pun">.</span><span class="pln">clauses </span><span class="pun">+=</span><span class="pln"> len</span><span class="pun">(</span><span class="kwd">self</span><span class="pun">.</span><span class="pln">clauseRE</span><span class="pun">.</span><span class="pln">findall</span><span class="pun">(</span><span class="pln">line</span><span class="pun">))</span><span class="pln">
          </span><span class="kwd">self</span><span class="pun">.</span><span class="pln">words </span><span class="pun">+=</span><span class="pln"> len</span><span class="pun">(</span><span class="pln">line</span><span class="pun">.</span><span class="pln">split</span><span class="pun">())</span><span class="pln">
          </span><span class="kwd">self</span><span class="pun">.</span><span class="pln">chars </span><span class="pun">+=</span><span class="pln"> len</span><span class="pun">(</span><span class="pln">line</span><span class="pun">.</span><span class="pln">strip</span><span class="pun">())</span><span class="pln">
          </span><span class="kwd">if</span><span class="pln"> line</span><span class="pun">.</span><span class="pln">strip</span><span class="pun">()</span><span class="pln"> </span><span class="pun">==</span><span class="pln"> </span><span class="str">""</span><span class="pun">:</span><span class="pln">
             </span><span class="kwd">self</span><span class="pun">.</span><span class="pln">paras </span><span class="pun">+=</span><span class="pln"> </span><span class="lit">1</span><span class="pln">

</span><span class="kwd">if</span><span class="pln"> __name__ </span><span class="pun">==</span><span class="pln"> </span><span class="str">"__main__"</span><span class="pun">:</span><span class="pln">
     </span><span class="kwd">if</span><span class="pln"> len</span><span class="pun">(</span><span class="pln">sys</span><span class="pun">.</span><span class="pln">argv</span><span class="pun">)</span><span class="pln"> </span><span class="pun">==</span><span class="pln"> </span><span class="lit">2</span><span class="pun">:</span><span class="pln">
         doc </span><span class="pun">=</span><span class="pln"> </span><span class="typ">TextDocument</span><span class="pun">(</span><span class="pln">sys</span><span class="pun">.</span><span class="pln">argv</span><span class="pun">[</span><span class="lit">1</span><span class="pun">])</span><span class="pln">
         doc</span><span class="pun">.</span><span class="pln">analyze</span><span class="pun">()</span><span class="pln">
         </span><span class="kwd">print</span><span class="pun">(</span><span class="pln"> doc</span><span class="pun">.</span><span class="pln">formatResults</span><span class="pun">()</span><span class="pln"> </span><span class="pun">)</span><span class="pln">
     </span><span class="kwd">else</span><span class="pun">:</span><span class="pln">
         </span><span class="kwd">print</span><span class="pun">(</span><span class="pln"> </span><span class="str">"Usage: python &lt;document&gt; "</span><span class="pln"> </span><span class="pun">)</span><span class="pln">
         </span><span class="kwd">print</span><span class="pun">(</span><span class="pln"> </span><span class="str">"Failed to analyze file"</span><span class="pln"> </span><span class="pun">)</span></pre>

<p>
	يحقق دمج الأصناف هذا نفس ما يحققه الإصدار غير الكائني الأول، وإذا وازنّا بين طول هذه النسخة وطول الملف الأصلي فسندرك أن بناء كائنات قابلة لإعادة الاستخدام ليس سهلًا، لذا ينبغي أن نكتب إصدارات غير كائنية دومًا؛ ما لم نكن بحاجة إلى إعادة استخدام الكائنات، كأن نخطط لتوسيع التصميم مستقبلًا، كما سنفعل بعد قليل.
</p>

<p>
	ومن المهم أن نراعي الموقع الفعلي للشيفرة، فقد كان بإمكاننا عرض إنشاء ملفين، واحد لكل صنف، وهو سلوك شائع في البرمجة الكائنية، ويحافظ على النظام العام، رغم أنه يكون على حساب كثير من الملفات الصغيرة، وكثير من تعليمات الاستيراد في الشيفرة عند استخدام تلك الملفات أو الأصناف.
</p>

<p>
	ونفضل أن نعامل الأصناف المرتبطة ببعضها بشدة مثل مجموعة، ونضعها جميعًا في ملف واحد، بما يكفي على الأقل لإنشاء برنامج صغير عامل، لذا جمعنا الصنفين <code>Document</code> و<code>TextDocument</code> في وحدة واحدة، وميزة ذلك أن الصنف العامل يوفر قالبًا للمستخدمين ليقرؤوه مثالًا على توسيع الصنف المجرد، لكن عيبه أن أي تعديل في <code>TextDocument</code> سيؤثر على صنف المستند، وبالتالي سيعطل أجزاءً من الشيفرة، فلا يوجد حل صالح هنا، وتوجد أمثلة على كلا النمطين في مكتبة بايثون، فاختر أحدهما والتزم به.
</p>

<p>
	من مصادر المعلومات المفيدة في مثل هذا النوع من التعديل على الملفات النصية كتاب "معالجة النصوص في بايثون" أو Text Processing in Python لـ David Mertz، لكن لاحظ أن هذا الكتاب متقدم وموجه إلى المبرمجين المحترفين، لذا قد تجد صعوبةً في استيعاب مادته إذا كنت مبتدئًا في البرمجة، لكنك ستجد فيه دروسًا مفيدةً للغاية بالمثابرة والتعلم.
</p>

<h2>
	مستند HTML
</h2>

<p>
	الخطوة التالية في تطوير تطبيقنا هي توسيع إمكانياته لنستطيع تحليل مستندات HTML، وسنفعل ذلك بإنشاء صنف جديد، وبما أن مستند HTML ما هو إلا مستند نصي يحتوي على الكثير من وسوم HTML وقسم للترويسة في الأعلى؛ فكل ما نحتاج إليه هو حذف هذه العناصر الإضافية ومعاملته بعدها على أنه نص عادي، لذا سننشئ صنفًا جديدًا نسميه <code>HTMLDocument</code> مشتقًا من <code>TextDocument</code>، وسنغير التابع <code>getLines()‎</code> الذي ورثناه من <code>Document</code> بحيث يحذف الترويسة ووسوم HTML.
</p>

<p>
	سيبدو الصنف HTMLDocument الآن كما يلي:
</p>

<pre class="ipsCode prettyprint lang-html prettyprinted" id="ips_uid_9828_63" style=""><span class="pln">class HTMLDocument(TextDocument):
    def getLines(self):
       lines = super().getLines()
       lines = self._stripHeader(lines)
       lines = self._stripTags(lines)
       return lines

    def _stripHeader(self,lines):
       ''' remove all lines up until start of body '''
       bodyMark = '</span><span class="tag">&lt;body&gt;</span><span class="pln">'
       bodyRE = re.compile(bodyMark,re.IGNORECASE)
       while bodyRE.findall(lines[0]) == []:
          del lines[0]
       return lines

    def _stripTags(self,lines):
       ''' remove anything between &lt; and &gt;, not perfect but ok for now'''
       tagMark = '&lt;.+&gt;'
       tagRE = re.compile(tagMark)
       lines2 = []
       for line in lines:
           line = tagRE.sub('',line).strip()
           if line: lines2.append(line)
       return lines2</span></pre>

<p>
	استخدمنا التابع الموروث داخل <code>getLines</code>، وهذا سلوك شائع عند توسيع تابع موروث،حيث ننفذ ذلك بمعالجة أولية، أو نستدعي الشيفرة الموروثة ثم نكمل باقي العمل في الصنف الجديد كما فعلنا هنا، وينفّضذ هذا في التابع <code>__init__</code> الخاص بالصنف <code>TextDocument</code> أعلاه.
</p>

<p>
	وصلنا إلى التابع الموروث <code>getLines</code> من خلال <code>super()‎</code>، رغم أن التابع معرَّف فعليًا في الصنف <code>Document</code> المجرد في الأعلى، ويرث <code>TextDocument</code> جميع مزايا <code>Document</code>، وبالتالي يحتوي على <code>getLines</code> أيضًا، وهكذا نرى أن بايثون و<code>super</code> تجدان التابع المناسب دومًا.
</p>

<p>
	أما التابعان الآخران فهما محميان نظريًا -كما هو واضح من الشرطة السفلية قبل اسميهما-، وهما هنا لإبقاء المنطق مستقلًا، ولتسهيل توسيع هذا الصنف في المستقبل إلى مستند XHTML أو XML مثلًا، فتدرب على بناء أحدهما.
</p>

<p>
	من الصعب أن نحذف جميع وسوم HTML باستخدام التعابير النمطية بسبب إمكانية تشعب الوسوم، وبسبب احتمال حدوث خطأ في احتساب محرفي <code>&lt;</code> و<code>&gt;</code> غير المهرَّبيْن على أنهما وسوم في حين أنهما ليسا كذلك، كما أن الوسوم قد تأتي على أكثر من سطر، وغير ذلك من احتمالات الخطأ الواردة، فالأسلم هنا استخدام محلل HTML -مثل الموجود في وحدة <code>html.parser</code> القياسية- لتحويل ملفات HTML إلى نص عادي، لذا أعد كتابة الصنف <code>HTMLDocument</code> لتستخدم وحدة المحلل هنا لتوليد الأسطر النصية.
</p>

<p>
	نحتاج الآن إلى تعديل شيفرة التعريف في نهاية الملف لتكون على الصورة التالية من أجل اختبار HTMLDocument:
</p>

<pre class="ipsCode">if __name__ == "__main__":
       if len(sys.argv) == 2:
         doc = HTMLDocument(sys.argv[1])
         doc.analyze()
         print( doc.formatResults() )
       else:
         print( "Usage: python &lt;document&gt; " )
         print( "Failed to analyze file" )
</pre>

<p>
	وإذا كنت على دراية ببعض أنواع الملفات الأخرى مثل ملفات PDF و LaTeX و RTF و Postscript وغيرها، فهل تستطيع إنشاء أصناف تحقق وفحص لها؟
</p>

<h2>
	إضافة واجهة رسومية
</h2>

<p>
	سنستخدم Tkinter الذي شرحناه باختصار في <a href="https://academy.hsoub.com/programming/general/%D8%A7%D9%84%D8%A8%D8%B1%D9%85%D8%AC%D8%A9-%D8%A7%D9%84%D8%AD%D8%AF%D8%AB%D9%8A%D8%A9-event-driven-programming-%D8%A7%D9%84%D9%85%D8%B3%D8%A7%D9%82%D8%A9-%D8%A8%D8%A7%D9%84%D8%A3%D8%AD%D8%AF%D8%A7%D8%AB-r1376/" rel="">مقال البرمجة الحدَثية</a>، ثم توسعنا فيه بتفصيل أكثر في مقال برمجة الواجهات الرسومية المشار إليه بالأعلى، أما هنا فستكون الواجهة الرسومية أكثر تعقيدًا وتستخدم مزيدًا من الودجات widgets التي يوفرها Tk، ومن العوامل التي ستعيننا على إنشاء النسخة الرسومية تجنبنا لوضع أي تعليمات طباعة في أصنافنا، ووضعنا لطباعة الخرج في شيفرة التعريف بدلًا من ذلك، وهذا سيفيدنا حين نستخدم الواجهة الرسومية، حيث سنستطيع استخدام سلسلة الخرج نفسها وعرضها في ودجت، بدلًا من طباعتها على مجرى الخرج القياسي stdout، ويُعد تغليف التطبيق في واجهة رسومية بسهولة من أهم الأسباب التي نتجنب استخدام تعليمات الطباعة في الدوال أو التوابع الخاصة بمعالجة البيانات لأجلها.
</p>

<h3>
	تصميم الواجهة الرسومية
</h3>

<p>
	إن الخطوة الأولى في بناء أي برنامج رسومي هي محاولة تصور شكله النهائي، فمثلًا سنحتاج إلى تحديد اسم ملف، لذا سنضيف متحكمًا للتعديل أو الإدخال النصي، كما سنحدد إذا كنا نريد تحليل ملف نصي أم ملف HTML، فنمثل هذا الاختيار من متعدد بمجموعة من متحكمات أزرار الانتقاء radiobuttons، ويجب أن تُجمع هذه الأزرار معًا لإظهار ارتباطها ببعضها.
</p>

<p>
	أما الشرط الثاني فهو أسلوب عرض النتائج، ورغم أنه يمكن اعتماد عدة متحكمات للعناوين؛ بحيث يكون لدينا عنوان لكل عداد، إلا أننا سنستخدم متحكمًا نصيًا بسيطًا نستطيع إدخال سلاسل نصية فيه، وهو بهذا أقرب إلى خرج سطر الأوامر، مع أن هذا يرجع بالنهاية لمصمم البرنامج، لكن هذا التصميم الذي سنعتمده لن يكون الأجمل مظهرًا.
</p>

<p>
	وأخيرًا نحتاج إلى وسيلة لبدء التحليل والخروج من التطبيق، وبما أننا نستخدم متحكمًا نصيًا لعرض النتائج؛ فقد يكون من الأفضل أن يكون لدينا وسيلة لإعادة ضبط الشاشة، ويمكن تمثيل جميع خيارات الأوامر بمتحكمات أزرار.
</p>

<p>
	إذا رسمنا هذه الأفكار أعلاه فقد نحصل على شكل قريب مما يلي:
</p>

<pre class="ipsCode prettyprint lang-py prettyprinted" id="ips_uid_9828_70" style=""><span class="pun">+-------------------------+-----------+</span><span class="pln">
</span><span class="pun">|</span><span class="pln">    FILENAME             </span><span class="pun">|</span><span class="pln"> O TEXT    </span><span class="pun">|</span><span class="pln">
</span><span class="pun">|</span><span class="pln">                         </span><span class="pun">|</span><span class="pln"> O HTML    </span><span class="pun">|</span><span class="pln">
</span><span class="pun">+-------------------------+-----------+</span><span class="pln">
</span><span class="pun">|</span><span class="pln">                                     </span><span class="pun">|</span><span class="pln">
</span><span class="pun">|</span><span class="pln">                                     </span><span class="pun">|</span><span class="pln">
</span><span class="pun">|</span><span class="pln">                                     </span><span class="pun">|</span><span class="pln">
</span><span class="pun">|</span><span class="pln">                                     </span><span class="pun">|</span><span class="pln">
</span><span class="pun">|</span><span class="pln">                                     </span><span class="pun">|</span><span class="pln">
</span><span class="pun">+-------------------------------------+</span><span class="pln">
</span><span class="pun">|</span><span class="pln">                                     </span><span class="pun">|</span><span class="pln">
</span><span class="pun">|</span><span class="pln">   ANALYZE      RESET       QUIT     </span><span class="pun">|</span><span class="pln">
</span><span class="pun">|</span><span class="pln">                                     </span><span class="pun">|</span><span class="pln">
</span><span class="pun">+-------------------------------------+</span></pre>

<p>
	يشبه هذا التصميم ثلاثة إطارات بالعرض الكامل فوق بعضها، وفي الإطار العلوي إطاران جنبًا إلى جنب، ويحتوي الإطار الأيمن العلوي على زري انتقاء مرتبين رأسيًا، أما الإطار السفلي فيحتوي على ثلاثة أزرار مرتبة أفقيًا، ونستطيع استخدام تخطيط المحزِّم pack لكل ما سبق، وبهذا نعلم الودجات التي نحتاج إليها، ومدير التخطيط المطلوب لكل إطار، ويتبقى لدينا مزية واحدة جديدة، وهي أزرار الانتقاء، وسننظر فيها لاحقًا.
</p>

<p>
	لنحول ما سبق إلى شيفرة:
</p>

<pre class="ipsCode prettyprint lang-py prettyprinted" id="ips_uid_9828_68" style=""><span class="kwd">import</span><span class="pln"> tkinter </span><span class="kwd">as</span><span class="pln"> tk
</span><span class="kwd">import</span><span class="pln"> document


</span><span class="com">################### CLASS DEFINITIONS ######################</span><span class="pln">
</span><span class="kwd">class</span><span class="pln"> </span><span class="typ">GrammarApp</span><span class="pun">(</span><span class="typ">Frame</span><span class="pun">):</span><span class="pln">
  </span><span class="kwd">def</span><span class="pln"> __init__</span><span class="pun">(</span><span class="pln">self</span><span class="pun">,</span><span class="pln"> parent</span><span class="pun">=</span><span class="lit">0</span><span class="pun">):</span><span class="pln">
    super</span><span class="pun">().</span><span class="pln">__init__</span><span class="pun">(</span><span class="pln">parent</span><span class="pun">)</span><span class="pln">
    self</span><span class="pun">.</span><span class="pln">type </span><span class="pun">=</span><span class="pln"> </span><span class="lit">1</span><span class="pln">    </span><span class="com"># create variable with default value</span><span class="pln">
    self</span><span class="pun">.</span><span class="pln">master</span><span class="pun">.</span><span class="pln">title</span><span class="pun">(</span><span class="str">'Grammar counter'</span><span class="pun">)</span><span class="pln">
    self</span><span class="pun">.</span><span class="pln">buildUI</span><span class="pun">()</span></pre>

<p>
	استوردنا وحدتي <code>tkinter</code> و<code>document</code>، وجعلنا كل أسماء Tkinter مرئيةً داخل الوحدة الحالية، أما بالنسبة للوحدة الثانية فسنحتاج إلى سبق الأسماء بـ <code>document.</code>.
</p>

<p>
	كما عرَّفنا التطبيق على أنه صنف فرعي للصنف <code>Frame</code>، ويستدعي التابع <code>__init__</code> تابع الصنف الرئيسي <code>Frame.__init__‎</code> لضمان إعداد Tk بالطريقة الصحيحة داخليًا، ثم ننشئ سمةً تخزن قيمة نوع المستند، ونستدعي التابع <code>buildUI</code> الذي ينشئ جميع الودجات لنا، وسننظر الآن فيه:
</p>

<pre class="ipsCode prettyprint lang-py prettyprinted" id="ips_uid_9828_72" style=""><span class="pln">   </span><span class="kwd">def</span><span class="pln"> buildUI</span><span class="pun">(</span><span class="pln">self</span><span class="pun">):</span><span class="pln">
     </span><span class="com"># إطار الخيارات أولًا</span><span class="pln">
     </span><span class="com"># - اسم الملف ونوعه</span><span class="pln">
     fOpts </span><span class="pun">=</span><span class="pln"> tk</span><span class="pun">.</span><span class="typ">Frame</span><span class="pun">(</span><span class="pln">self</span><span class="pun">)</span><span class="pln">
     fFile </span><span class="pun">=</span><span class="pln"> tk</span><span class="pun">.</span><span class="typ">Frame</span><span class="pun">(</span><span class="pln">fOpts</span><span class="pun">)</span><span class="pln">
     tk</span><span class="pun">.</span><span class="typ">Label</span><span class="pun">(</span><span class="pln">fFile</span><span class="pun">,</span><span class="pln"> text</span><span class="pun">=</span><span class="str">"Filename: "</span><span class="pun">).</span><span class="pln">pack</span><span class="pun">(</span><span class="pln">side</span><span class="pun">=</span><span class="str">"left"</span><span class="pun">)</span><span class="pln">
     self</span><span class="pun">.</span><span class="pln">eName </span><span class="pun">=</span><span class="pln"> tk</span><span class="pun">.</span><span class="typ">Entry</span><span class="pun">(</span><span class="pln">fFile</span><span class="pun">)</span><span class="pln">
     self</span><span class="pun">.</span><span class="pln">eName</span><span class="pun">.</span><span class="pln">insert</span><span class="pun">(</span><span class="pln">tk</span><span class="pun">.</span><span class="pln">INSERT</span><span class="pun">,</span><span class="str">"test.htm"</span><span class="pun">)</span><span class="pln">
     self</span><span class="pun">.</span><span class="pln">eName</span><span class="pun">.</span><span class="pln">pack</span><span class="pun">(</span><span class="pln">side</span><span class="pun">=</span><span class="str">'left'</span><span class="pun">,</span><span class="pln"> padx</span><span class="pun">=</span><span class="lit">5</span><span class="pun">)</span><span class="pln">
     fFile</span><span class="pun">.</span><span class="pln">pack</span><span class="pun">(</span><span class="pln">side</span><span class="pun">=</span><span class="str">'left'</span><span class="pun">,</span><span class="pln"> padx</span><span class="pun">=</span><span class="lit">3</span><span class="pun">)</span><span class="pln">

     </span><span class="com"># والآن أزرار الانتقاء</span><span class="pln">
     fType </span><span class="pun">=</span><span class="pln"> </span><span class="typ">Frame</span><span class="pun">(</span><span class="pln">fFile</span><span class="pun">,</span><span class="pln"> borderwidth</span><span class="pun">=</span><span class="lit">1</span><span class="pun">,</span><span class="pln"> relief</span><span class="pun">=</span><span class="pln">tk</span><span class="pun">.</span><span class="pln">SUNKEN</span><span class="pun">)</span><span class="pln">
     self</span><span class="pun">.</span><span class="pln">rText </span><span class="pun">=</span><span class="pln"> </span><span class="typ">Radiobutton</span><span class="pun">(</span><span class="pln">fType</span><span class="pun">,</span><span class="pln"> text</span><span class="pun">=</span><span class="str">"TEXT"</span><span class="pun">,</span><span class="pln">
                              variable </span><span class="pun">=</span><span class="pln"> self</span><span class="pun">.</span><span class="pln">type</span><span class="pun">,</span><span class="pln"> value</span><span class="pun">=</span><span class="lit">1</span><span class="pun">,</span><span class="pln"> 
                              command</span><span class="pun">=</span><span class="pln">self</span><span class="pun">.</span><span class="pln">doText</span><span class="pun">)</span><span class="pln">
     self</span><span class="pun">.</span><span class="pln">rText</span><span class="pun">.</span><span class="pln">pack</span><span class="pun">(</span><span class="pln">side</span><span class="pun">=</span><span class="pln">tk</span><span class="pun">.</span><span class="pln">TOP</span><span class="pun">,</span><span class="pln"> anchor</span><span class="pun">=</span><span class="pln">tk</span><span class="pun">.</span><span class="pln">W</span><span class="pun">)</span><span class="pln">
     self</span><span class="pun">.</span><span class="pln">rHTML </span><span class="pun">=</span><span class="pln"> </span><span class="typ">Radiobutton</span><span class="pun">(</span><span class="pln">fType</span><span class="pun">,</span><span class="pln"> text</span><span class="pun">=</span><span class="str">"HTML"</span><span class="pun">,</span><span class="pln">
                              variable</span><span class="pun">=</span><span class="pln">self</span><span class="pun">.</span><span class="pln">type</span><span class="pun">,</span><span class="pln"> value</span><span class="pun">=</span><span class="lit">2</span><span class="pun">,</span><span class="pln">
                              command</span><span class="pun">=</span><span class="pln">self</span><span class="pun">.</span><span class="pln">doHTML</span><span class="pun">)</span><span class="pln">
     self</span><span class="pun">.</span><span class="pln">rHTML</span><span class="pun">.</span><span class="pln">pack</span><span class="pun">(</span><span class="pln">side</span><span class="pun">=</span><span class="pln">tk</span><span class="pun">.</span><span class="pln">TOP</span><span class="pun">,</span><span class="pln"> anchor</span><span class="pun">=</span><span class="pln">tk</span><span class="pun">.</span><span class="pln">W</span><span class="pun">)</span><span class="pln">

     </span><span class="com"># هو الخيار الافتراضي TEXT اجعل </span><span class="pln">
     self</span><span class="pun">.</span><span class="pln">rText</span><span class="pun">.</span><span class="pln">select</span><span class="pun">()</span><span class="pln">
     fType</span><span class="pun">.</span><span class="pln">pack</span><span class="pun">(</span><span class="pln">side</span><span class="pun">=</span><span class="pln">tk</span><span class="pun">.</span><span class="pln">RIGHT</span><span class="pun">,</span><span class="pln"> padx</span><span class="pun">=</span><span class="lit">3</span><span class="pun">)</span><span class="pln">
     fOpts</span><span class="pun">.</span><span class="pln">pack</span><span class="pun">(</span><span class="pln">side</span><span class="pun">=</span><span class="pln">tk</span><span class="pun">.</span><span class="pln">TOP</span><span class="pun">,</span><span class="pln"> fill</span><span class="pun">=</span><span class="pln">tk</span><span class="pun">.</span><span class="pln">X</span><span class="pun">)</span><span class="pln">


     </span><span class="com"># يحتوي الصندوق النصي على الخرج، فأضف له حشوة</span><span class="pln">
     </span><span class="com"># (self أي) لإضافة حد إليه، واجعل الأب هو إطار التطبيق</span><span class="pln">
     self</span><span class="pun">.</span><span class="pln">txtBox </span><span class="pun">=</span><span class="pln"> </span><span class="typ">Text</span><span class="pun">(</span><span class="pln">self</span><span class="pun">,</span><span class="pln"> width</span><span class="pun">=</span><span class="lit">60</span><span class="pun">,</span><span class="pln"> height</span><span class="pun">=</span><span class="lit">10</span><span class="pun">)</span><span class="pln">
     self</span><span class="pun">.</span><span class="pln">txtBox</span><span class="pun">.</span><span class="pln">pack</span><span class="pun">(</span><span class="pln">side</span><span class="pun">=</span><span class="pln">tk</span><span class="pun">.</span><span class="pln">TOP</span><span class="pun">,</span><span class="pln"> padx</span><span class="pun">=</span><span class="lit">3</span><span class="pun">,</span><span class="pln"> pady</span><span class="pun">=</span><span class="lit">3</span><span class="pun">)</span><span class="pln">


     </span><span class="com"># ضع بعض أزرار التحكم</span><span class="pln">
     fButts </span><span class="pun">=</span><span class="pln"> </span><span class="typ">Frame</span><span class="pun">(</span><span class="pln">self</span><span class="pun">)</span><span class="pln">
     self</span><span class="pun">.</span><span class="pln">bAnal </span><span class="pun">=</span><span class="pln"> </span><span class="typ">Button</span><span class="pun">(</span><span class="pln">fButts</span><span class="pun">,</span><span class="pln"> text</span><span class="pun">=</span><span class="str">"Analyze"</span><span class="pun">,</span><span class="pln">
                         command</span><span class="pun">=</span><span class="pln">self</span><span class="pun">.</span><span class="pln">doAnalyze</span><span class="pun">)</span><span class="pln">
     self</span><span class="pun">.</span><span class="pln">bAnal</span><span class="pun">.</span><span class="pln">pack</span><span class="pun">(</span><span class="pln">side</span><span class="pun">=</span><span class="pln">tk</span><span class="pun">.</span><span class="pln">LEFT</span><span class="pun">,</span><span class="pln"> anchor</span><span class="pun">=</span><span class="pln">tk</span><span class="pun">.</span><span class="pln">W</span><span class="pun">,</span><span class="pln"> padx</span><span class="pun">=</span><span class="lit">50</span><span class="pun">,</span><span class="pln"> pady</span><span class="pun">=</span><span class="lit">2</span><span class="pun">)</span><span class="pln">
     self</span><span class="pun">.</span><span class="pln">bReset </span><span class="pun">=</span><span class="pln"> </span><span class="typ">Button</span><span class="pun">(</span><span class="pln">fButts</span><span class="pun">,</span><span class="pln"> text</span><span class="pun">=</span><span class="str">"Reset"</span><span class="pun">,</span><span class="pln">
                          command</span><span class="pun">=</span><span class="pln">self</span><span class="pun">.</span><span class="pln">doReset</span><span class="pun">)</span><span class="pln">
     self</span><span class="pun">.</span><span class="pln">bReset</span><span class="pun">.</span><span class="pln">pack</span><span class="pun">(</span><span class="pln">side</span><span class="pun">=</span><span class="pln">tk</span><span class="pun">.</span><span class="pln">LEFT</span><span class="pun">,</span><span class="pln"> padx</span><span class="pun">=</span><span class="lit">10</span><span class="pun">)</span><span class="pln">
     self</span><span class="pun">.</span><span class="pln">bQuit </span><span class="pun">=</span><span class="pln"> </span><span class="typ">Button</span><span class="pun">(</span><span class="pln">fButts</span><span class="pun">,</span><span class="pln"> text</span><span class="pun">=</span><span class="str">"Quit"</span><span class="pun">,</span><span class="pln">
                         command</span><span class="pun">=</span><span class="pln">self</span><span class="pun">.</span><span class="pln">quit</span><span class="pun">)</span><span class="pln">
     self</span><span class="pun">.</span><span class="pln">bQuit</span><span class="pun">.</span><span class="pln">pack</span><span class="pun">(</span><span class="pln">side</span><span class="pun">=</span><span class="pln">tk</span><span class="pun">.</span><span class="pln">RIGHT</span><span class="pun">,</span><span class="pln"> anchor</span><span class="pun">=</span><span class="pln">tk</span><span class="pun">.</span><span class="pln">E</span><span class="pun">,</span><span class="pln"> padx</span><span class="pun">=</span><span class="lit">50</span><span class="pun">,</span><span class="pln"> pady</span><span class="pun">=</span><span class="lit">2</span><span class="pun">)</span><span class="pln">

     fButts</span><span class="pun">.</span><span class="pln">pack</span><span class="pun">(</span><span class="pln">side</span><span class="pun">=</span><span class="pln">tk</span><span class="pun">.</span><span class="pln">BOTTOM</span><span class="pun">,</span><span class="pln"> fill</span><span class="pun">=</span><span class="pln">tk</span><span class="pun">.</span><span class="pln">X</span><span class="pun">)</span><span class="pln">
     self</span><span class="pun">.</span><span class="pln">pack</span><span class="pun">()</span></pre>

<p>
	لن نشرح كل هذا إذ يجب أن يكون مفهومًا لمن قرأ الفصل التاسع عشر: برمجة الواجهات الرسومية، أما لمن أراد الاستزادة فعليه فيمكنه الرجوع إلى مراجع وتوثيقات أخرى خارجية، والقاعدة العامة هي أن ننشئ ودجات من أصنافها الموافقة لها، ونوفر الخيارات مثل معاملات ذوات أسماء، ثم نحزّم الودجت في إطارها الحاوي لها.
</p>

<p>
	كذلك قد ترغب في تجربة إضافة زر "browse" الذي يفتح صندوق FileOpen الحواري، ويمكن تنفيذ ذلك باستخدام صناديق Tk الافتراضية، انظر الدليل أعلاه لمزيد من الشرح.
</p>

<p>
	أما النقاط الأخرى التي يجب ملاحظتها فهي استخدام ودجات <code>Frame</code> الفرعية لتحوي أزرار الانتقاء <code>Radiobuttons</code> وأزرار الأوامر <code>Button</code>، كما تأخذ أزرار الانتقاء زوجًا من الخيارات هما <code>variable</code> و<code>value</code>، ويربط الأول أزرار الانتقاء معًا، من خلال تحديد نفس المتغير الخارجي <code>self.type</code>، ويعطي الخيار الثاني قيمةً فريدةً لكل زر منها.
</p>

<p>
	لاحظ أيضًا الخيارات <code>command=xxx</code> الممررة إلى المتحكمات، فهي توابع سيستدعيها Tk عند الضغط على الزر.
</p>

<p>
	الشيفرة الممثلة لما سبق هي كما يلي:
</p>

<pre class="ipsCode prettyprint lang-py prettyprinted" id="ips_uid_9828_74" style=""><span class="pln">   </span><span class="com">################# EVENT HANDLING METHODS ####################</span><span class="pln">

   </span><span class="com"># استعد الإعدادات الافتراضية</span><span class="pln">
   </span><span class="kwd">def</span><span class="pln"> doReset</span><span class="pun">(</span><span class="pln">self</span><span class="pun">):</span><span class="pln">
     self</span><span class="pun">.</span><span class="pln">txtBox</span><span class="pun">.</span><span class="pln">delete</span><span class="pun">(</span><span class="lit">1.0</span><span class="pun">,</span><span class="pln"> tk</span><span class="pun">.</span><span class="pln">END</span><span class="pun">)</span><span class="pln">
     self</span><span class="pun">.</span><span class="pln">rText</span><span class="pun">.</span><span class="pln">select</span><span class="pun">()</span><span class="pln">

   </span><span class="com"># اضبط قيم الانتقاء</span><span class="pln">
   </span><span class="kwd">def</span><span class="pln"> doText</span><span class="pun">(</span><span class="pln">self</span><span class="pun">):</span><span class="pln">
     self</span><span class="pun">.</span><span class="pln">type </span><span class="pun">=</span><span class="pln"> </span><span class="lit">1</span><span class="pln">

   </span><span class="kwd">def</span><span class="pln"> doHTML</span><span class="pun">(</span><span class="pln">self</span><span class="pun">):</span><span class="pln">
     self</span><span class="pun">.</span><span class="pln">type </span><span class="pun">=</span><span class="pln"> </span><span class="lit">2</span></pre>

<blockquote class="ipsQuote" data-ipsquote="">
	<div class="ipsQuote_citation">
		اقتباس
	</div>

	<p data-gramm="false">
		تأتي أزرار الانتقاء مع القليل من سحر Tk الذي يسمح لها أن تُربط مع أنواع خاصة من متغيرات بايثون، بحيث إذا ضُغط على الزر فستُسند قيمته تلقائيًا إلى المتغير المرتبط به، ولم نستخدم هذه التقنية لأنها خاصة بصندوق Tk وحده، واستخدمنا الآلية المعتادة لمعالجة الأحداث بدلًا منها ليكون الشرح واضحًا، وليكون صريحًا في الدالة.
	</p>

	<p>
		للاطلاع على المزيد حول الخيار المؤتمت فانظر <code>IntVar</code> و<code>StringVar</code> في توثيق <a href="https://docs.python.org/3/library/tkinter.html" rel="external nofollow">Tkinter</a>، حيث يمكن استخدام هذه الأنواع الخاصة من المتغيرات مع العديد من ودجات ضبط القيم في Tk، لكنها خارج نطاق شرحنا.
	</p>
</blockquote>

<p>
	يتبقى لدينا آخر معالج أحداث، وهو الذي ينفذ التحليل:
</p>

<pre class="ipsCode prettyprint lang-py prettyprinted" id="ips_uid_9828_76" style=""><span class="pln">   </span><span class="com"># أنشئ نوع المستند المناسب وحلله.</span><span class="pln">
   </span><span class="com"># ثم اعرض النتائج في الاستمارة</span><span class="pln">
   </span><span class="kwd">def</span><span class="pln"> doAnalyze</span><span class="pun">(</span><span class="pln">self</span><span class="pun">):</span><span class="pln">
     filename </span><span class="pun">=</span><span class="pln"> self</span><span class="pun">.</span><span class="pln">eName</span><span class="pun">.</span><span class="pln">get</span><span class="pun">()</span><span class="pln">
     </span><span class="kwd">if</span><span class="pln"> filename </span><span class="pun">==</span><span class="pln"> </span><span class="str">""</span><span class="pun">:</span><span class="pln">
        self</span><span class="pun">.</span><span class="pln">txtBox</span><span class="pun">.</span><span class="pln">insert</span><span class="pun">(</span><span class="pln">tk</span><span class="pun">.</span><span class="pln">END</span><span class="pun">,</span><span class="str">"\nNo filename provided!\n"</span><span class="pun">)</span><span class="pln">
        </span><span class="kwd">return</span><span class="pln">
     </span><span class="kwd">if</span><span class="pln"> self</span><span class="pun">.</span><span class="pln">type </span><span class="pun">==</span><span class="pln"> </span><span class="lit">1</span><span class="pun">:</span><span class="pln">
        doc </span><span class="pun">=</span><span class="pln"> document</span><span class="pun">.</span><span class="typ">TextDocument</span><span class="pun">(</span><span class="pln">filename</span><span class="pun">)</span><span class="pln">
     </span><span class="kwd">else</span><span class="pun">:</span><span class="pln">
        doc </span><span class="pun">=</span><span class="pln"> document</span><span class="pun">.</span><span class="typ">HTMLDocument</span><span class="pun">(</span><span class="pln">filename</span><span class="pun">)</span><span class="pln">
     self</span><span class="pun">.</span><span class="pln">txtBox</span><span class="pun">.</span><span class="pln">insert</span><span class="pun">(</span><span class="pln">tk</span><span class="pun">.</span><span class="pln">END</span><span class="pun">,</span><span class="pln"> </span><span class="str">"\nAnalyzing...\n"</span><span class="pun">)</span><span class="pln">
     doc</span><span class="pun">.</span><span class="pln">analyze</span><span class="pun">()</span><span class="pln">
     resultStr </span><span class="pun">=</span><span class="pln"> doc</span><span class="pun">.</span><span class="pln">formatResults</span><span class="pun">()</span><span class="pln">
     self</span><span class="pun">.</span><span class="pln">txtBox</span><span class="pun">.</span><span class="pln">insert</span><span class="pun">(</span><span class="pln">tk</span><span class="pun">.</span><span class="pln">END</span><span class="pun">,</span><span class="pln"> resultStr</span><span class="pun">)</span></pre>

<p>
	تتحقق هذه الشيفرة من وجود اسم ملف صالح قبل إنشاء كائن المستند، رغم أنها قد لا تتحقق من صلاحية الاسم.
</p>

<p>
	تستخدم قيمة <code>self.type</code> المحددة بواسطة أزرار الانتقاء لتحديد نوع المستند الذي يجب إنشاؤه.
</p>

<p>
	تلحَق النتائج بالحقل النصي -الوسيط <code>tk.END</code> في <code>insert</code>- مما يعني أننا نستطيع التحليل عدة مرات وموازنة النتائج، وهذه ميزة الصندوق النصي هنا عن أسلوب خرج العناوين المتعددة multiple label output.
</p>

<p>
	وكل ما نحتاج إليه الآن هو إنشاء نسخة لصنف التطبيق <code>GrammarApp</code> وتشغيل حلقة الحدث:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_9828_78" style=""><span class="kwd">if</span><span class="pln"> __name__ </span><span class="pun">==</span><span class="pln"> </span><span class="str">"__main__"</span><span class="pun">:</span><span class="pln">  
    myApp </span><span class="pun">=</span><span class="pln"> </span><span class="typ">GrammarApp</span><span class="pun">()</span><span class="pln">
    myApp</span><span class="pun">.</span><span class="pln">mainloop</span><span class="pun">()</span></pre>

<p>
	لننظر الآن إلى النتيجة النهائية في نظام ويندوز، والتي تعرض نتائج تحليل ملف HTML:
</p>

<p style="text-align: center;">
	<a class="ipsAttachLink ipsAttachLink_image" data-fileid="84223" href="https://academy.hsoub.com/uploads/monthly_2021_12/gui.jpg.4487d83c5deea83b9f21ce492ad27920.jpg" rel="" data-fileext="jpg"><img alt="gui.jpg" class="ipsImage ipsImage_thumbnailed" data-fileid="84223" data-unique="ipyijj2od" src="https://academy.hsoub.com/uploads/monthly_2021_12/gui.jpg.4487d83c5deea83b9f21ce492ad27920.jpg"></a>
</p>

<p>
	من الممكن جعل معالجة ملف HTML أكثر تعقيدًا إذا أردنا، حيث نتحقق أكثر من الأخطاء -مثل التحقق من عدم وجود الملف-، وننشئ وحدات لأنواع المستندات الجديدة، ونستبدل عدة عناوين مجموعة في إطار واحد بالصندوق النصي، كما يمكن استخدام قائمة منسدلة لأنواع المستندات، خاصةً إذا أضفنا أنواعًا جديدة.
</p>

<h2>
	خاتمة
</h2>

<p>
	ينظر المقال التالي في الجانب العملي من بايثون في مشاريع حقيقية، وستكون الأمثلة أطول ولن نكثر من التفاصيل في الشرح، إذ يجب أن تكون الآن قادرًا على متابعة الأمثلة بسهولة.
</p>

<p>
	ترجمة -بتصرف- <a href="http://www.alan-g.me.uk/l2p2/tutcase.htm" rel="external nofollow">للفصل الثاني والعشرين: A Case Study</a> من كتاب Learn To Program لصاحبه Alan Gauld.
</p>

<h2>
	اقرأ أيضًا
</h2>

<ul>
	<li>
		المقال التالي: <a href="https://academy.hsoub.com/devops/servers/databases/%D8%A7%D9%84%D8%AA%D8%B9%D8%A7%D9%85%D9%84-%D9%85%D8%B9-%D9%82%D9%88%D8%A7%D8%B9%D8%AF-%D8%A7%D9%84%D8%A8%D9%8A%D8%A7%D9%86%D8%A7%D8%AA-r602/" rel="">التعامل مع قواعد البيانات</a>
	</li>
	<li>
		المقال السابق: <a href="https://academy.hsoub.com/programming/general/%D9%85%D9%82%D8%AF%D9%85%D8%A9-%D8%A5%D9%84%D9%89-%D8%A7%D9%84%D8%A8%D8%B1%D9%85%D8%AC%D8%A9-%D8%A7%D9%84%D9%88%D8%B8%D9%8A%D9%81%D9%8A%D8%A9-functional-programming-r1391/" rel="">مقدمة إلى البرمجة الوظيفية Functional Programming</a>
	</li>
	<li>
		<a href="https://academy.hsoub.com/programming/general/%D8%AA%D8%B9%D9%84%D9%85-%D8%A7%D9%84%D8%A8%D8%B1%D9%85%D8%AC%D8%A9-r662/" rel="">تعلم البرمجة</a>
	</li>
	<li>
		<a href="https://academy.hsoub.com/programming/general/%D8%A8%D8%AF%D8%A7%D9%8A%D8%A9-%D8%B1%D8%AD%D9%84%D8%A9-%D8%AA%D8%B9%D9%84%D9%85-%D8%A7%D9%84%D8%A8%D8%B1%D9%85%D8%AC%D8%A9-r1280/" rel="">بداية رحلة تعلم البرمجة</a>
	</li>
</ul>
]]></description><guid isPermaLink="false">1392</guid><pubDate>Tue, 14 Dec 2021 16:05:00 +0000</pubDate></item><item><title>&#x645;&#x642;&#x62F;&#x645;&#x629; &#x625;&#x644;&#x649; &#x627;&#x644;&#x628;&#x631;&#x645;&#x62C;&#x629; &#x627;&#x644;&#x648;&#x638;&#x64A;&#x641;&#x64A;&#x629; Functional Programming</title><link>https://academy.hsoub.com/programming/general/%D9%85%D9%82%D8%AF%D9%85%D8%A9-%D8%A5%D9%84%D9%89-%D8%A7%D9%84%D8%A8%D8%B1%D9%85%D8%AC%D8%A9-%D8%A7%D9%84%D9%88%D8%B8%D9%8A%D9%81%D9%8A%D8%A9-functional-programming-r1391/</link><description><![CDATA[
<p><img src="https://academy.hsoub.com/uploads/monthly_2021_12/61a9f17853940_----Functional-Programming.png.0a1d5d65759609dda407b3d5ccfe406a.png" /></p>
<p>
	سننظر في كيفية دعم <a href="https://academy.hsoub.com/programming/python/%D8%A7%D9%84%D9%85%D8%B1%D8%AC%D8%B9-%D8%A7%D9%84%D8%B4%D8%A7%D9%85%D9%84-%D8%A5%D9%84%D9%89-%D8%AA%D8%B9%D9%84%D9%85-%D9%84%D8%BA%D8%A9-%D8%A8%D8%A7%D9%8A%D8%AB%D9%88%D9%86-r735/" rel="">بايثون</a> لأسلوب آخر من أساليب البرمجة، ألا وهو البرمجية الوظيفية Functional Programming، واختصارًا FP، وهو موضوع متقدم بالنسبة للمبتدئين في البرمجة، كما ذكرنا في شأن التعاودية في <a href="https://academy.hsoub.com/programming/general/%D9%85%D9%81%D9%87%D9%88%D9%85-%D8%A7%D9%84%D8%AA%D8%B9%D8%A7%D9%88%D8%AF%D9%8A%D8%A9-recursion-r1387/" rel="">المقال السابق</a>، وربما تصرف نظرك عنه الآن إلى أن تقطع شوطًا في البرمجة بنفسك.
</p>

<p>
	يعتقد المؤيدون للبرمجة الوظيفية أنها الأسلوب الأمثل <a href="https://academy.hsoub.com/entrepreneurship/outsourcing/%D8%AF%D9%84%D9%8A%D9%84%D9%83-%D9%84%D8%A5%D9%86%D8%AC%D8%A7%D8%AD-%D8%B9%D9%85%D9%84%D9%8A%D8%A9-%D8%A7%D9%84%D8%AA%D8%B9%D9%87%D9%8A%D8%AF-%D8%A7%D9%84%D8%AE%D8%A7%D8%B1%D8%AC%D9%8A-%D9%84%D8%AA%D8%B7%D9%88%D9%8A%D8%B1-%D8%A7%D9%84%D8%A8%D8%B1%D9%85%D8%AC%D9%8A%D8%A7%D8%AA-r529/" rel="">لتطوير البرمجيات</a>.
</p>

<p>
	سنغطي في هذا المقال ما يلي:
</p>

<ul>
	<li>
		الفرق بين أسلوب البرمجة التقليدي والأسلوب الدالّي في البرمجة.
	</li>
	<li>
		الدول والتقنيات الخاصة بالبرمجية الوظيفية في بايثون.
	</li>
	<li>
		<a href="https://academy.hsoub.com/programming/cpp/%D8%AF%D9%88%D8%A7%D9%84-%D9%84%D8%A7%D9%85%D8%AF%D8%A7-lambdas-%D9%81%D9%8A-cpp-r960/" rel="">دوال لامدا Lambda Functions</a>.
	</li>
	<li>
		تقييم الدارة المقصورة البولياني Short Circuit Boolean evaluation، والتعابير الشرطية.
	</li>
	<li>
		البرامج كتعابير.
	</li>
</ul>

<h2>
	ما هي البرمجية الوظيفية؟
</h2>

<p>
	ينبغي ألا نخلط بين البرمجية الوظيفية والأسلوب الإلزامي أو الإجرائي في البرمجة imperative style، وهو الذي كنا نستخدمه في أغلب الفصول حتى الآن، كما أنها تختلف عن البرمجة كائنية التوجه قليلًا بما أن المفاهيم التي سنراها هنا هي مفاهيم برمجية مألوفة لكننا نعبّر عنها تعبيرًا مختلفًا نوعًا ما، كما أن الفلسفة التي تقوم عليها البرمجية الوظيفية في حل المشاكل مختلفة عن باقي الأساليب أيضًا.
</p>

<p>
	وتدور <a href="https://academy.hsoub.com/questions/936-%D9%85%D8%A7-%D9%87%D9%8A-%D8%A7%D9%84%D8%A8%D8%B1%D9%85%D8%AC%D8%A9-%D8%A7%D9%84%D9%88%D8%B8%D9%8A%D9%81%D9%8A%D8%A9-functional-programming%D8%9F/" rel="">البرمجية الوظيفية</a> حول التعابير، بل يمكن القول إن البرمجية الوظيفية هي البرمجة تعبيرية التوجه expression oriented programming، لأن كل شيء فيها يؤول إلى تعبير في النهاية، وقد ذكرنا أن التعبير هو تجميعة من العمليات والمتغيرات التي ينتج عنها قيمة واحدة، فيكون <code>x == 5</code> تعبيرًا بوليانيًا boolean، و<code>5 + (7-Y)</code> تعبيرًا حسابيًا، و<code>"Hello world".uppercase()‎</code> تعبيرًا نصيًا، وهذا التعبير الأخير هو استدعاء دالة function أيضًا، أو استدعاء تابع method بالأحرى، على كائن السلسلة النصية <code>"Hello world"</code>، وسنرى أهمية الدوال في البرمجية الوظيفية، كما هو واضح من الاسم.
</p>

<p>
	تُستخدم الدوال في البرمجية الوظيفية مثل كائنات، أي أنها تُمرَّر من مكان لآخر داخل البرنامج بنفس طريقة تمرير المتغيرات، وقد رأينا أمثلةً على ذلك في برامج الواجهة الرسومية التي أنشأناها من قبل، حيث أسندنا اسم الدالة إلى سمة <code>command</code> الخاصة بمتحكم الزر، وعاملنا دالة معالج الحدث على أنها كائن وأسندنا إلى الزر مرجعًا إلى الدالة، وهذا المفهوم الخاص بتمرير الدوال في البرامج أمر أساسي في البرمجية الوظيفية، كما تميل البرامج الوظيفية إلى أن تكون قائمية التوجه List Oriented.
</p>

<p>
	تحاول البرمجية الوظيفية التركيز على ماهية المشاكل وليس كيفية حلها، أي أنها تصف المشكلة التي نريد حلها، بدلًا من التركيز على آلية الحل نفسها، وتوجد عدة لغات برمجة تميل إلى التصرف بهذه الطريقة، لعل أوسعها انتشارًا هي Haskell، ويحتوي <a href="http://www.haskell.org/" rel="external nofollow">موقع Haskell</a> على أوراق عديدة تصف فلسفة البرمجية الوظيفية، إضافةً إلى لغة Haskell نفسها، رغم أننا نرى أن مؤيدي هذا النمط من البرمجة يبالغون في ذلك الهدف.
</p>

<p>
	ويهَيكل البرنامج الوظيفي بتعريف تعبير يلتقط الهدف من البرنامج، وكل شرط term في التعبير هو تعليمة لخاصية من خصائص المشكلة -وربما يوضع الشرط نفسه في تعبير آخر-، ونحصل على الحل من خلال تقييم كل شرط من هذه الشروط.
</p>

<p>
	لكن هل هذا الأسلوب ناجح؟ الجواب: أحيانًا نعم وبكفاءة، لكننا للأسف نحتاج في كثير من المشاكل الأخرى إلى أسلوب تفكير أكثر تجريدًا abstract، ويتأثر كثيرًا بالمفاهيم الرياضية، وتصعب قراءة الشيفرة الناتجة من قبل المبرمج العادي، وتكون عادةً أقصر من الشيفرة الإلزامية المكافئة لها، وأكثر موثوقيةً منها، وقد دفعت هذه المزايا الأخيرة -من الاختصار والموثوقية- الكثير من المبرمجين الذين يستخدمون الأسلوب الكائني أو الإلزامي إلى النظر في البرمجية الوظيفية، إذ توجد العديد من الأدوات القوية التي يمكن استخدامها، حتى لو لم ينتقل المبرمج إلى اتباع هذا النمط كليًا.
</p>

<blockquote class="ipsQuote" data-ipsquote="">
	<div class="ipsQuote_citation">
		اقتباس
	</div>

	<h3 data-gramm="false">
		موثوقية البرمجية الوظيفية
	</h3>

	<p>
		تأتي موثوقية البرامج الوظيفية من العلاقة الوطيدة بين البنى الخاصة بالبرمجية الوظيفية والمواصفات الاصطلاحية formal specification languages مثل: Z أو VDM، فإذا حُددت مشكلة في لغة رسمية فمن البديهي أن نترجم التحديد إلى لغة وظيفية التوجه مثل Haskell، لكن إذا كان التحديد خاطئًا فسيكون البرنامج الناتج مرآة لذلك الخطأ! يُعرف هذا المبدأ في علوم الحاسوب باسم "Garbage In, Garbage Out" أو "قمامة داخلة، قمامة ناتجة"، ولا تزال هذه الصعوبة في التعبير عن متطلبات النظام بأسلوب موجز لا لبس فيه من أعظم التحديات في هندسة البرمجيات.
	</p>
</blockquote>

<h2>
	كيف تنفذ بايثون البرمجية الوظيفية
</h2>

<p>
	توفر <a href="https://academy.hsoub.com/files/15-%D8%A7%D9%84%D8%A8%D8%B1%D9%85%D8%AC%D8%A9-%D8%A8%D9%84%D8%BA%D8%A9-%D8%A8%D8%A7%D9%8A%D8%AB%D9%88%D9%86/" rel="">بايثون</a> دوالًا عديدة تمكننا من استخدام منظور البرمجية الوظيفية، وتمتلئ الدوال بالمزايا السهلة، أي يمكن كتابتها في بايثون بسهولة، أما ما يجب النظر إليه فهو الغرض المضمَّن في توفير تلك الدوال، وهو السماح لمبرمج بايثون بالعمل بأسلوب البرمجية الوظيفية إذا شاء.
</p>

<p>
	سننظر الآن في بعض الدوال المتوفرة في بايثون ونرى كيف تعمل على بعض أمثلة هياكل البيانات التي نعرّفها على النحو التالي:
</p>

<pre class="ipsCode prettyprint lang-c prettyprinted" id="ips_uid_6246_12" style=""><span class="pln">choices </span><span class="pun">=</span><span class="pln"> </span><span class="pun">[</span><span class="str">'eggs'</span><span class="pun">,</span><span class="str">'chips'</span><span class="pun">,</span><span class="str">'spam'</span><span class="pun">]</span><span class="pln">
numbers </span><span class="pun">=</span><span class="pln"> </span><span class="pun">[</span><span class="lit">1</span><span class="pun">,</span><span class="lit">2</span><span class="pun">,</span><span class="lit">3</span><span class="pun">,</span><span class="lit">4</span><span class="pun">,</span><span class="lit">5</span><span class="pun">]</span><span class="pln">

def spam</span><span class="pun">(</span><span class="pln">item</span><span class="pun">):</span><span class="pln"> 
    </span><span class="kwd">return</span><span class="pln"> </span><span class="str">"Spam &amp; "</span><span class="pln"> </span><span class="pun">+</span><span class="pln"> item</span></pre>

<h3>
	الدالة map(aFunction, aSequence)‎
</h3>

<p>
	تطبق الدالة <code>aFunction</code> الخاصة ببايثون على كل عضو من <code>aSequence</code>، ويكون التعبير كما يلي:
</p>

<pre class="ipsCode prettyprint lang-py prettyprinted" id="ips_uid_6246_18" style=""><span class="pln">L </span><span class="pun">=</span><span class="pln"> map</span><span class="pun">(</span><span class="pln">spam</span><span class="pun">,</span><span class="pln"> choices</span><span class="pun">)</span><span class="pln">
</span><span class="kwd">print</span><span class="pun">(</span><span class="pln"> list</span><span class="pun">(</span><span class="pln">L</span><span class="pun">)</span><span class="pln"> </span><span class="pun">)</span></pre>

<p>
	ينتج عن هذا إعادة قائمة جديدة في L، مع السابقة <code>Spam &amp;‎</code> في حالتنا قبل كل عنصر، ونلاحظ كيف مررنا الدالة <code>spam()‎</code> إلى دالة <code>map()‎</code> مثل قيمة، أي أننا لم نستخدم الأقواس لتنفيذ شيفرة الدالة، بل استخدمنا اسمها مرجعًا إلى الدالة، ولعلك تذكر أننا فعلنا هذا مع معالجات الأحداث في مقال <a href="https://academy.hsoub.com/programming/general/%D8%A8%D8%B1%D9%85%D8%AC%D8%A9-%D8%A7%D9%84%D9%88%D8%A7%D8%AC%D9%87%D8%A7%D8%AA-%D8%A7%D9%84%D8%B1%D8%B3%D9%88%D9%85%D9%8A%D8%A9-%D8%A8%D8%A7%D8%B3%D8%AA%D8%AE%D8%AF%D8%A7%D9%85-tkinter-r1378/" rel="">برمجة الواجهات الرسومية</a>، وهذه الخاصية في معاملة الدوال مثل قيم هي إحدى المزايا الرئيسية في البرمجية الوظيفية.
</p>

<p>
	يمكن تحقيق نفس النتيجة بكتابة ما يلي:
</p>

<pre class="ipsCode prettyprint lang-py prettyprinted" id="ips_uid_6246_20" style=""><span class="pln">L </span><span class="pun">=</span><span class="pln"> </span><span class="pun">[]</span><span class="pln">
</span><span class="kwd">for</span><span class="pln"> i </span><span class="kwd">in</span><span class="pln"> choices</span><span class="pun">:</span><span class="pln">
   L</span><span class="pun">.</span><span class="pln">append</span><span class="pun">(</span><span class="pln"> spam</span><span class="pun">(</span><span class="pln">i</span><span class="pun">)</span><span class="pln"> </span><span class="pun">)</span><span class="pln">
</span><span class="kwd">print</span><span class="pun">(</span><span class="pln"> L </span><span class="pun">)</span></pre>

<p>
	لكن نلاحظ أن دالة <code>map</code> تسمح لنا بإلغاء الحاجة إلى كتلة شيفرة متشعبة، مما يقلل تعقيد البرنامج، وسنرى أن هذه سمة متتكررة في البرمجية الوظيفية، حيث يقلل استخدام الدوال التعقيد النسبي للشيفرة بالتخلص من الكتل البرمجية.
</p>

<h3>
	الدالة (filter(aFunction, aSequence
</h3>

<p>
	تستخلص <code>filter</code> كل عنصر في التسلسل aSequence تعيد له الدالة aFunction القيمة <code>True</code>، وإذا عدنا إلى قائمة الأعداد الخاصة بنا فيمكن أن ننشئ قائمةً جديدةً من الأعداد الفردية فقط:
</p>

<pre class="ipsCode prettyprint lang-py prettyprinted" id="ips_uid_6246_24" style=""><span class="kwd">def</span><span class="pln"> isOdd</span><span class="pun">(</span><span class="pln">n</span><span class="pun">):</span><span class="pln"> </span><span class="kwd">return</span><span class="pln"> </span><span class="pun">(</span><span class="pln">n</span><span class="pun">%</span><span class="lit">2</span><span class="pln"> </span><span class="pun">!=</span><span class="pln"> </span><span class="lit">0</span><span class="pun">)</span><span class="pln"> </span><span class="com"># mod استخدم العامل</span><span class="pln">
L </span><span class="pun">=</span><span class="pln"> filter</span><span class="pun">(</span><span class="pln">isOdd</span><span class="pun">,</span><span class="pln"> numbers</span><span class="pun">)</span><span class="pln">
</span><span class="kwd">print</span><span class="pun">(</span><span class="pln"> list</span><span class="pun">(</span><span class="pln">L</span><span class="pun">)</span><span class="pln"> </span><span class="pun">)</span></pre>

<p>
	نلاحظ مرةً أخرى أننا نمرر اسم الدالة <code>isodd</code> إلى <code>filter</code> قيمة وسيط، بدلًا من استدعاء <code>isodd()‎</code> مثل دالة، وعلى أي حال نستطيع كتابة الأسلوب البديل التالي:
</p>

<pre class="ipsCode prettyprint lang-py prettyprinted" id="ips_uid_6246_26" style=""><span class="kwd">def</span><span class="pln"> isOdd</span><span class="pun">(</span><span class="pln">n</span><span class="pun">):</span><span class="pln"> </span><span class="kwd">return</span><span class="pln"> </span><span class="pun">(</span><span class="pln">n</span><span class="pun">%</span><span class="lit">2</span><span class="pln"> </span><span class="pun">!=</span><span class="pln"> </span><span class="lit">0</span><span class="pun">)</span><span class="pln">
L </span><span class="pun">=</span><span class="pln"> </span><span class="pun">[]</span><span class="pln">
</span><span class="kwd">for</span><span class="pln"> i </span><span class="kwd">in</span><span class="pln"> numbers</span><span class="pun">:</span><span class="pln">
   </span><span class="kwd">if</span><span class="pln"> isOdd</span><span class="pun">(</span><span class="pln">i</span><span class="pun">):</span><span class="pln">
      L</span><span class="pun">.</span><span class="pln">append</span><span class="pun">(</span><span class="pln">i</span><span class="pun">)</span><span class="pln">
</span><span class="kwd">print</span><span class="pun">(</span><span class="pln"> L </span><span class="pun">)</span></pre>

<p>
	ونلاحظ هنا أيضًا أن الأسلوب التقليدي يحتاج إلى مستويين إضافيين من الإزاحات لتحقيق نفس النتيجة، وهذه الزيادة في مستويات الإزاحة دليل على زيادة التعقيد.
</p>

<p>
	توجد عدة أدوات أخرى للبرمجة الوظيفية في وحدة اسمها <code>functools</code> يمكن استيرادها وتصفحها في محث بايثون، ويُرجع إلى <code>dir()‎</code> و<code>help()‎</code> عند الحاجة.
</p>

<h3>
	الدالة لامدا Lambda
</h3>

<p>
	إحدى الخصائص الواضحة في الأمثلة السابقة هو أن الدوال التي مُرِّرت إلى دوال البرمجية الوظيفية كانت قصيرة جدًا، وغالبًا ما كانت سطرًا واحدًا فقط، وتوفر بايثون دعمًا جديدًا للبرمجة الوظيفية لتوفير الجهد المبذول لتعريف هذه الدوال الصغيرة، وهي <a href="http://B1_lambda" rel="external nofollow">دالة لامدا lambda</a>، والتي يأتي اسمها من فرع في الرياضيات هو حسابات لامدا Lambda Calculus، الذي يستخدم حرف لامدا الإغريقي λ لتمثيل مفهوم قريب من هذا.
</p>

<p>
	ويُستخدم مصطلح لامدا في البرمجية الوظيفية للإشارة إلى دالة مجهولة تمثل كتلةً برمجيةً يمكن تنفيذها كما لو كانت دالةً لكن دون اسم، ويمكن تعريف دوال لامدا في أي مكان داخل البرنامج يمكن أن يحدث فيه تعبير بايثون، وهذا يعني أننا نستطيع استخدامها داخل دوال البرمجية الوظيفية الخاصة بنا.
</p>

<p>
	وتبدو الدالة لامدا بالشكل التالي:
</p>

<pre class="ipsCode prettyprint lang-py prettyprinted" id="ips_uid_6246_29" style=""><span class="kwd">lambda</span><span class="pln"> </span><span class="pun">&lt;</span><span class="pln">aParameterList</span><span class="pun">&gt;</span><span class="pln"> </span><span class="pun">:</span><span class="pln"> </span><span class="pun">&lt;</span><span class="pln">a </span><span class="typ">Python</span><span class="pln"> expression using the parameters</span><span class="pun">&gt;</span></pre>

<p>
	وعلى ذلك يمكن كتابة دالة <code>isodd</code> سالفة الذكر كما يلي:
</p>

<pre class="ipsCode prettyprint lang-py prettyprinted" id="ips_uid_6246_31" style=""><span class="pln">isOdd </span><span class="pun">=</span><span class="pln"> </span><span class="kwd">lambda</span><span class="pln"> j</span><span class="pun">:</span><span class="pln"> j</span><span class="pun">%</span><span class="lit">2</span><span class="pln"> </span><span class="pun">!=</span><span class="pln"> </span><span class="lit">0</span></pre>

<p>
	ونتجنب هنا تعريف السطر بالكامل من خلال إنشاء الدالة لامدا داخل الاستدعاء على <code>filter</code> كما يلي:
</p>

<pre class="ipsCode prettyprint lang-py prettyprinted" id="ips_uid_6246_34" style=""><span class="pln">L </span><span class="pun">=</span><span class="pln"> filter</span><span class="pun">(</span><span class="kwd">lambda</span><span class="pln"> j</span><span class="pun">:</span><span class="pln"> j</span><span class="pun">%</span><span class="lit">2</span><span class="pln"> </span><span class="pun">!=</span><span class="pln"> </span><span class="lit">0</span><span class="pun">,</span><span class="pln"> numbers</span><span class="pun">)</span><span class="pln">
</span><span class="kwd">print</span><span class="pun">(</span><span class="pln"> list</span><span class="pun">(</span><span class="pln">L</span><span class="pun">)</span><span class="pln"> </span><span class="pun">)</span></pre>

<p>
	ويُنفَّذ الاستدعاء إلى map باستخدام ما يلي:
</p>

<pre class="ipsCode prettyprint lang-py prettyprinted" id="ips_uid_6246_36" style=""><span class="pln">L </span><span class="pun">=</span><span class="pln"> map</span><span class="pun">(</span><span class="kwd">lambda</span><span class="pln"> s</span><span class="pun">:</span><span class="pln"> </span><span class="str">"Spam &amp; "</span><span class="pln"> </span><span class="pun">+</span><span class="pln"> s</span><span class="pun">,</span><span class="pln"> choices</span><span class="pun">)</span><span class="pln">
</span><span class="kwd">print</span><span class="pun">(</span><span class="pln"> list</span><span class="pun">(</span><span class="pln">L</span><span class="pun">)</span><span class="pln"> </span><span class="pun">)</span></pre>

<p>
	ونلاحظ هنا أننا كنا نحول نتائج <code>map()‎</code> و<code>filter()‎</code> إلى قوائم، لأنهما صنفان يعيدان نسخًا من شيء يدعى المتكرر itreable، وهو يتصرف مثل التسلسل أو التجميعة إذا استُخدم على حلقة تكرارية، ويمكن تحويله إلى قائمة، لكن كفاءته تظهر في استخدام الذاكرة، وصديقتنا القديمة <code>range()‎</code> قابلة للتكرار كذلك، وتسمح بايثون بإنشاء أنواع قابلة للتكرار خاصة بنا، لكننا لن نشرحها.
</p>

<h3>
	استيعاب القوائم
</h3>

<p>
	استيعاب القوائم list comprehension هي تقنية لبناء قوائم جديدة، مستوردة من لغة Haskell وأُدخلت إلى بايثون في الإصدار الثاني، وبنيتها غريبة قليلًا وتشبه الصياغة الرياضية، مثلًا:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_6246_38" style=""><span class="pun">[&lt;</span><span class="pln">expression</span><span class="pun">&gt;</span><span class="pln"> </span><span class="kwd">for</span><span class="pln"> </span><span class="pun">&lt;</span><span class="pln">value</span><span class="pun">&gt;</span><span class="pln"> in </span><span class="pun">&lt;</span><span class="pln">collection</span><span class="pun">&gt;</span><span class="pln"> </span><span class="kwd">if</span><span class="pln"> </span><span class="pun">&lt;</span><span class="pln">condition</span><span class="pun">&gt;]</span></pre>

<p>
	والتي تكافئ ما يلي:
</p>

<pre class="ipsCode">L = []
for value in collection:
    if condition:
        L.append(expression)
</pre>

<p>
	مما يوفر علينا كتابة بعض الأسطر كما في بقية البنى في البرمجية الوظيفية، ومستويين من الإزاحة كذلك، لننظر في بعض الأمثلة العملية، حيث سننشئ أولًا قائمةً من جميع الأعداد الزوجية الأصغر من 10:
</p>

<pre class="ipsCode prettyprint lang-py prettyprinted" id="ips_uid_6246_42" style=""><span class="pun">&gt;&gt;&gt;</span><span class="pln"> </span><span class="pun">[</span><span class="pln">n </span><span class="kwd">for</span><span class="pln"> n </span><span class="kwd">in</span><span class="pln"> range</span><span class="pun">(</span><span class="lit">10</span><span class="pun">)</span><span class="pln"> </span><span class="kwd">if</span><span class="pln"> n </span><span class="pun">%</span><span class="pln"> </span><span class="lit">2</span><span class="pln"> </span><span class="pun">==</span><span class="pln"> </span><span class="lit">0</span><span class="pln"> </span><span class="pun">]</span><span class="pln">
</span><span class="pun">[</span><span class="lit">0</span><span class="pun">,</span><span class="pln"> </span><span class="lit">2</span><span class="pun">,</span><span class="pln"> </span><span class="lit">4</span><span class="pun">,</span><span class="pln"> </span><span class="lit">6</span><span class="pun">,</span><span class="pln"> </span><span class="lit">8</span><span class="pun">]</span></pre>

<p>
	والذي يقول إننا نريد قائمةً من القيم <code>n</code> التي تُختار من المجال 0-9، وتكون زوجيةً (<code>n % 2 == 0</code>)، ويمكن استبدال دالةٍ بالشرط الأخير لا شك، شرط أن تعيد الدالة قيمةً تستطيع بايثون أن تفسرها مثل قيمة بوليانية، وعليه يمكن إعادة كتابة المثال السابق كما يلي:
</p>

<pre class="ipsCode prettyprint lang-py prettyprinted" id="ips_uid_6246_44" style=""><span class="pun">&gt;&gt;&gt;</span><span class="kwd">def</span><span class="pln"> isEven</span><span class="pun">(</span><span class="pln">n</span><span class="pun">):</span><span class="pln"> </span><span class="kwd">return</span><span class="pln"> </span><span class="pun">((</span><span class="pln">n</span><span class="pun">%</span><span class="lit">2</span><span class="pun">)</span><span class="pln"> </span><span class="pun">==</span><span class="pln"> </span><span class="lit">0</span><span class="pun">)</span><span class="pln">
</span><span class="pun">&gt;&gt;&gt;</span><span class="pln"> </span><span class="pun">[</span><span class="pln"> n </span><span class="kwd">for</span><span class="pln"> n </span><span class="kwd">in</span><span class="pln"> range</span><span class="pun">(</span><span class="lit">10</span><span class="pun">)</span><span class="pln"> </span><span class="kwd">if</span><span class="pln"> isEven</span><span class="pun">(</span><span class="pln">n</span><span class="pun">)</span><span class="pln"> </span><span class="pun">]</span><span class="pln">
</span><span class="pun">[</span><span class="lit">0</span><span class="pun">,</span><span class="pln"> </span><span class="lit">2</span><span class="pun">,</span><span class="pln"> </span><span class="lit">4</span><span class="pun">,</span><span class="pln"> </span><span class="lit">6</span><span class="pun">,</span><span class="pln"> </span><span class="lit">8</span><span class="pun">]</span></pre>

<p>
	والآن لننشئ قائمةً من تربيعات أول 5 أعداد:
</p>

<pre class="ipsCode prettyprint lang-py prettyprinted" id="ips_uid_6246_47" style=""><span class="pun">&gt;&gt;&gt;</span><span class="pln"> </span><span class="pun">[</span><span class="pln">n</span><span class="pun">*</span><span class="pln">n </span><span class="kwd">for</span><span class="pln"> n </span><span class="kwd">in</span><span class="pln"> range</span><span class="pun">(</span><span class="lit">5</span><span class="pun">)]</span><span class="pln">
</span><span class="pun">[</span><span class="lit">0</span><span class="pun">,</span><span class="pln"> </span><span class="lit">1</span><span class="pun">,</span><span class="pln"> </span><span class="lit">4</span><span class="pun">,</span><span class="pln"> </span><span class="lit">9</span><span class="pun">,</span><span class="pln"> </span><span class="lit">16</span><span class="pun">]</span></pre>

<p>
	نلاحظ أن تعليمة if الأخيرة لم تكن ضروريةً لكل حالة، فالتعبير الابتدائي هنا هو <code>n*n</code>، حيث نستخدم جميع قيم المجال، لنستخدم الآن تجميعةً موجودةً مسبقًا بدلًا من دالة المجال:
</p>

<pre class="ipsCode prettyprint lang-py prettyprinted" id="ips_uid_6246_49" style=""><span class="pun">&gt;&gt;&gt;</span><span class="pln"> values </span><span class="pun">=</span><span class="pln"> </span><span class="pun">[</span><span class="lit">1</span><span class="pun">,</span><span class="pln"> </span><span class="lit">13</span><span class="pun">,</span><span class="pln"> </span><span class="lit">25</span><span class="pun">,</span><span class="pln"> </span><span class="lit">7</span><span class="pun">]</span><span class="pln">
</span><span class="pun">&gt;&gt;&gt;</span><span class="pln"> </span><span class="pun">[</span><span class="pln">x </span><span class="kwd">for</span><span class="pln"> x </span><span class="kwd">in</span><span class="pln"> values </span><span class="kwd">if</span><span class="pln"> x </span><span class="pun">&lt;</span><span class="pln"> </span><span class="lit">10</span><span class="pun">]</span><span class="pln">
</span><span class="pun">[</span><span class="lit">1</span><span class="pun">,</span><span class="pln"> </span><span class="lit">7</span><span class="pun">]</span></pre>

<p>
	يمكن استخدام ذلك لاستبدال دالة المرشح التالية:
</p>

<pre class="ipsCode prettyprint lang-py prettyprinted" id="ips_uid_6246_51" style=""><span class="pun">&gt;&gt;&gt;</span><span class="pln"> </span><span class="kwd">print</span><span class="pun">(</span><span class="pln"> list</span><span class="pun">(</span><span class="pln">filter</span><span class="pun">(</span><span class="kwd">lambda</span><span class="pln"> x</span><span class="pun">:</span><span class="pln"> x </span><span class="pun">&lt;</span><span class="pln"> </span><span class="lit">10</span><span class="pun">,</span><span class="pln"> values</span><span class="pun">))</span><span class="pln"> </span><span class="pun">)</span><span class="pln">
</span><span class="pun">[</span><span class="lit">1</span><span class="pun">,</span><span class="pln"> </span><span class="lit">7</span><span class="pun">]</span></pre>

<p>
	لا يقتصر استيعاب القوائم على متغير واحد أو اختبار واحد، لكن سيزداد تعقيد الشيفرة كلما زادت المتغيرات والاختبارات، ويعود إليك الاختيار بين استيعاب القوائم أو الدوال التقليدية بحسب ما تراه أسهل، إذ تستطيع استخدام دوال البرمجية الوظيفية السابقة أو استيعابات القوائم الجديدة عند إنشاء تجميعة جديدة مبنية على واحدة موجودة مسبقًا، لكن الأسهل في إنشاء التجميعات الجديدة هو الاستيعاب.
</p>

<p>
	ورغم أن هذه البُنى تبدو مغريةً إلا أن التعابير اللازمة للحصول على النتيجة التي نريدها قد تصبح معقدةً للغاية بحيث يسهل توسيعها إلى مكافئاتها التقليدية في بايثون، ولا عيب في هذا إذ إن سهولة القراءة أفضل من غموض الشيفرة، خاصةً إذا كان ذلك الغموض لمجرد التذاكي.
</p>

<h2>
	بنى أخرى
</h2>

<p>
	رغم أن هذه الدوال مفيدة في ذاتها إلا أنها لا تكفي للسماح بنمط برمجة وظيفية كامل داخل بايثون، إذ يجب تغيير هياكل التحكم أو على الأقل استبدالها بمنظور وظيفية، ويمكن تنفيذ هذا بتطبيق أثر جانبي لكيفية تقييم بايثون للتعابير البوليانية.
</p>

<h3>
	التقييم المقصور أو تقييم الدارة المقصورة
</h3>

<p>
	لعلك تذكر من مقال مقدمة في البرمجة الشرطية أن بايثون تستخدم التقييم المقصور للتعابير البوليانية، ويمكن استغلال بعض خصائص هذه التعابير في توفير أسلوب وظيفية للتحكم في البرامج، والتقييم المقصور باختصار هو بدء تقييم التعبير البولياني من التعبير الأيسر إلى الأيمن، ويتوقف التقييم عند عدم الحاجة إلى تقييم أكثر لتحديد النتيجة النهائية، لننظر في بعض الأمثلة لنرى كيف يعمل هذا التقييم:
</p>

<pre class="ipsCode prettyprint lang-py prettyprinted" id="ips_uid_6246_53" style=""><span class="pun">&gt;&gt;&gt;</span><span class="pln"> </span><span class="kwd">def</span><span class="pln"> TRUE</span><span class="pun">():</span><span class="pln">
</span><span class="pun">...</span><span class="pln">   </span><span class="kwd">print</span><span class="pun">(</span><span class="pln"> </span><span class="str">'TRUE'</span><span class="pln"> </span><span class="pun">)</span><span class="pln">
</span><span class="pun">...</span><span class="pln">   </span><span class="kwd">return</span><span class="pln"> </span><span class="kwd">True</span><span class="pln">
</span><span class="pun">...</span><span class="pln">   
</span><span class="pun">&gt;&gt;&gt;</span><span class="pln"> </span><span class="kwd">def</span><span class="pln"> FALSE</span><span class="pun">():</span><span class="pln">
</span><span class="pun">...</span><span class="pln">   </span><span class="kwd">print</span><span class="pun">(</span><span class="pln"> </span><span class="str">'FALSE'</span><span class="pln"> </span><span class="pun">)</span><span class="pln">
</span><span class="pun">...</span><span class="pln">   </span><span class="kwd">return</span><span class="pln"> </span><span class="kwd">False</span><span class="pln">
</span><span class="pun">...</span></pre>

<p>
	نعرِّف أولًا دالتين تخبراننا متى تُنفَّذان وتعيدان قيمة أسمائهما، ونستخدم ذلك لنرى كيفية تقييم التعابير البوليانية، لاحظ أن الخرج بالأحرف الكبيرة ناتج عن الدوال، والخرج بالأحرف مختلطة الحالة ناتج عن التعبير:
</p>

<pre class="ipsCode prettyprint lang-py prettyprinted" id="ips_uid_6246_55" style=""><span class="pun">&gt;&gt;&gt;</span><span class="pln"> </span><span class="kwd">print</span><span class="pun">(</span><span class="pln"> TRUE</span><span class="pun">()</span><span class="pln"> </span><span class="kwd">and</span><span class="pln"> FALSE</span><span class="pun">()</span><span class="pln"> </span><span class="pun">)</span><span class="pln">
TRUE
FALSE
</span><span class="kwd">False</span><span class="pln">
</span><span class="pun">&gt;&gt;&gt;</span><span class="pln"> </span><span class="kwd">print</span><span class="pun">(</span><span class="pln"> TRUE</span><span class="pun">()</span><span class="pln"> </span><span class="kwd">and</span><span class="pln"> TRUE</span><span class="pun">()</span><span class="pln"> </span><span class="pun">)</span><span class="pln">
TRUE
TRUE
</span><span class="kwd">True</span><span class="pln">
</span><span class="pun">&gt;&gt;&gt;</span><span class="pln"> </span><span class="kwd">print</span><span class="pun">(</span><span class="pln"> FALSE</span><span class="pun">()</span><span class="pln"> </span><span class="kwd">and</span><span class="pln"> TRUE</span><span class="pun">()</span><span class="pln"> </span><span class="pun">)</span><span class="pln">
FALSE
</span><span class="kwd">False</span><span class="pln">
</span><span class="pun">&gt;&gt;&gt;</span><span class="pln"> </span><span class="kwd">print</span><span class="pun">(</span><span class="pln"> TRUE</span><span class="pun">()</span><span class="pln"> </span><span class="kwd">or</span><span class="pln"> FALSE</span><span class="pun">()</span><span class="pln"> </span><span class="pun">)</span><span class="pln">
TRUE
</span><span class="kwd">True</span><span class="pln">
</span><span class="pun">&gt;&gt;&gt;</span><span class="pln"> </span><span class="kwd">print</span><span class="pun">(</span><span class="pln"> FALSE</span><span class="pun">()</span><span class="pln"> </span><span class="kwd">or</span><span class="pln"> TRUE</span><span class="pun">()</span><span class="pln"> </span><span class="pun">)</span><span class="pln">
FALSE
TRUE
</span><span class="kwd">True</span><span class="pln">
</span><span class="pun">&gt;&gt;&gt;</span><span class="pln"> </span><span class="kwd">print</span><span class="pun">(</span><span class="pln"> FALSE</span><span class="pun">()</span><span class="pln"> </span><span class="kwd">or</span><span class="pln"> FALSE</span><span class="pun">()</span><span class="pln"> </span><span class="pun">)</span><span class="pln">
FALSE
FALSE
</span><span class="kwd">False</span></pre>

<p>
	نلاحظ أنه إذا تحقق الجزء الأول من تعبير AND -أي كان <code>True</code>- وفقط إذا تحقق؛ فسيقيَّم الجزء الثاني، أما إذا لم يتحقق الجزء الأول -كان <code>False</code>- فلن يُقيَّم الجزء الثاني بما أن التعبير ككل لا يمكن أن يتحقق.
</p>

<p>
	وبالمثل ففي التعبير المبني على OR، إذا كان الجزء الأول <code>True</code> فلا توجد حاجة إلى تقييم الجزء الثاني، لأن التعبير الكلي يجب أن يكون <code>True</code>، وذاك يتحقق بأحد الجزئين فقط.
</p>

<p>
	هناك ميزة أخرى في تقييم بايثون للتعابير البوليانية يمكن استغلالها، وهي أنها لا تعيد -عند تقييم تعبير ما- <code>True</code> أو <code>False</code> فقط، بل تعيد القيمة الحقيقية للتعبير، لذا ستعيد بايثون السلسلة النصية نفسها إذا تحققنا من سلسلة فارغة -والتي يجب أن تُعد <code>False</code>- كما يلي:
</p>

<pre class="ipsCode prettyprint lang-py prettyprinted" id="ips_uid_6246_57" style=""><span class="kwd">if</span><span class="pln"> </span><span class="str">"This string is not empty"</span><span class="pun">:</span><span class="pln"> </span><span class="kwd">print</span><span class="pun">(</span><span class="pln"> </span><span class="str">"Not Empty"</span><span class="pln"> </span><span class="pun">)</span><span class="pln">
</span><span class="kwd">else</span><span class="pun">:</span><span class="pln"> </span><span class="kwd">print</span><span class="pun">(</span><span class="pln"> </span><span class="str">"No string there"</span><span class="pln"> </span><span class="pun">)</span></pre>

<p>
	يمكن استخدام هذه الخصائص لإعادة إنتاج سلوك شبيه بالتفريع branching، لنفترض مثلًا أن لدينا جزءًا من شيفرة كما يلي:
</p>

<pre class="ipsCode prettyprint lang-py prettyprinted" id="ips_uid_6246_59" style=""><span class="kwd">if</span><span class="pln"> TRUE</span><span class="pun">():</span><span class="pln"> </span><span class="kwd">print</span><span class="pun">(</span><span class="pln"> </span><span class="str">"It is True"</span><span class="pln"> </span><span class="pun">)</span><span class="pln">
</span><span class="kwd">else</span><span class="pun">:</span><span class="pln"> </span><span class="kwd">print</span><span class="pun">(</span><span class="pln"> </span><span class="str">"It is False"</span><span class="pln"> </span><span class="pun">)</span></pre>

<p>
	يمكن استبدال بنية وظيفية دالية بها:
</p>

<pre class="ipsCode prettyprint lang-py prettyprinted" id="ips_uid_6246_61" style=""><span class="pln">V </span><span class="pun">=</span><span class="pln">  </span><span class="pun">(</span><span class="pln">TRUE</span><span class="pun">()</span><span class="pln"> </span><span class="kwd">and</span><span class="pln"> </span><span class="str">"It is True"</span><span class="pun">)</span><span class="pln"> </span><span class="kwd">or</span><span class="pln"> </span><span class="pun">(</span><span class="str">"It is False"</span><span class="pun">)</span><span class="pln">
</span><span class="kwd">print</span><span class="pun">(</span><span class="pln"> V </span><span class="pun">)</span></pre>

<p>
	جرب العمل على هذا المثال واستبدل استدعاءً إلى <code>FALSE()‎</code> بالاستدعاء إلى <code>TRUE()‎</code>.
</p>

<p>
	وهكذا نكون قد وجدنا طريقةً للتخلص من تعليمات if/else الشرطية في برامجنا باستخدام التقييم المقصور للتعابير البوليانية، وقد ترى هذه الأساليب في البرامج القديمة، لكنها قد تأتي بنتائج عكسية، لهذا توجد بنية أُدخلت حديثًا إلى بايثون تسمى بالتعبير الشرطي تسمح لنا بكتابة شرط <code>if/else</code> مثل تعبير، كما يلي:
</p>

<pre class="ipsCode prettyprint lang-py prettyprinted" id="ips_uid_6246_63" style=""><span class="pln">result </span><span class="pun">=</span><span class="pln"> </span><span class="pun">&lt;</span><span class="kwd">True</span><span class="pln"> expression</span><span class="pun">&gt;</span><span class="pln"> </span><span class="kwd">if</span><span class="pln"> </span><span class="pun">&lt;</span><span class="pln">test condition</span><span class="pun">&gt;</span><span class="pln"> </span><span class="kwd">else</span><span class="pln"> </span><span class="pun">&lt;</span><span class="kwd">False</span><span class="pln"> expression</span><span class="pun">&gt;</span></pre>

<p>
	وسيبدو مثال حقيقي بها كما يلي:
</p>

<pre class="ipsCode prettyprint lang-py prettyprinted" id="ips_uid_6246_65" style=""><span class="pun">&gt;&gt;&gt;</span><span class="pln"> </span><span class="kwd">print</span><span class="pun">(</span><span class="pln"> </span><span class="str">"This is True"</span><span class="pln"> </span><span class="kwd">if</span><span class="pln"> TRUE</span><span class="pun">()</span><span class="pln"> </span><span class="kwd">else</span><span class="pln"> </span><span class="str">"This is not printed"</span><span class="pln"> </span><span class="pun">)</span><span class="pln">
TRUE
</span><span class="typ">This</span><span class="pln"> </span><span class="kwd">is</span><span class="pln"> </span><span class="kwd">True</span></pre>

<p>
	وإذا استخدمنا else:
</p>

<pre class="ipsCode prettyprint lang-py prettyprinted" id="ips_uid_6246_67" style=""><span class="pun">&gt;&gt;&gt;</span><span class="pln"> </span><span class="kwd">print</span><span class="pun">(</span><span class="pln"> </span><span class="str">"This is True"</span><span class="pln"> </span><span class="kwd">if</span><span class="pln"> FALSE</span><span class="pun">()</span><span class="pln"> </span><span class="kwd">else</span><span class="pln"> </span><span class="str">"We see it this time"</span><span class="pln"> </span><span class="pun">)</span><span class="pln">
FALSE
</span><span class="typ">We</span><span class="pln"> see it this time</span></pre>

<p>
	وقد ذكرنا في المقال السابق حول مفهوم التعاودية في البرمجة، أنه يمكن استخدام التعاودية لاستبدال بنية الحلقة التكرارية، فإذا جمعنا التعاودية مع التعابير الشرطية فيمكننا التخلص من بنى التحكم القديمة كلها من برنامجنا، ونستبدل بها تعابير صرفةً، وهذه خطوة كبيرة نحو تفعيل حلول البرمجية الوظيفية.
</p>

<p>
	ولنضع هذا في تدريب عملي سنكتب برنامج المضروب factorial بأسلوب وظيفية كليًا، باستخدام <code>lambda</code> بدلًا من <code>def</code>، والتعاودية بدلًا من الحلقات التكرارية، والتعابير الشرطية بدلًا من <code>if/else</code> المعتادة:
</p>

<pre class="ipsCode prettyprint lang-py prettyprinted" id="ips_uid_6246_69" style=""><span class="pun">&gt;&gt;&gt;</span><span class="pln"> factorial </span><span class="pun">=</span><span class="pln"> </span><span class="kwd">lambda</span><span class="pln"> n</span><span class="pun">:</span><span class="pln"> </span><span class="pun">(</span><span class="pln"> </span><span class="kwd">None</span><span class="pln"> </span><span class="kwd">if</span><span class="pln"> n </span><span class="pun">&lt;</span><span class="pln"> </span><span class="lit">0</span><span class="pln"> </span><span class="kwd">else</span><span class="pln"> 
                            </span><span class="lit">1</span><span class="pln"> </span><span class="kwd">if</span><span class="pln"> </span><span class="pun">(</span><span class="pln">n </span><span class="pun">==</span><span class="pln"> </span><span class="lit">0</span><span class="pun">)</span><span class="pln"> </span><span class="kwd">else</span><span class="pln"> 
                            factorial</span><span class="pun">(</span><span class="pln">n</span><span class="pun">-</span><span class="lit">1</span><span class="pun">)</span><span class="pln"> </span><span class="pun">*</span><span class="pln"> n </span><span class="pun">)</span><span class="pln">
</span><span class="pun">&gt;&gt;&gt;</span><span class="pln"> </span><span class="kwd">print</span><span class="pun">(</span><span class="pln"> factorial</span><span class="pun">(</span><span class="lit">5</span><span class="pun">)</span><span class="pln"> </span><span class="pun">)</span><span class="pln">
</span><span class="lit">120</span></pre>

<p>
	وهذا كل ما في الأمر، وقد لا تكون هذه الشيفرة سهلة القراءة مثل شيفرة بايثون العادية لكنها تعمل، وهي دالة بنمط البرمجية الوظيفية كليًا لأنها تعبير خالص، ونلاحظ أننا استخدمنا مجموعةً من الأقواس حول التعبير كله، وهو ما يسمح لنا بتوزيعه على عدة أسطر لتحسين قراءته، ثم حاذينا قيم الإعادة المحتملة الثلاثة رأسيًا في أسطر منفصلة، وهذا اصطلاح شائع مستورد من لغات Lisp التي تميل إلى استخدام التعاودية بكثرة.
</p>

<h2>
	استنتاجات
</h2>

<p>
	لعل السؤال الذي يطرح نفسه الآن هو الجدوى من كل ذلك، فرغم أن البرمجية الوظيفية تروق لكثير من الأكاديميين في مجال علوم الحاسوب وعلماء الرياضيات كذلك؛ إلا أن أغلب المبرمجين العاملين يقتصدون في استخدام تقنيات البرمجية الوظيفية، ويدمجونها مع الأساليب الإلزامية التقليدية وفق ما يرونه مناسبًا.
</p>

<p>
	وعند الحاجة إلى تطبيق عمليات على عناصر في قائمة مثل <code>map</code> أو <code>filter</code> تكون البرمجية الوظيفية هي المثلى للتعبير عن الحل، وبالمثل قد نجد أحيانًا أن التعاودية أفضل من <a href="https://academy.hsoub.com/programming/general/%D8%A7%D9%84%D8%AD%D9%84%D9%82%D8%A7%D8%AA-%D8%A7%D9%84%D8%AA%D9%83%D8%B1%D8%A7%D8%B1%D9%8A%D8%A9-%D9%81%D9%8A-%D8%A7%D9%84%D8%A8%D8%B1%D9%85%D8%AC%D8%A9-r1306/" rel="">الحلقات التكرارية</a>، كما قد نجد استخدامًا للتقييم المقصور أو التعبير الشرطي بدلًا من تعابير <code>if/else</code> الشرطية، خاصةً داخل تعبير ما، والمهم أنه يجب على المتعلم ألا يتحمس كثيرًا لتقنية أو فلسفة برمجية بعينها، وإنما يستخدم الأداة المناسبة للمهمة التي بين يديه، ويكفيه حينئذ أن يعلم بوجود حلول بديلة.
</p>

<p>
	لدينا أمر أخير حول الدالة <code>lambda</code>، إذ يمكن استخدامها خارج مجال البرمجية الوظيفية، وهي تعريف معالجات الأحداث في برمجة الواجهات الرسومية، حيث تكون معالجات الأحداث دوالًا قصيرةً في الغالب، أو تستدعي دوالًا أكبر منها بقيم وسائط مدمجة فيها، وفي كلا الحالتين يمكن استخدام دالة لامدا مثل معالج حدث يتجنب الحاجة إلى تعريف الكثير من الدوال المنفردة وشغل فضاء الاسم بأسماء لن تُستخدم إلا مرةً واحدةً فقط، ويجب تذكر أن تعليمة لامدا تعيد كائن دالة يُمرَّر إلى الودجِت widget ويُستدعى في وقت وقوع الحدث، وقد عرَّفنا ودجت الزر في Tkinter من قبل، لذا ستبدو لامدا كما يلي:
</p>

<pre class="ipsCode prettyprint lang-py prettyprinted" id="ips_uid_6246_72" style=""><span class="pln">b </span><span class="pun">=</span><span class="pln"> </span><span class="typ">Button</span><span class="pun">(</span><span class="pln">parent</span><span class="pun">,</span><span class="pln"> text</span><span class="pun">=</span><span class="str">"Press Me"</span><span class="pun">,</span><span class="pln"> 
           command </span><span class="pun">=</span><span class="pln"> </span><span class="kwd">lambda</span><span class="pln"> </span><span class="pun">:</span><span class="pln"> </span><span class="kwd">print</span><span class="pun">(</span><span class="str">"I got pressed!"</span><span class="pun">))</span><span class="pln">
b</span><span class="pun">.</span><span class="pln">pack</span><span class="pun">()</span></pre>

<p>
	نلاحظ أنه رغم عدم السماح لمعالج الحدث بامتلاك معامِل إلا أننا نسمح بتحديد سلسلة داخل متن لامدا، ونستطيع الآن إضافة زر ثانٍ بسلسلة مختلفة كليًا:
</p>

<pre class="ipsCode prettyprint lang-py prettyprinted" id="ips_uid_6246_74" style=""><span class="pln">b2 </span><span class="pun">=</span><span class="pln"> </span><span class="typ">Button</span><span class="pun">(</span><span class="pln">parent</span><span class="pun">,</span><span class="pln"> text</span><span class="pun">=</span><span class="str">"Or Me"</span><span class="pun">,</span><span class="pln"> 
           command </span><span class="pun">=</span><span class="pln"> </span><span class="kwd">lambda</span><span class="pln"> </span><span class="pun">:</span><span class="pln"> </span><span class="kwd">print</span><span class="pun">(</span><span class="str">"I got pressed too!"</span><span class="pun">))</span><span class="pln">
b2</span><span class="pun">.</span><span class="pln">pack</span><span class="pun">()</span></pre>

<p>
	كما نستطيع توظيف <code>lambda</code> عند استخدام تقنية الربط bind technique التي ترسل كائن حدث مثل وسيط:
</p>

<pre class="ipsCode prettyprint lang-py prettyprinted" id="ips_uid_6246_76" style=""><span class="pln">b3 </span><span class="pun">=</span><span class="pln"> </span><span class="typ">Button</span><span class="pun">(</span><span class="pln">parent</span><span class="pun">,</span><span class="pln"> text</span><span class="pun">=</span><span class="str">"Press me as well"</span><span class="pun">)</span><span class="pln">
b3</span><span class="pun">.</span><span class="pln">bind</span><span class="pun">(&lt;</span><span class="typ">Button</span><span class="pun">-</span><span class="lit">1</span><span class="pun">&gt;,</span><span class="pln"> </span><span class="kwd">lambda</span><span class="pln"> ev </span><span class="pun">:</span><span class="pln"> write</span><span class="pun">(</span><span class="str">"Pressed"</span><span class="pun">))</span></pre>

<h2>
	البرمجية الوظيفية في جافاسكربت
</h2>

<p>
	لا نريد الخوض في تفاصيل البرمجية الوظيفية هنا، لكن من المهم أن ندرك أن جافاسكربت متأثرة كثيرًا بمفاهيم البرمجية الوظيفية، بل إن الاستخدام الحديث لها يشجع استخدام البرمجية الوظيفية أكثر من البرمجة الكائنية، ومفتاح البرمجية الوظيفية فيها هو أن إمكانية كتابة تعريفات الدوال بأسلوب مشابه لتعابير لامدا، فلا تتطلب إلا تغييرًا بسيطًا في الأسلوب والبنية اللغوية لتعريف الدالة، انظر هذا المثال من مقال <a href="https://academy.hsoub.com/programming/general/%D8%A7%D9%84%D8%A8%D8%B1%D9%85%D8%AC%D8%A9-%D8%A8%D8%A7%D8%B3%D8%AA%D8%AE%D8%AF%D8%A7%D9%85-%D8%A7%D9%84%D9%88%D8%AD%D8%AF%D8%A7%D8%AA-r1333/" rel="">البرمجة باستخدام الوحدات</a>:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_6246_78" style=""><span class="pun">&lt;</span><span class="pln">script type</span><span class="pun">=</span><span class="str">"text/javascript"</span><span class="pun">&gt;</span><span class="pln">
</span><span class="kwd">var</span><span class="pln"> i</span><span class="pun">,</span><span class="pln"> values</span><span class="pun">;</span><span class="pln">

</span><span class="kwd">function</span><span class="pln"> times</span><span class="pun">(</span><span class="pln">m</span><span class="pun">)</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
    </span><span class="kwd">var</span><span class="pln"> results </span><span class="pun">=</span><span class="pln"> </span><span class="kwd">new</span><span class="pln"> </span><span class="typ">Array</span><span class="pun">();</span><span class="pln">
    </span><span class="kwd">for</span><span class="pln"> </span><span class="pun">(</span><span class="pln">i </span><span class="pun">=</span><span class="pln"> </span><span class="lit">1</span><span class="pun">;</span><span class="pln"> i </span><span class="pun">&lt;=</span><span class="pln"> </span><span class="lit">12</span><span class="pun">;</span><span class="pln"> i</span><span class="pun">++)</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
        results</span><span class="pun">[</span><span class="pln">i</span><span class="pun">]</span><span class="pln"> </span><span class="pun">=</span><span class="pln"> i </span><span class="pun">*</span><span class="pln"> m</span><span class="pun">;</span><span class="pln">
        </span><span class="pun">}</span><span class="pln">
    </span><span class="kwd">return</span><span class="pln"> results</span><span class="pun">;</span><span class="pln">
</span><span class="pun">}</span><span class="pln">


</span><span class="com">// استخدم الدالة</span><span class="pln">
values </span><span class="pun">=</span><span class="pln"> times</span><span class="pun">(</span><span class="lit">8</span><span class="pun">);</span><span class="pln">

</span><span class="kwd">for</span><span class="pln"> </span><span class="pun">(</span><span class="pln">i</span><span class="pun">=</span><span class="lit">1</span><span class="pun">;</span><span class="pln">i</span><span class="pun">&lt;=</span><span class="lit">12</span><span class="pun">;</span><span class="pln">i</span><span class="pun">++){</span><span class="pln">
    document</span><span class="pun">.</span><span class="pln">write</span><span class="pun">(</span><span class="pln">values</span><span class="pun">[</span><span class="pln">i</span><span class="pun">]</span><span class="pln"> </span><span class="pun">+</span><span class="pln"> </span><span class="str">"&lt;br /&gt;"</span><span class="pun">);</span><span class="pln">
    </span><span class="pun">}</span><span class="pln">
</span><span class="pun">&lt;/</span><span class="pln">script</span><span class="pun">&gt;</span></pre>

<p>
	لاحظ أننا عرّفنا الدالة بوضع الاسم <code>times</code> بعد الكلمة المفتاحية <code>function</code>، لكن جافاسكربت تسمح لنا بتسمية الدالة من خلال الإسناد، كما في أسلوب لامدا الخاص ببايثون أعلاه:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_6246_82" style=""><span class="pln">times </span><span class="pun">=</span><span class="pln"> </span><span class="kwd">function</span><span class="pun">(</span><span class="pln">m</span><span class="pun">)</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
    </span><span class="kwd">var</span><span class="pln"> results </span><span class="pun">=</span><span class="pln"> </span><span class="kwd">new</span><span class="pln"> </span><span class="typ">Array</span><span class="pun">();</span><span class="pln">
    </span><span class="kwd">for</span><span class="pln"> </span><span class="pun">(</span><span class="pln">i </span><span class="pun">=</span><span class="pln"> </span><span class="lit">1</span><span class="pun">;</span><span class="pln"> i </span><span class="pun">&lt;=</span><span class="pln"> </span><span class="lit">12</span><span class="pun">;</span><span class="pln"> i</span><span class="pun">++)</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
        results</span><span class="pun">[</span><span class="pln">i</span><span class="pun">]</span><span class="pln"> </span><span class="pun">=</span><span class="pln"> i </span><span class="pun">*</span><span class="pln"> m</span><span class="pun">;</span><span class="pln">
        </span><span class="pun">}</span><span class="pln">
    </span><span class="kwd">return</span><span class="pln"> results</span><span class="pun">;</span><span class="pln">
</span><span class="pun">}</span></pre>

<p>
	لذا يكون <code>times</code> الآن متغيرًا يحمل مرجعًا إلى كائن الدالة، ويمكن استدعاؤه كما فعلنا من قبل:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_6246_84" style=""><span class="pln">values </span><span class="pun">=</span><span class="pln"> times</span><span class="pun">(</span><span class="lit">8</span><span class="pun">);</span><span class="pln">

</span><span class="kwd">for</span><span class="pln"> </span><span class="pun">(</span><span class="pln">i</span><span class="pun">=</span><span class="lit">1</span><span class="pun">;</span><span class="pln">i</span><span class="pun">&lt;=</span><span class="lit">12</span><span class="pun">;</span><span class="pln">i</span><span class="pun">++){</span><span class="pln">
    document</span><span class="pun">.</span><span class="pln">write</span><span class="pun">(</span><span class="pln">values</span><span class="pun">[</span><span class="pln">i</span><span class="pun">]</span><span class="pln"> </span><span class="pun">+</span><span class="pln"> </span><span class="str">"&lt;br /&gt;"</span><span class="pun">);</span><span class="pln">
    </span><span class="pun">}</span></pre>

<p>
	بل يمكن استخدام <code>function()‎</code> لإنشاء دوال مجهولة كما في لامدا، باستثناء أنه ليس لجافاسكربت قيود على أنواع الدوال التي ننشئها، فيمكن أن تكون بأي طول وتعقيد نريده، مما يؤدي إلى نمط في <a href="https://academy.hsoub.com/programming/javascript/%d9%85%d8%a7-%d9%87%d9%8a-%d8%ac%d8%a7%d9%81%d8%a7-%d8%b3%d9%83%d8%b1%d9%8a%d8%a8%d8%aa-%d8%9f-r524/" rel="">برمجة جافاسكربت</a> ستقابله غالبًا في صفحات الويب، ولذا سنسرد مثالًا مختصرًا له هنا، وهو يتضمن استخدام دوال جافاسكربت التي تأخذ دوالًا أخرى معامِلات لها، وقد رأينا هذا في برامج الواجهة الرسومية من قبل وسميناه رد النداء callback، لأن العديد من مكتبات جافاسكربت تستخدم رد النداء ذاك، ويكون عادةً من دالة رد نداء تُحدَّد على أنها المعامِل الأخير، وهنا مثال من رد نداء مُستخدَم في صفحة ويب بسيطة، وهي مثال كامل، لذا يمكن تحميله وتجربته في المتصفح:
</p>

<pre class="ipsCode prettyprint lang-html prettyprinted" id="ips_uid_6246_87" style=""><span class="tag">&lt;html&gt;</span><span class="pln">
</span><span class="tag">&lt;head&gt;</span><span class="pln">
</span><span class="tag">&lt;title&gt;</span><span class="pln">Callback test</span><span class="tag">&lt;/title&gt;</span><span class="pln">
</span><span class="tag">&lt;script</span><span class="pln"> </span><span class="atn">type</span><span class="pun">=</span><span class="atv">"text/javascript"</span><span class="tag">&gt;</span><span class="pln">
window</span><span class="pun">.</span><span class="pln">setTimeout</span><span class="pun">(</span><span class="pln"> </span><span class="kwd">function</span><span class="pun">()</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
       document</span><span class="pun">.</span><span class="pln">write</span><span class="pun">(</span><span class="str">"رأيتني الآن!"</span><span class="pun">);</span><span class="pln">
     </span><span class="pun">},</span><span class="pln"> </span><span class="lit">3000</span><span class="pun">);</span><span class="pln">
</span><span class="tag">&lt;/script&gt;</span><span class="pln">
</span><span class="tag">&lt;/head&gt;</span><span class="pln">

</span><span class="tag">&lt;body&gt;</span><span class="pln">
</span><span class="tag">&lt;p&gt;</span><span class="pln">انتظر نهاية الوقت....</span><span class="tag">&lt;p&gt;</span><span class="pln">

</span><span class="tag">&lt;/body&gt;</span><span class="pln">
</span><span class="tag">&lt;/html&gt;</span></pre>

<p>
	نلاحظ أن الدالة التي نفذها الوقت المستقطع لي لها اسم، فقد أُنشئت وسيطًا أول في استدعاء <code>setTimeout</code> نفسه، ثم أضيف زمن الانتظار الذي هو 3000 مللي ثانية وسيطًا ثانيًا، فإذا حملته في المتصفح لديك فسترى وقت الانتظار يحل محل الرسالة الأولى بعد ثلاث ثوانٍ.
</p>

<p>
	صار هذا الأسلوب من تعريف الدوال المضمَّنة شائعًا للغاية في مجتمع جافاسكربت، وما هو إلا برمجة وظيفية خالصة، وتحتوي <a href="https://academy.hsoub.com/programming/javascript/jquery/%d8%a3%d8%b3%d8%a7%d8%b3%d9%8a%d9%91%d8%a7%d8%aa-jquery-r60/" rel="">JQuery</a> وهي إحدى أشهر مكتبات الويب لجافاسكربت، على دوال كثيرة تأخذ دوالًا أخرى مثل معامِلات، لنحصل على أسلوب برمجي وظيفي للغاية.
</p>

<p>
	أما VBScript فليس فيها دعم مباشر للبرمجة الوظيفية، لكن يمكن استخدامها بأسلوب وظيفي إذا كان لدى المبرمج صبر على ذلك، بهيكلة البرامج مثل تعابير وعدم السماح للآثار الجانبية بتعديل متغيرات البرنامج.
</p>

<h2>
	خاتمة
</h2>

<p>
	نرجو في نهاية هذا المقال أن تكون تعلمت ما يلي:
</p>

<ul>
	<li>
		البرامج الوظيفية ما هي إلا تعابير خالصة.
	</li>
	<li>
		توفر بايثون <code>map</code> و <code>filter</code> و <code>reduce</code> و <a href="https://academy.hsoub.com/programming/python/%D9%81%D9%87%D9%85-%D9%83%D9%8A%D9%81%D9%8A%D8%A9-%D8%A7%D8%B3%D8%AA%D8%B9%D9%85%D8%A7%D9%84-list-comprehensions-%D9%81%D9%8A-%D8%A8%D8%A7%D9%8A%D8%AB%D9%88%D9%86-3-r515/" rel=""><code>list comprehensions</code></a> لدعم أسلوب البرمجية الوظيفية.
	</li>
	<li>
		تعابير لامدا هي كتل من الشيفرات المجهولة التي لا تحمل اسمًا، ويمكن إسنادها إلى متغيرات أو استخدامها مثل دوال.
	</li>
	<li>
		تقيِّم التعابير البوليانية عند الحاجة فقط لضمان النتيجة التي تمكن تلك التعابير من استخدامها مثل هياكل تحكم.
	</li>
	<li>
		عند جمع مزايا البرمجية الوظيفية لبايثون مع التعاودية فمن الممكن كتابة أي دالة بأسلوب وظيفي في بايثون، رغم أننا لا ننصح بهذا.
	</li>
	<li>
		تدعم جافاسكربت البرمجية الوظيفية، وهو الموجود الآن في أغلب صفحات الويب الحديثة.
	</li>
</ul>

<p>
	ترجمة -بتصرف- <a href="http://www.alan-g.me.uk/l2p2/tutfctnl.htm" rel="external nofollow">للفصل الحادي والعشرين: Functional Programming</a> من كتاب Learn To Program لصاحبه Alan Gauld.
</p>

<h2>
	اقرأ أيضًا
</h2>

<ul>
	<li>
		المقال التالي: <a href="https://academy.hsoub.com/programming/general/%D8%AF%D8%B1%D8%A7%D8%B3%D8%A9-%D8%AD%D8%A7%D9%84%D8%A9-%D8%A8%D8%B1%D9%85%D8%AC%D9%8A%D8%A9-r1392/" rel="">دراسة حالة برمجية</a>
	</li>
	<li>
		المقال السابق: <a href="https://academy.hsoub.com/programming/general/%D9%85%D9%81%D9%87%D9%88%D9%85-%D8%A7%D9%84%D8%AA%D8%B9%D8%A7%D9%88%D8%AF%D9%8A%D8%A9-recursion-r1387/" rel="">مفهوم التعاودية Recursion</a>
	</li>
	<li>
		<a href="https://academy.hsoub.com/programming/general/%D8%A7%D9%84%D8%A8%D8%B1%D9%85%D8%AC%D8%A9-%D8%A7%D9%84%D8%AD%D8%AF%D8%AB%D9%8A%D8%A9-event-driven-programming-%D8%A7%D9%84%D9%85%D8%B3%D8%A7%D9%82%D8%A9-%D8%A8%D8%A7%D9%84%D8%A3%D8%AD%D8%AF%D8%A7%D8%AB-r1376/" rel="">البرمجة الحدثية Event Driven Programming المساقة بالأحداث</a>
	</li>
	<li>
		<a href="https://academy.hsoub.com/programming/general/%D9%85%D9%82%D8%AF%D9%85%D8%A9-%D9%81%D9%8A-%D8%A7%D9%84%D8%A8%D8%B1%D9%85%D8%AC%D8%A9-%D8%A7%D9%84%D8%B4%D8%B1%D8%B7%D9%8A%D8%A9-r1329/" rel="">مقدمة في البرمجة الشرطية</a>
	</li>
	<li>
		<a href="https://academy.hsoub.com/programming/general/%D8%A7%D9%84%D8%A8%D8%B1%D9%85%D8%AC%D8%A9-%D9%83%D8%A7%D8%A6%D9%86%D9%8A%D8%A9-%D8%A7%D9%84%D8%AA%D9%88%D8%AC%D9%87-r1375/" rel="">البرمجة كائنية التوجه</a>
	</li>
</ul>
]]></description><guid isPermaLink="false">1391</guid><pubDate>Tue, 07 Dec 2021 16:09:00 +0000</pubDate></item></channel></rss>
