لوحة المتصدرين
المحتوى الأكثر حصولًا على سمعة جيدة
المحتوى الأعلى تقييمًا في 12/24/15 في كل الموقع
-
SSE اختصار لـ Server Sent Events وتسمى أيضًا EventSource تُستخدم لِبنّاء تطبيقات ويب تفاعلية. حيث يُرسل الخادوم أحداثا في الوقت الحقيقي إلى المستخدم، قد يتضمن الحدث تنبيهات للمستخدم أو بيانات يمكن استغلالها في عمل شيء ما وتحديث صفحة الويب. في السّابق، لِعمل تحديث تلقائي للبيانات كل ثانية كانت تُستَخدم هذه الطريقة: setInterval(function(){ // إستدعاء الدالة بشكل تكراري xhr = new XMLHttpRequest(); // إستخدام طلب ajax xhr.onreadystatechange = function(){// عند أي تغير في حالة الطلب if(this.readyState == 4){// تم إستقبال النص بنجاح // إفعل بعض الاوامر } } xhr.open("get","http://localhost"); // تحديد نوع الطلب ورابط الموقع xhr.send("mydata"); // إرسال البيانات إلى الخادم }, 1000); // تحديد مدّة التكرار إلى ثانية أو هذه الطريقة الأكثر تطورًا: function getAjax(){ // تعريف الدالة التي ستدعى بشكل تكراري xhr = new XMLHttpRequest(); xhr.onreadystatechange = function(){ if(this.readyState == 4) setTimeout(function(){ // استدعاء ألدالة مجددًا بعد ثانية من الإنتهاء لِتكرار طلب الajax getAjax(); },1000); } xhr.open("get","http://localhost"); xhr.send("mydata"); } getAjax();// إستدعاء الدالة للمرة الأولىهذه الطرق صحيحة لكنها ليست الأفضل، حيث تقوم بإرسال طلب كل ثانية للخادم مما يُسبٍّب ضغط عليه وغالبًا لا يكون التحديث في الوقت الحقيقي لظهوره. فكرة عمل SSE أن الطلب يظل مَفتوحا في إنتظار محتوى جديد والخادم هو من يُرسل المحتوى الجديد وليس المتصفح من يطلبه. SSE ليست الطريقة الوحيدة لِبناء تطبيقات ويب تفاعلية، يوجد العديد من الطرق الأخرى من أشهرها WebSocket. مُقارنة بين SSE و WebSocketالسهولة والتوافقيةمعظم الإستضافات المشتركة لا تَدعم WebSocket وهو يعمل على بروتوكل ws أو wss (في حالة إستخدام شهادة أمان ssl) وهما مختلفان عن الذي عليه واجهة المستخدم مما يُسبِّب مشاكل في مصادفة الاثنين معًا (يوجد مكتبات لفعل ذلك) على خلاف SSE التي تُعتبر طلب عادي على نفس بروتوكول واجهة المستخدم النهائية. تزامن المتسخدمينWebSocket يُمكنها عمل تزامن بين المستخدمين بطريقة مباشرة حيث أن الإتصلات تُعالج كلها معًا. في SSE لايوجد طريقة مباشرة لِتزامن المسخدمين معًا لأن كل طلب مُنفصل عن الآخر لذا تُستخدم قاعدة بيانات وتحفظ أخر التغيرات للمستخدم الأول وعند المستخدم الآخر يَتم البحث بشكل دوري عن التغيرات في قاعدة البيانات ثم إرسالها إلى المستخدم الآخر. إرسال وإستقبال البياناتWebSocket و SSE يدعمان إستقبال البيانات لكن لا يُمكن إرسال البيانات إلى الخادم بإستخدام SSE، أي عند بناء تطبيق يعتمد على إرسال وإستقبال البيانات من الخادوم ستضطر إلى بناء صفحة منفصلة تقوم بإستقبال الطلبات من المستخدم بواسطة ajax مثلًا. تطبيقات قد يكون إستخدام WebSocket فيها أفضلفي تطبيق سيحتاج إلى تفاعل المستخدمين معًا (تطبيق تواصل مثلًا) سيكون إستخدام WebSocket أفضل من SSE لأن الأخيرة لا يُمكنها إستقبال الطلبات من الخادوم.إرسال إشعارات أو رسائل للمستخدم أو أي تطبيق لن يَحتاج المستخدم فيه إلى إرسال رسائل إلى الخادوم. هنا ممكن أن يكون إستخدام SSE أفضل وأسهل.اهلًا بالعالمقبل البدء يجب أن تَعرف المتصفحات الداعمة لـِ SSE وأن متصفح أنترنت أكسبلور لايَدعمه لكن يُمكنك إستخدام مكتبة خارجية لدعمه مثل EventSource.js (يتم تضمين ملف javascript في الصفحة) هذا مثال لنص مصدري لإستجابة طلب SSE: http/1.1 200 OK ## الصفحة موجودة ! Content-Type: text/event-stream ## تعريف المتصفح أن الصفحة هي محتوى لطلب SSE event: delete## تعريف الحدث الذي سيُستقبل من javascript data: "some data" ## البيانات التي سترسل إلى الحدث event: add## تعريف حدث آخر data: "some data" data: "some data"## إرسال بيانات بدون حدث مُعرف id: 3 ## غير مهم وغير مطلوب بشكل ضروري يُستخدم لتحديد مُعرف lastEventId للرسائلالأمثلة مكتوبة بلغة php ويُمكنك فعلها في أي لغة ويب أخرى هذا تطبيق بسيط لجلب الساعة من الخادم لحظة بلحظة. ملف server.php ( الذي سيعالج طلبات SSE احفظه بجوار واجهة المستخدم أو أي مكان آخر مع تغير المسار في شفرة javascript ): <?php set_time_limit(0);// تحديد أقصى مدة للطلب غير نهائية لان هناك خوادم تقوم بتحديدها $time = 1;// متغير بقيمة الوقت الذي سيرسل فيه تحديث جديد header("Content-Type: text/event-stream");// إرسال ترويسة أن الصفحة هي محتوى sse header('Cache-Control: no-cache'); // لمنع حفظ الكاش للصفحة while(true){// تكرار /* date("s-i-h") تُخرج الوقت على التَنسيق ساعة-دقيقة-ثانية PHP_EOL تعني سطر جديد يُمكن إستخدام \n لكن سَتختلف من نظام تَشغيل الى آخر */ echo "data: ".date("s-i-h").PHP_EOL; echo PHP_EOL; // كتابة نص جديد آخر للتفريق بين التنبيهات // إرسال المحتوى الذي كتب دون الإنتظار إلى انتهاء الصفحة ob_flush(); flush(); // إيقاف الاسكربت إلى المدة التي تم تعريفها في المتغير time لمدة ثانية أن لم تَقف الاسكربت سَيعمل بدون توقف sleep($time); } ?>إن فتحت الصفحة ستجد أنها تقوم بإرسال الساعة الحالية كل ثانية. الآن الواجهة التي ستتعامل معها: <!DOCTYPE HTML> <html> <head> <meta charset="utf-8"> </head> <body style="direction: rtl"> <label>الساعة الآن : <span>.......</span></label> <script type="text/javascript"> if(!EventSource) alert("مٌتصفحك لايَدعم SSE :("); else{ SSE = new EventSource("server.php"); // انشاء الطلب SSE.onmessage = function(ms){ // عند وجود رسالة جديدة document.querySelector("span").innerHTML = ms.data;// استبدال النص بالجديد } SSE.onerror = function(){//عند وجود خطأ alert("يوجد خطأ في الاتصال ..."); mkcon(); // إعادة الطلب } } </script> </body> </html> الأحداث وطرق انشاءهايُمكن في SSE إنشاء أحداث مخصصة لكي تَكون الشفرة أكثر ذكاءا، مثلًا إرسال حدث لحذف عنصر وحدث لإنشاء عنصر آخر. مثال: تعريف مصفوفة بإسم الألوان أحمر أخضر أزرق. $colors = array("red", "green", "blue");ثم تعريف اسم الحدث بإسم عشوائي من هذه الألوان: $colors[rand(0,2)];ليكون النص الكامل لملف server.php: <?php set_time_limit(0);// تحديد أقصى مدة للطلب غير نهائية لان هناك خوادم تقوم بتحديدها $time = 1;// متغير بقيمة الوقت الذي سيرسل فيه تحديث جديد header("Content-Type: text/event-stream");// إرسال ترويسة أن الصفحة هي محتوى sse $colors = array( // مصفوفة الألوان من النوع الرقمي "red", "green", "blue" ); while(true){// تكرار /* date("s-i-h") تُخرج الوقت على التَنسيق ساعة-دقيقة-ثانية PHP_EOL تعني سطر جديد يُمكن إستخدام \n لكن سَتختلف من نظام تَشغيل إلى آخر */ echo "data: ".date("s-i-h").PHP_EOL; echo "event: ". $colors[rand(0,2)] // توليد لون عشوائي بإسم الحدث .PHP_EOL; echo PHP_EOL; // كتابة نص جديد آخر للتفريق بين التنبيهات // إرسال المحتوى وعدم الإنتظار إلى إكتمال الطلب إلى النهاية ob_flush(); flush(); // إيقاف الاسكربت إلى المدة التي تم تعريفها في المتغير time لمدة ثانية أن لم تَقف الاسكربت سَيعمل بدون توقف sleep($time); } ?>وفي واجهة المستخدم إنشاء بعض العناوين: <style> .red{ color: red } .blue{ color: blue } .green{ color: green } </style> <label class="red"> ....... </label> <label class="green"> ....... </label> <label class="blue"> ....... </label>الآن إستقبال الأحداث: SSE.addEventListener("red",function(ms){ //اللّون الأحمر red اسم الحدث الذي عرف من php document.querySelector(".red").innerHTML = ms.data; });لتصبح شفرة الواجهة الكاملة: <!DOCTYPE HTML> <html> <head> <meta charset="utf-8"> <style> .red{ color: red } .blue{ color: blue } .green{ color: green } </style> </head> <body> <label class="red"> ....... </label> <label class="green"> ....... </label> <label class="blue"> ....... </label> <script type="text/javascript"> if(!EventSource) alert("مٌتصفحك لايَدعم SSE :("); else{ function mkcon(){ SSE = new EventSource("server.php"); // إنشاء الطلب SSE.addEventListener("red",function(ms){ //اللون الأحمر document.querySelector(".red").innerHTML = ms.data; }); SSE.addEventListener("green",function(ms){ //اللون الأخضر document.querySelector(".green").innerHTML = ms.data; }); SSE.addEventListener("blue",function(ms){ //اللون الأزرق document.querySelector(".blue").innerHTML = ms.data; }); SSE.onerror = function(){//عند وجود خطأ alert("يوجد خطأ في الاتصال ..."); mkcon(); // اعادة الطلب } } mkcon(); } </script> </body> </html>ستجد أن أحدى الساعات من الثلاثة تزيد بشكل عشوائي كل ثانية لكن بالطبع هذا مثال، لن تقوم بإستخدام هذه التقنية في هذا. إستخدام بيانات jsonإن أردت إرسال مقال بإستخدام SSE فستحتاج إلى إرسال العنوان والمحتوى ولن تُرسل حدثين لذلك يُمكنك إستخدام json كما يلي: { "title": "العنوان", "content": "المحتوى" }اذًا سَترسل هذه البيانات: data: {"title": "ألعنوان","content":"ألمحتوى"}ثم سيكون إستقبال البيانات من خلال javascript بهذا الشكل: SSE.onmessage = function(ms){ var JsonData = JSON.parse(ms.data); // قراءة نص json alert(JsonData.title + "\n" + JsonData.content); }مثال عملي عن إرسال بيانات json بتوقيت السيرفر المحلي: ملف server.php <?php set_time_limit(0);//تُحدد أقصى مدة للطلب غير نهائية لان هناك خوادم تقوم بتحديدها $time = 1;// متغير بقيمة الوقت الذي سيرسل فيه تحديث جديد header("Content-Type: text/event-stream");// إرسال ترويسة أن الصفحة هي محتوى sse while(true){// تكرار /* date("s-i-h") تُخرج الوقت على التَنسيق ساعة-دقيقة-ثانية PHP_EOL تعني سطر جديد يُمكن إستخدام \n لكن سَتختلف من نظام تَشغيل الى آخر */ echo 'data: '. /** مصفوفة بالوقت. دالة json_encode تقوم بتحويل البيانات الى ترميز json */ json_encode(array( "hour" => date("h"), // الساعة "minute" => date("i"), // الدقيقة "second" => date("s") // الثانية )) .PHP_EOL; echo PHP_EOL; // كتابة نص جديد آخر للتفريق بين التنبيهات // إرسال المحتوى وعدم الإنتظار إلى إكتمال الطلب إلى النهاية ob_flush(); flush(); // إيقاف الاسكربت إلى المدة التي تم تعريفها في ألمتغير time لمدة ثانية ان لم تَقف الاسكربت سَيعمل بدون توقف sleep($time); } ?>وملف الواجهة: <!DOCTYPE HTML> <html> <head> <meta charset="utf-8"> </head> <body style="direction: rtl"> <p>الساعة الآن <b id="hour">0</b> و <b id="minute">0</b> دقيقة و <b id="second">0</b> ثانية.</p> <script type="text/javascript"> if(!EventSource) alert("مٌتصفحك لايَدعم SSE :("); else{ function mkcon(){ SSE = new EventSource("server.php"); // إنشاء الطلب SSE.onmessage = function(ms){ var JsonData = JSON.parse(ms.data); // قراءة نص json document.querySelector("#hour").innerHTML = JsonData.hour; // إستبدال الساعة document.querySelector("#minute").innerHTML = JsonData.minute;// إستبدال الدقائق document.querySelector("#second").innerHTML = JsonData.second;// إستبدال الثواني } SSE.onerror = function(){//عند وجود خطأ alert("يوجد خطأ في الاتصال ..."); mkcon(); // إعادة الطلب } } mkcon(); } </script> </body> </html>في هذا المثال والذي سبقه لن تَحتاج إلى إستحدام SSE ويمكن عَمل ذلك بإستخدام javascript بسهولة. تطبيق على ما شُرح: بناء تطبيق تواصللم تُستخدم قاعدة بيانات لتسهيل تشغيل السكربت (لكن بالطبع إستخدام قاعدة بيانات أفضل) سيولد لون لكل مستخدم وسيحفظ في cookies للتعرف عليه في الرسائل، ستحفظ البيانات في ملف ChatData.json على هذا الشكل (كان يُمكن إستخدام قاعدة بيانات sqlite): [// مصفوفة الرسائل { "author": "rgb(54,48,98)", // لون السمتخدم "message": "رسالة", }, { "author": "rgb(54,48,98)", // لون السمتخدم "message": "رسالة 2", }// ....,...,.. ]تصميم الواجهةهذه هيكلة الصفحة: <!DOCTYPE html> <html> <head> <meta charset="utf-8"> <title>تجربة</title> <meta name="viewport" content="width=device-width"> </head> <body> <div class="messages"> </div> <div class="form"> <div class="author me"></div> <textarea placeholder="كتابة رسالة"></textarea> <button id="send">أرسل</button> </div> </body> </html>إضافة الحيوية للصفحة: body,html{ width: 100%;/** جعل عرض الصفحة بكامل الشاشة **/ direction: rtl; height: 100%; background: #f0f0f0;/** لون الخلفية **/ padding: 0; margin: 0 } /** جعل حجم بعض العناصر يحسب بالحواشي الخارجة **/ .messages, .messages > .message, .message > .content, .form, .form > textarea{ box-sizing: border-box } /** الرسائل **/ .messages{ padding: 40px; /** عمل فراغ بقيمة 40px من كل جهة **/ height: 80%; overflow-y: auto/** جعل الرسائل الزائدة تتحول الى اسكرول **/ } /** عناصر لن تكون بكامل عرض الحافظة **/ .message > .author, .message > .content{ display: inline-block;/** لن يأخذ العنصر كامل العرض **/ vertical-align: top /** العنصر سيكون في محاذة الأعلى **/ } /** هوية المستخدم **/ .message > .author{ width: 64px; height: 64px; background: #ddd; /** اللون الافتراضي سيغير بعد ذلك **/ border-radius: 100% /** تدوير العنصر **/ } /** جسم الرسالة **/ .message > .content{ background: white; box-shadow: 0 0 1px #ccc; /** تأثير الظل **/ padding: 20px; margin-right: 30px; /** لجعل الصفحة أكثر إستجابة على الشاشات المختلفة **/ width: 100%; max-width: 550px } /** عناصرالتحكم لإرسال رسالة **/ .form{ padding: 10px; height: 20% } /** صندوق النصوص **/ .form > textarea{ width: 100%; max-width: 678px; height: 100% } /** زر الإرسال **/ .form > button{ background: rgb(31, 158, 238); padding: 4px 20px; border: 0; cursor: pointer; /** مؤشر الفارة **/ color: white; border-radius: 3px /** عمل بعض الحواف **/ } .form > button:active{ background: rgb(31, 158, 200) } /** تصميم الجوال إصلاح بعض العلل **/ @media screen and (max-width:640px){ .messages{ padding: 0 } .message > .content{ margin: 0; margin-bottom: 20px } }إستقبال الرسائلSEE لاتدعم إرسال البيانات إلى الخادوم لذا سَتستخدم ajax لذلك. هذه شفرة بسيطة لإرسال الرسائل إلى الخادوم (يُضاف بين الوسم script في أخر الصفحة قبل </body> أو إن كنت ستضيفه الى head، يجب أن يكون في دالة: window.onload = function(){ //هنا }; document.querySelector("#send").addEventListener("click",function(){// عند الضغط على زر إرسال var mss = document.querySelector(".form > textarea").value; // محتوى الرسالة if(mss && mss.length){// التأكد من أن الرسالة مكتوبة var ajax = new XMLHttpRequest(); ajax.onreadystatechange = function(){ if(this.readyState == 4) alert("تم إرسال الرسالة"); } ajax.open("get","server.php"); // نوع الطلب ومسار الإرسال ajax.send("?ms="+mss);// إرسال الرسالة } });ستحدث مشكلة إن أرسل المستخدم أكثر من رسالة في وقت واحد، من الممكن أن تصل رسالة قبل الأخرى. لذا سنستعمل قائمة بالرسائل المرسلة ونقوم بمعالجتها واحدة ثم الأخرى مع تحسين تجربة المستخدم قليلًا: messagesList = []; // مصفوفة بالرسائل InProgress = false;// يوجد طلب يُعالج أم لا function sendFirstMessage(){ if(!messagesList.length || InProgress) // لايوجد رسائل أو هناك رسالة تُعالج return false; var ajax = new XMLHttpRequest(); ajax.onreadystatechange = function(){ // الرسالة ارسلت if(this.readyState == 4){ messagesList.splice(0, 1);// حذف الرسالة المرسلة اول رسالة InProgress = false; // تم الإنتهاء من العمل sendFirstMessage(); // إرسال الرسالة الأخرى } } ajax.onerror = function(){ alert("خطأ في الإتصال جاري المحاولة مجددًا"); sendFirstMessage(); } InProgress = true; ajax.open("get","send.php?message="+messagesList[0]); // نوع الطلب ومسار الإرسال ajax.send();// إرسال الرسالة } document.querySelector("#send").addEventListener("click",function(){// عند الضغط على زر إرسال var mss = document.querySelector(".form > textarea").value; // محتوى الرسالة if(mss && mss.length){// التأكد من أن هناك رسالة مكتوبة messagesList.push(mss); // إضافة رسالة إلى المصفوفة sendFirstMessage(); // إرسال الرسالة الأولى document.querySelector(".form > textarea").value = "";// افراغ حقل إرسال الرسائل } });ملف الخادوم الذي سيستقبل الرسائل، لن تكتب [] في الملف لتسهيل الكتابة في نهايته دون قِرائته: ملف send.php (الذي سيستقبل الرسائل) <?php if(empty($_GET["message"])) die(); /* التأكد من المستخدم */ if(!isset($_COOKIE["author"]) || !preg_match("/^rgb\([0-9]{0,3}\,[0-9]{0,3}\,[0-9]{0,3}\)$/i",$_COOKIE["author"])){ // توليد لون عشوائي أن لم يُعرف من قبل $R = rand(0,250); // اللّون الأحر $G = rand(0,250); // اللّون الأخضر $B = rand(0,250); // اللّون الأزرق setcookie("author","rgb($R,$G,$B)"); // نمط الألوان rgb } $message = str_replace(array("<",">"),array("<",">"),$_GET["message"]); // الوقاية من ثغرة xss $data = array( // البيانات التي ستكتب "content" => $message, "author" => $_COOKIE["author"] ); $FILE = fopen("./ChatData.json","a"); //فتح الملف للكتابة فيه $star = (!filesize("./ChatData.json")) ? "" :",";// إضافة فاصلة أن تم الكتابة بالملف من قبل fwrite($FILE,$star.json_encode($data)); // كتابة بيانات json في الملف fclose($FILE); ?>ملاحظة: سبب إستخدام الألوان هو لكي تتمكن من التعامل مع المستخدمين وحفظ البيانات في قاعدة البيانات للمستخدم. ملف server.php (الذي سيراقب تغير الملف ويرسل التحديث) <?php set_time_limit(0); // لايوجد اقصى مدة للطلب header("Content-Type: text/event-stream"); $viewd = 0; // عدد الرسائل التي عرضت لمنع إرسال الرسالة اكثر من مرة $lastFileSize = 0; // حجم الملف عندما يتغير فان هناك رسالة ارسلت while(true){ if(filesize("./ChatData.json") >= $lastFileSize){// التحديث فقط عند تغير حجم الملف $messages = json_decode("[".file_get_contents("./ChatData.json")."]"); // قراءة الرسائل for($i=$viewd;$i<=sizeof($messages)-1;$i++){ // حلقة تكرار من أخر رسالة مُرسلة echo "data: ".json_encode($messages[$i]).PHP_EOL; echo PHP_EOL; } $viewd = sizeof($messages); // تحديث عدد الرسائل المرسلة $lastFileSize = filesize("./ChatData.json"); // تحديث مُتغير أخر حجم للملف } ob_flush(); flush(); sleep(1); } ?>ثم في واجهة المستخدم شفرة javascript لجلب التحديثات: sse = new EventSource("server.php"); // انشاء الاتصال sse.onmessage = function(ms){ var data = JSON.parse(ms.data); // قراءة بيانات json var message = document.createElement("div"); // عنصر الرسائل message.setAttribute("class","message"); // اضافة كلاسس message var author = document.createElement("div"); // عنصر مُرسل الرسائل author.setAttribute("class","author"); // اضافة كلاسس author author.style.backgroundColor = data.author; // تغير لون الخلفية لمعرف المستخدم message.appendChild(author); // اضافة عنصر مُعرف مُعرف المستخدم الى عنصر الرسالة var content = document.createElement("p"); // محتوى الرسالة content.setAttribute("class","content"); content.innerHTML = data.content;// محتوى الرسالة message.appendChild(content); messages = document.querySelector(".messages"); messages.appendChild(message);// اضافة عنصر الرسالة الى حافظة الرسائل messages.scrollTop = messages.scrollHeight; // انزال الاسكرول الى الاعلى } ليعمل على انترنت اكسبلور يجب تضمين ملف javscript هذا في الـ header: <script src="https://rawgithub.com/remy/polyfills/master/EventSource.js"></script> يجب ان يكون العمل مُطابق لهذا: إن لم يعمل معك بشكل صحيح يُمكنك تحميل ملفات الأمثلة وقراءتها حتى تتمكن من معرفة كيف يعمل هذا المثال . الخاتمةيُمكنك رؤية المزيد من المصادر لمعرفة المزيد حول SSE: eventsource من طرف W3C.Server Sent Events من طرف مدونة موزيلا للمبرمجين.1 نقطة
-
على الرغم من التضاد اللغوي الظاهر بين جزئيّ عبارة "الأتمتة اليدويّة"، إلا أنه مكمن السر فيها، وهي من الحيل الصغيرة المفضّلة لديّ شخصيًا، بل إن بعضًا من أذكى الشركات الناشئة التي أعرفها تعتمد هذا الأسلوب في العمل بشكل مستمرّ. في سياقنا هذا، يمكن تعريف الأتمتة اليدوية بأنها عملية تبدو من زاوية المستخدم مؤتمتة، لكنها ليست كذلك من زاوية عملك كرائد أعمال. دعونا نوضّح المقصود بمثالين اثنين: أرادت إحدى الشركات التي أعمل معها إطلاق خدمة مميزة، وكانوا متأكدين من استعداد الكثير من الزبائن للدفع لقاء هذه الخدمة؛ إلا أنه ثمة ما يعيق ذلك، وهو عدم وجود بنية تحتية مبرمجة للدفع في موقعهم، ورغم كون نظام الدفع على قائمة الأولويات إلا أن الحصول عليه سيستغرق أربعة أشهر، في ضوء المهام الأخرى التي يجب عليهم القيام بها. لم يكن الخوف من خسارة الإيرادات فحسب؛ وإنما من خسارة فرص تسجيل زبائن راغبين بالخدمة والعائدات الشهرية الناتجة عنهم أيضًا. تحايلت الشركة على هذه المشكلة عن طريق بناء موقع ويب آمن وسريع، يمكّن الزبون من إملاء معلومات بطاقة الائتمان الخاصة به لترسل إلى قاعدة بيانات الشركة، حيث يبدو له كل شيء مؤتمتًا. في الحقيقة، فإن موظفي الشركة يُدخلون هذه البيانات لكل مستخدم مرة واحدة شهريًا باستخدام جهاز متصل بالإنترنت، ويرسلون وصل استلام إلكتروني مكتوب يدويًا، لكنه يبدو للمستخدم أوتوماتيكيًّا. تمّت برمجة عمل الموقع بعد خمسة أشهر -لا تأتي البرمجيات على الموعد دائمًا-، والآن ورغم أن العملية صارت مؤتمتة بالكامل إلا أن الزبائن لم يشعروا بالفارق. المثال الثاني من شركة أعمل معها حاليًا، إذ أرادوا إطلاق ميزة جديدة لتعديل مقاطع الفيديو، ولم يكن لديهم الشيفرة البرمجية المعقدة اللازمة لمعالجة هذه المقاطع، لكن وبنفس الوقت لم يكن ثمة الكثير من المستخدمين المهتمين بإطلاق هذه الخاصيّة بعد، والنقطة الأهم هي أن الشركة رغبت بتجريب الميزة للتحقق منها والحصول على تغذية راجعة من العملاء. مجددًا، عمدوا إلى حيلة الأتمتة اليدوية، فتعديل مقاطع الفيديو كان يدويًا على سطح المكتب، ليرفعوا بعدها النتيجة إلى قاعدة البيانات بشكل يدويّ أيضًا، ويرسل النظام النتائج "عندما تجهز". تبدو العملية مؤتمتة كلّيًا من جهة المستخدم، لكنها في الحقيقة مؤتمتة بالنسبة له فحسب، مع مرور الوقت بُرمجت هذه الميزة الصغيرة لتغدو أسرع بشكل نسبي. من مزايا الأتمتة اليدوية بالإضافة إلى ما ذُكر في الأمثلة، عدم احتوائها الجانب المزعج الموجود في العمل اليدوي، إذ تميل الأتمتة اليدوية لتكون أسرع في هذا المضمار. قد تكون التقنية ضعيفة في بعض الجوانب، إلا أن أكثر الشركات الناشئة نشاطًا لا تدع ذلك يعيق التحقق من فرضياتها، وبالنسبة لهذه الشركات فإن الأتمتة اليدوية موجودة دائمًا في صندوق الأدوات. تُرجم وبتصرّف عن مقال Manual automation لكاتبه David Cohen. حقوق الصورة البارزة: Free Vectors by www.Vecteezy.com.1 نقطة
-
AngularJS هي إطار عمل لتطبيقات الويب من طرف المستخدم يقوم بتفسير نصوص HTML مرة ثانية، ولو كنت خبيرا في تطوير الويب فمن الطبيعي أن تحاول مقارنة AngularJS مع منصات ومكتبات JavaScript التي تألفها مثل jQuery ،Knockout ،Backbone ،Ember وربّما مع React أيضا، وربما حاولت بناءً على معارفك السابقة ببرمجة واجهة المستخدم الرسومية GUI أن تربط AngularJS بـMVC أو MVVM، إلّا أنّ هذه المقارنات ستجعل معرفتك بـAngularJS أكثر ضبابية، لذا سأطلب منك في هذا الفصل فقط أن تتوقف عن النظر إلى AngularJS على أنها إطار عمل للغة JavaScript، كما أرجو منك أن تتخلّى في البداية عن رغبتك في فهم آلية عمل Angular وأن تحاول أخذها كما هي دون تفاصيل، فلتعتبرها مجموعة قوية من التطويرات لـHTML. سنبدأ دروسنا مع البنى الثّلاث الأساسيّة في AngularJS : العبارات expressions، التّوجيهات directives والمجالات scopes ولكننا سنبدأ قبل ذلك بالتعرف على كيفية تشغيل Angular في صفحة ويب. التثبيتيمكنك جلب Angular من الموقع الرسمي ثم تحميلها إلى صفحتك عن طريق المكاتب المستضافة عند Google (كـCDN) وهي طريقة ملائمة وتعمل جيدا، وقد قمنا بتشغيل شيفرات Angular عن طريق إضافة الاستدعاء التّالي في رأس ملف HTML: index.html <script src="//ajax.googleapis.com/ajax/libs/angularjs/1.4.2/angular.js"></script>والآن بإمكاننا البدء معًا. بعد تضمينك لملف المكتبة في رأس الصفحة ستكون الخطوة الأولى تحديد الجزء الذي ستعالجه Angular داخل مستند HTML، تذكر دومًا أن Angular موجّهة نحو HTML أكثر من توجهها نحو JavaScript، فمبدؤها العام هو: بدلا من كتابة شيفرة JavaScript ثم تنفيذها، نقوم بكتابة خصائص HTML غير معياريّة تفهمها Angular وتقوم بمعالجتها. وهنا سنتعرّف على الخاصّية الأولى ng-app التي يمكن إضافتها إلى أي عنصر من عناصر مستند HTML، وقد اخترنا وضعها كخاصية للعنصر body في مثالنا هذا، فعند وضعها في body أو في html ستقوم Angular بمعالجة المستند كاملًا بحثًا عن تعليماتها لتقوم بتنفيذها، وبالطّبع يمكنك تحديد مجال أضيق كفقرة أو عنوان فقط، إن أردت أن تستعمل بيئة عمل أخرى إلى جانب Angular أو تحميل عدّة تطبيقات لـAngular في نفس المستند. إذًا لنكتب في المستند الذي نعمل عليه الشيفرة التالية: index.html <html> <head> <script src="http://ajax.googleapis.com/ajax/libs/angularjs/1.4.2/angular.js"></script> </head> <body ng-app> <!-- كل الأمثلة توضع هنا --> </body> </html> بهذه الخاصية السحرية سنتمكن من جعل Angular تعالج تعليماتها الموجودة داخل الصفحة، والآن لنتعرف على إمكانيات هذه المكتبة وما الذي يمكنها فعله. العبارات Expressionsتحذير: إذا كنت تتبنّى فكرة إخفاء شفرات جافا سكريبت فالمثال التالي سيثير حفيظتك حول Angular فهي تعتمد على كتابة عبارات شبيهة بعبارات JavaScript داخل نصوص HTML. تشمل عبارات Angular أي عبارة بسيطة وصحيحة في JavaScript إلّا أنّها لا تسمح بتعليمات التّحكم بسير البرنامج مثل الحلقات وغيرها، وأرجو منك تأجيل أحكامك المسبقة بينما نستكشف الأمور المسموحة (والتي يمكن ألا تكون مستحسنة) في Angular بطرق التّجريب التّقليدية. لنبدأ بجمع عددين إلى بعضهما: <p>The number {{11 + 12}}.</p>الناتج The number 23.هيا انطلق، قم بتغيير 12+11 في المثال السابق إلى أي عبارة رياضيّة أخرى، جرب إن كان بإمكانك إيجاد شيء لا يمكن لـAngular معالجته (عندما تفشل Angular في معالجة عبارة ما، فإنّها تعرض السلسلة الأصلية دون تغيير، أو لا تعرض شيئا في بعض الحالات الأخرى). الأقواس المتعرجة المزدوجة هي التي تحدد قالب Angular، وقد تكون قد شاهدتها من قبل لو تعاملت مع Mustache أو مع Handlebars، أحيانًا يمكنك التّفكير في Angular بانها مكتبة قوالب شديدة التعقيد، فهي تتعامل مع كل شيءٍ داخل العنصر الذي قمت بإضافة الخاصية ng-app إليه على أنه قالب وتقوم بترجمته عند تحميل الصّفحة، ثم تقوم بإعادة عملية الإخراج كلما حدث تغيير على البيانات (لا تقلق إن لم يكن مفهوم القوالب مألوفًا لك فسوف نتطرّق إلى مبادئه لاحقًا). ماذا عن اختبار المساواة لقيمتين؟ بالطّبع يمكننا القيام بهذا أيضًا. <p>Are strings and numbers equal? {{'2' == 2}}</p>الناتج Are strings and numbers equal? trueالنّتيجة موافقةٌ لما هي عليه في JavaScript، إذا كنت متفاجئًا بناتج عمليّة المقارنة السّابقة فقم بمراجعةٍ سريعة لعملية المقارنة ثم قم بتغيير == إلى === في المثال السّابق، لترى اختلاف النّتيجة. فيما يلي مثال لدمج سلسلتين نصيتين، ويوضح قدرتنا على الوصول إلى توابع مكتبة JavaScript المعيارية مثل توابع السلاسل النصية كالتابع toUpperCase. <code><p>{{"Angular" + "js".toUpperCase()}}</p></code>الناتج AngularJSهل تشعر الآن بأنّه بإمكانك القيام بأي شيء داخل عبارات Angular؟ لا تكن متسرّعًا يا شريك، وانظر إلى المثال التّالي: <!-- كود خاطئ! هذه الدالة ليست مسموح بها داخل عبارة --> <p>{{alert("Hello world")}}</p>لا يمكنك استخدام التّابع alert كما لا يمكنك الوصول إلى معظم الكائنات العامة مثل Math، Number و Date وهلم جرا. حاول استبدال ("alert("Hello world في المثال السّابق بـ ("parseInt("1 أو ()Date.now أو Number.Nan أو ()Math.random، إن لم تنتج أي مخرجات فهذا يعني أن Angular قد رفضت معالجة العبارة. لا بد من أن التساهل في مسألة دمج الشيفرة التنفيذية مع نصوص HTML قد أتعبك، وزاد عليه محدوديّة ما يمكنك القيام به داخل عبارات Angular، ولكن لا تتوقّف هنا فهناك الكثير بانتظارك، لنحاول الوصول إلى حدود إمكانيات العبارات في Angular، هل تظن بأنها تسمج بإسناد المتغيرات؟ <p>{{a = 1; a + a}}</p>الناتج 2إنها تعمل، ولكن حاول إضافة الكلمة المفتاحية var إلى اسم المتغير، فلن تقوم Angular بمعالجة العبارة وستصدر خطأ، فعندما ترى العبارة كما هي مع الأقواس المتعرجة فهذا يعني حدوث خطأ في الترجمة، لا تشعر بالاستياء، فتخريب الأشياء يكون أحيانًا وسيلة ممتازة للتعلم. هكذا تكون التجربة، لا أدري إن كان بالإمكان تعريف متغيّر في مجموعة من الأقواس المتعرّجة ثمّ استخدامه داخل مجموعة أخرى، لم لا نجرّب ذلك؟ <p>{{a = 1}} remains {{a}}</p>الناتج 1 remains 1إنّها تعمل أيضًا، ولكن ماذا لو نقلنا تهيئة المتغيّر إلى العبارة الثّانية؟ هيّا جرّبها، هل عملت؟ هل يمكنك معرفة السبب المحتمل وراء ذلك؟ حسنًا، العبارات تدعم عمليّة إسناد المتغيّرات، ما رأيك بتجربة معامل الشّرط الثلاثي؟ <p>There {{count = 1; (count == 1 ? "is " : "are ") + count}} of them.</p>الناتج There is 1 of them.من حسن حظّنا أنها تعمل أيضًا، فهذه العمليّة الثلاثية توفّر لنا تركيبًا مختصرا عمليًا داخل القوالب، والآن ماذا عن عملية الزّيادة "++"، هل يمكننا استخدامها؟ <p>{{a = 1; ++a}}</p>الناتج 1من الواضح أنّها لم تعمل، فهل هذا يعني بأنّ حلقة for غير موجودة في Angular، لم لا نستغني عن الكلمة var ونستبدل عملية الزّيادة "++" بجمع عادي. <p>{{for (i = 0; i < 10; i = i + 1) {i}}}</p>الناتج {{for (i = 0; i < 10; i = i + 1) {i}}}لم يتمّ تشغيل شيفرة الحلقة، كما أنّها سبّبت إصدار خطأ نحوي يمكن رؤيته من نافذة المتصفح console، رغم أنّ الحلقة ليس فيها أي خطأ ويمكن نسخها ولصقها في النافذة ليتم تشغيلها وستصل إلى العدد 9، جرّبها لتتأكّد بنفسك. إذًا لقد وصلنا إلى بعض الحدود، عبارات Angular ليست JavaScript، فـلغة العبارات لا تدعم الشروط، الحلقات ولا رمي الأخطاء واستلامها. يبدو أنّنا وصلنا إلى حدود العبارات، بالنّسبة لي فأنا أتقبّل وجود بعض شيفرات JavaScript داخل نص HTML إن كانت شيفرات مختصرة ومتعلقة بالعرض، لذا فأنا أقدّر الطبيعة المتساهلة لـAngular مع هذا الأمر، ولكن هذا لا يعني أنّني أشجع على كتابة شيفرات JavaScript أكبر من ذلك، فذلك سيتحوّل سريعًا إلى خربشات مربكة وغير مقروءة. من الجيّد أنّ العبارات لا تلعب إلّا دورًا بسيطًا في Angular، ويجب ألّا يكون هناك داع لكتابة الكثير من الشيفرات داخل العبارة الواحدة، فالمفتاح الحقيقي للإنتاجيّة المذهلة لـAngular هو التوجيه directive. التوجيهات Directivesالتّوجيهات هي روح Angular وقلبها النّابض، وأنصحك بأن تنظر إليها على أنها HTML معدلة، ففي كثير من الأحيان ترى أنها تشابه إلى حد كبير خصائص HTML التي يمكن استخدامها مع عناصر عاديّة ومألوفة. تبدأ التوجيهات المدمجة مع Angular عادة بالسابقة ng- التي تدل على الحرفين الثاني والثالث من كلمة A**ng**ular، كما أنّك ستجد عددًا هائلًا من التّوجيهات التي برمجها طرف ثالث متاحة للاستخدام. أول ما عليك التفكير به عندما تواجه شيفرة JavaScript مطولة داخل أحد التعبيرات في Angular هو أنه لا بد من وجود توجيه يقوم بذلك. لقد قمنا باستخدام أحد التّوجيهات مسبقًا بالفعل، هل تذكر التّوجيه الذي يجعل Angular تعالج محتويات العنصر body، إنه التوجيه ng-app، ففي هذه الحالة استخدمنا التوجيه دون تمرير أي وسطاء إليه، ولتمرير الوسطاء إلى التوجيهات ما عليك سوى استخدام "=" كما تقوم بإسناد القيم إلى خصائص HTML تمامًا. يمكنك على سبيل المثال تمرير اسم التّطبيق كوسيط "ng-app="myApp. (اسم التطبيق يشكل فعليا اسم وحدة وهي جزء هام من بنية Angular، وسنقوم بتغطيته في فصل الوحدات) ng-bindتقبل بعض التوجيهات تمرير سلاسل نصية تحوي عبارات لتقوم بتفيذها، (يمكنك التعرف على محددات كل توجيه من التوجيهات بزيارة توثيق API الخاصّبه)، فمثلًا يقوم التوجيه ng-bind بمعالجة العبارات وإخراجها، تمامًا كالأقواس المتعرّجة المزدوجة التي رأيناها في الفقرة السابقة، والمثال التالي يوضح استخدامه: <p>The number <span ng-bind="11 + 12"></span>.</p>الناتج The number 23.قد تجد أنّ المثال السابق مطابق لأول مثال تطرّقنا إليه، إلا أنّ هناك فرقًا هاما هو أن ng-bind تسبب إخفاء العبارة ريثما تقوم Angular بالترجمة وعملية الإخراج، ولذلك فهي الطريقة الأكثر تفضيلًا لاستخدام العبارات في Angular، فأثناء فتح الصّفحة وترجمتها ثمّ إخراجها لن تظهر العبارات والأقواس المتعرّجة، ولك أن تتخيّل شكل صفحة مليئةٍ بالعبارات قبل أن تنتهي عمليّة الإخراج خصوصًا إن كان هناك تأخير كبير بسبب كِبَرِ حجم الصّفحة وكثرة عباراتها. ربما ترغب في إخفاء كامل المحتوى أو جزءًا كبيرًا منه ريثما تنتهي عمليّة الإخراج بشكل كامل، وهذا ما تتيحه لك ng-cloak، لا بد من وجود توجيه يقوم بذلك. ng-initهل تذكر قيامنا بتهيئة المتغيّر في العبارة لنرى هل يعمل أم لا، حسنًا لا بدّ أن تحزر الآن، هناك توجيهٌ للقيام بهذا أيضًا، فالتّوجيه ng-init يسمح لك بتهيئة المتغيّرات لاستخدامها في أي مكان داخل العنصر الذي طبقت هذا التوجيه عليه. <div ng-init="sum = 3 + 2"> <p> {{sum + 1}} is more than <span ng-bind='sum - 1'></span> </p> </div>الناتج 6 is more than 4كما يمكنك استخدام الفاصلة المنقوطة لتعريف عدّة متغيّرات داخل توجيه ng-init كما يوضّح المثال التّالي: <div ng-init="count = 7; units = 'days'; collection = 'week'"> <p> There are {{count}} {{units}} in a {{collection}}. </p> </div>الناتج There are 7 days in a week.وقد تجد عند مرحلة ما أنه من الضروري تنظيم متغيّراتك داخل كائنات. <div ng-init="time = {count: 12, units: 'months', collection: 'year'}"> <p> There are {{time.count}} {{time.units}} in a {{time.collection}}. </p> </div>الناتج There are 12 months in a year.والمصفوفات مفيدة أيضًا. <div ng-init="months = ['January','February','March','April']"> <p> {{months[3]}} follows {{months[2]}} in {{months}}. </p> </div>الناتج April follows March in ["January","February","March","April"].انتبه، فلا مجال للخطأ في أسماء العناصر داخل الكائن، فـAngular لا تساعدك في تحديد هذا الخطأ وكلّ ما تقوم به هو عدم ترجمة العبارة وتجاهلها، وكذلك الحال في أخطاءِ الوصول إلى عناصر كائنٍ غير موجود أصلًا والوصول إلى عناصر خارج حدود المصفوفة. <div ng-init="paragraph = {sentence: {words: ['first','second','third']}}"> <p> "{{typo.sentence.words[0]}}", "{{paragraph.typo.words[1]}}", "{{paragraph.sentence.typo[2]}}", "{{paragraph.sentence.words[3]}}". </p> </div>الناتج "", "", "", "".كنت أتمنّى لو أن Angular تحتوي على عملية اختبار الوجود كالموجودة في CoffeeScript لجعل التّساهل مع هذه الأخطاء خيارًا وليس القاعدة. والآن بعد أن رأينا سماحيّات Angular هل تتوقع بأنها تسمح بتعريف التوابع داخل ng-init؟ ما الذي تتوقThere are months in a year.عه؟ <div ng-init="count = function() { return 12; }"> <p> There are {{count()}} months in a year. </p> </div>الناتج There are months in a year.لا، لا تسمح Angular بعبارات تعريف التوابع، كما أنها تقوم برمي خطأ parse:syntax$ أثناء معالجة الوسيط الممرّر للتوجيه ng-init، ويمكنك رؤيته في نافذة المتصفح console، فالمتحكم هو المكان الصحيح لتعريف التوابع لاستخدامها في عبارات Angular، وسنتعرف عليها في فصل المتحكمات وهي في الحقيقة المكان المناسب لتحضير جميع بيانات التطبيق للعرض، أمّا التّوجيه ng-init فوظيفته الأساسية هي تغيير أسماء المتغيرات لسبب سنراه لاحقًا في فصل المجموعات. ng-non-bindableيمكن استخدام التوجيه ng-non-bindable لمنع Angular من معالجة جزء من المستند، كما يوضح المثال التالي: <p ng-non-bindable> {{2 * 2}} is the same as <span ng-bind='2 + 2'>?</span> </p>الناتج {{2 * 2}} is the same as ?جرب إزالة التوجيه السابق لترى ما سيحدث. ng-showحان الوقت للتّعرف على أمور أكبر من مجرّد معالجة وإخراج ناتج عبارة، سؤالٌ للمبتدئين: كيف يمكننا إظهار وإخفاء عنصر HTML حسب شرطٍ ما؟ احتجت مرة لإخفاء نموذج استمارةٍ بعد أن يقوم المستخدم بملئها بنجاح، فقمت بإضافة استدعاء للتابع jQuery.hide داخل متحكّم قمت بإنشائه في Angular، لقد عمل بشكل صحيح رغم أن تلك الطريقة ليست هي الأفضل للقيام بذلك، ولكن الرغبة في إنهاء المشروع سريعًا دفعتني لتجنب البحث عن التّوجيه الّذي يقوم بذلك في Angular، وبالفعل وجدت توجيهين للقيام بذلك لا واحدًا فقط، ng-hide وng-show وسيبيّن المثال التالي استخدامهما معًا: <p ng-init="authorized = true"> The secret code is <span ng-show="authorized">0123</span> <span ng-hide="authorized">not for you to see</span> </p>الناتج The secret code is 0123جرّب تغيير true إلى false في المثال السابق لترى ما سيحدث، إنّ Angular تراقب التحديثات الّتي تطرأ على المتغيرات طوال الوقت، ولذلك فسيؤدّي تغيير المتغير authorized في أي مكان إلى تغيير نتيجة المثال السابق في العرض. أرى أنه يمكننا التعمق الآن في الحديث عن المتغيرات لنعرف ماهيّتها الحقيقيّة. المجالات Scopesتُعدّ المجالات مصدر البيانات الوحيد داخل تطبيقك، والفكرة من ورائها هي أنّه مهما كان عدد الأماكن الّتي تسخدم فيها المتغيّر في طبقة العرض، يجب عليك الالتزام بموضع واحدٍ لتغيير قيمته ويجب أن ينتشر هذا التغيير تلقائيًا إلى أماكن استخدام هذا المتغيّر في العرض. بما أنّ عملية الإخراج وإعادة الإخراج تحتاج بنيةً تحتيّة، فأكثر ما ستلاحظه في كائنات JavaScript الّتي تضعها في مجالات Angular هو كم هي مألوفة واعتياديّة بالنسبة لك. قد تكون ملمًّا بمفهوم كائنات نموذج المجال القديمة البسيطة، والذي أصله كائنات Java القديمة البسيطة أو ما يُعرف اختصارًا لـPOJO، فعندما قام Martin Fowler بشرح مفهوم POJO للمرّة الأولى، كان يعني الكائنات الأساسيّة الاعتياديّة التي يقدّمها قلب اللغة في وقت التشغيل runtime، على عكس كائنات نموذج المجال domain model المعقّدة الّتي ترث قدرات خاصّة من فئة متفوّقة superclass في إطار العمل. لقد تمّ توسيع هذا المصطلح ليشمل الكائنات التي تبدو بأنّها بسيطة إلّا أنّ إطار العمل يحسّنها بإضافة قدرات خاصّة بشكل خفي في وقت التشغيل بشكل مستمر عادة. الكائنات المرتبطة بمجالات Angular هي POJOs خاصة بـJavaScript، ويبدو أن Angular ستصبح حقا إطار عمل جافا سكربت البسيطة القديمة عندما سينتشر استخدام الميزة الجديدة Object.observe بين أوساط المبرمجين، وذلك لأنّها تقوم بعمليات معقدة للتّعرف على التّغييرات أثناء وقت التشغيل لتسمح بانتشار تأثير هذه التّغييرات. لقد مررنا مسبقاً على العديد من خصائص المجالات scope properties في هذا الفصل، هل تذكر المتغيّر الّذي قمنا بتهيئته داخل العبارات واستخدمنا ng-init في المثال أعلاه، كلّ هذه كانت من خصائص المجالات، هل تذكر محاولة إضافة الكلمة المفتاحية var إلى إحدى العبارات؟ إنّ استخدامها ممنوعٌ لأنّ ما كنت أقول بأنه متغيّرٌ لم يكن كذلك في الحقيقة(وأعتذر لأنّني كذبت بشأنه) فهو في الحقيقة أحد الخصائص في كائن المجال، يتمّ إنشاؤه تلقائياً خلف الكواليس وسنغطّي في الدّرس القادم المجالات بتفاصيل أعمق، وسنكتفي هنا ببعض الأمثلة الّتي تبين كيفيّة استخدام خصائص المجالات. الربط ثنائي الاتجاهكل الأمثلة السّابقة كانت تستخدم ربطًا أحادي الاتجاه، حيث يتم تحديث بيانات المجال باستمرار في العرض view، وسيزداد الأمر إثارةً عندما نستخدم HTML للتّحكم بهذه البيانات وتغييرها، ومعًا ستشكّل هاتان الطّريقتان في تغيير البيانات الربط ثنائيّ الاتّجاه كمثال مبدئي أوّل، سنستخدم التّوجيه ng-click للتعديل على خاصّية بوليانية boolean. <p ng-init="authorized = true"> The secret code is <span ng-show="authorized">0123</span> <span ng-hide="authorized">not for you to see</span> <br> <input type="button" value="toggle" ng-click="authorized = !authorized"> </p> يمكن أن يكون الوسيط الممرّر للتوجيه ng-click أي عبارة، ورغم أنّ هذا التّوجيه غير محدود بالعمل ضمن خصائص المجالات، إلا أن الشّيفرة الّتي كتبناها لقلب القيمة البوليانية تعمل بشكل صحيح لأنها بسيطةٌ جدًّا، ولكن كيف يمكننا ربط أدوات الدّخل الأخرى والتّعامل مع أنواع متغيّرات أكثر تعقيدًا؟ ng-modelيبدو أنّ جميع شروحات Angular لربط البيانات تسخدم مثالًا لربط دخلٍ نصّيّ بخاصّيةٍ من نوع سلسلةٍ نصّيّة، وها قد حان دورنا لكتابة هذا المثال. <input type="text" ng-model="title"> is bound to "<strong ng-bind="title"></strong>". Type something in the box!هذا المثال هو الطّريقة الأمثل لتوضيح مسألة الربط ثنائيّ الاتجاه، فعندما نضيف التّوجيه ng-model إلى عنصر input الخاصّ بـHTML، فإنّ Angular تقوم بتغليف تحكّم HTML به عن طريق توجيه input الخاصّ بها. ما الذي يمكننا القيام به أكثر من هذا؟ بإمكاننا دومًا استخدام ng-init لتهيئة قيمة ابتدائية للخاصية. <input type="text" ng-init="title = 'Angular'" ng-model="title"> is bound to "<strong ng-bind="title"></strong>". Change it!لنجرّب الآن بعض أدوات الإدخال الأخرى، لنبدأ بـcheckbox. <input type='checkbox' ng-init='optIn = true' ng-model='optIn'> is bound to <strong ng-bind="optIn"></strong>. Change it!القيمة المرتبطة بصندوق checkbox يمكن أن تكون سلسلةً نصّيّةً بدلًا من كونها قيمة بوليانيّة، وذلك بتأهيل قيمة كلٍ من التّوجيهين ng-true-value وng-false-value. <input type='checkbox' ng-init='feeling = "love it"' ng-model='feeling' ng-true-value='"love it"' ng-false-value='"hate it"'> is bound to "<strong ng-bind="feeling"></strong>". Change it!هل يمكنك توقّع وظيفة التّوجيه select في Angular؟ لاحظ أنّ Angular تتجاهل تمامًا وجود الخاصّية selected في الخيارات المقدّمة، وحتّى لو قمت بإزالة التّوجيه ng-init فستبقى بلا تأثير. <select ng-init='answer = "maybe"' ng-model='answer'> <option value='yes' selected>Yes</option> <option value='no'>No</option> <option value='maybe'>Maybe</option> </select> is bound to "<strong ng-bind="answer"></strong>". Change it!يبدو أنّ المثال السّابق يناسبه وجود radio buttons أكثر من قائمة الخيارات، هيّا نغيّره إذًا. <div ng-init='answer = "maybe"'> <input type='radio' ng-model='answer' value='yes'> Yes <input type='radio' ng-model='answer' value='no'> No <input type='radio' ng-model='answer' value='maybe'> Maybe is bound to "<strong ng-bind="answer"></strong>". Change it! </div>لديك الآن بعض خبرات الواقع العمليّ في التّعامل مع بيانات المجالات باستخدام توجيهات Angular، ولا يزال هناك الكثير من التّوجيهات المدمجة في Angular، وسنتعرف على العديد منها في الفصول القادمة. خلاصةلقد طلبت منك في مطلع هذا الفصل ألا تنظر إلى Angular على أنها إطار عمل لـJavaScript، بل كامتداد لـHTML، فكما أخبَرَنا Miško Hevery مخترع Angular في هذه المقابلة الرائعة فإن الهدف الأساسي من Angular هو أن تكون طريقة لزيادة إنتاجية مطوري الـ front-end لتحسين صفحات الويب، وقد صارت لاحقًا إطار عمل لـJavaScript. لقد تم الانطلاق من فكرة كون نمط البرمجة التصريحية هو أفضل الخيارات لتسريع عملية تطوير واجهات المستخدم الرسومية GUI، وقد اختار مطوروها ألا تكون لغة محصورة في مجال محدد مثل ما كانت MXML وXUL بل أرادوا جعلها تعتمد على تشابهها الكبير مع نصوص HTML. لقد رأينا بما يكفي أن Angular لا تستخدم دون JavaScript معدلة، كما أن التطبيقات في الواقع العملي في Angular تستخدم دومًا المتحكمات والخدمات والمسرات كما تدعم الوحدات وحقن التابعية إضافة إلى اعتمادها على البنية التحتية لـAjax، وسنغطي في هذه السلسلة جميع هذه الأمور، وعلى أي حال فإن وعد الإنتاجية الذي تقدمه Angular يمكن تحقيقه في فضاء تصريحي، مع درجة من الاعتماد على لا بد من وجود توجيه يقوم بذلك، كما أنّ كتابة توجيهات مخصصة لملء الفجوات هو الأمر الأكثر تحدّيًا في Angular، وهذا ما سيحاول الفصل الأخير إيصاله ليستقرّ في ذهن القارئ. والآن بعد أن استوعبت أن الهدف الأسمى لـAngular هو إيجاد امتدادات لـHTML لزيادة الإنتاجيّة وليس كتابة شيفرات JavaScript داخل إطار عمل، فأنت الآن جاهز لتبحر في تفاصيلها مع الفصول القادمة. ترجمة وبتصرّف للفصل الثاني من كتاب: Angular Basics لصاحبه: Chris Smith.1 نقطة
-
هل تفكر في بيع موقعك الإلكتروني أو مشروعك التجاري على الإنترنت لتحصل على مبلغ جيّد يمكنك استثماره في مشروع تجاري جديد، أو ربّما ادخار المال لإنفاقه عندما تتقاعد عن العمل، أو لتنفق المال في رحلة الأحلام التي ستتجول فيها حول العالم؟ قد يبدو الأمر سهلًا وبسيطًا، ولكن الواقع عكس ذلك تمامًا، فهناك العديد الأمور التي يجهلها المبتدئون في هذا المجال والتي تكون سببًا في: الفشل في إتمام الصفقة في اللحظات الأخيرة.الحصول على مبلغ أقل بكثير مما يستحقه المشروع التجاري.عدم القدرة على إيجاد مشترٍ على الإطلاق.فيما يلي جملة من الأخطاء الأكثر شيوعًا في هذا المجال، إضافة إلى بعض النصائح التي يمكنك من خلالها تهيئة نفسك ومشروعك التجاري لـ "مرحلة الخروج" Exit Phase مع ضمان نجاح الصفقة وحصول مشروعك على الثمن الذي يستحقّه. 1- هيئ نفسك لمرحلة الخروج في وقت مبكر جداإنّ أغلب المشاكل التي تؤدي إلى جعل عملية بيع الموقع أمرًا صعبًا أو حصوله على ثمن زهيد ناجمة عن عدم التهيُّؤ الكافي لمرحلة الخروج. ونتيجة لذلك يجب عليك أن تبدأ بالتهيؤ لهذه المرحلة في وقت مبكّر – يفضّل أن تبدأ مقدّمًا بـ 6 أشهر على الأقل – ليتوفّر لك الوقت الكافي لإكمال التحضيرات اللازمة. يساهم التهيؤ الجيّد في مضاعفة صافي الأرباح الذي ستحصل عليه، لذا لا تستهن بهذا الأمر على الإطلاق. 2- افصل شخصيتك عن الموقع أو المشروع التجاريبصرف النظر عن طبيعة الشخص الذي سيشتري موقعك فإن ارتباط موقعك بشخصيتك بشكل كبير يعدّ مشكلة يجب عليك معالجتها. لذا إن كانت محتويات الموقع تدور حول شخصيتك فقد حان الوقت لتغيير ذلك. أزل صورك الشخصية من صفحات الموقع، وافتتح مقاطع الفيديو بعبارة: "مرحبًا، أنا زيد عمرو من موقع ABCD.com" عوضًا عن "مرحبًا، أنا زيد عمرو"، أنشئ كذلك بريدًا إلكترونيًا خاصًّا بالعلاقات التي تخصّ موقعك الإلكتروني، لئلا تختلط رسائل العمل مع الرسائل الشخصية. 3- احرص على التوثيق الدقيق والمفصل لعائدات الموقعإنّ عدم وجود التوثيق الدقيق والمفصّل بما فيه الكافية هو من أهم الأسباب التي تؤدي إلى فشل المشاريع التجارية عبر الإنترنت، إذ يؤدّي التوثيق دورًا مهمًّا في إثبات مقدار العائدات التي يدرّها الموقع، وهي بدورها من أهم العوامل التي تؤثر على قيمة الموقع، إذ لا قيمة للموقع دون توثيق دقيق لعائداته المالية. ونظرًا لذلك، يجب عليك توثيق كل صغيرة وكبيرة حتى لو كانت هناك فرصة ضئيلة جدًّا لبيع موقعك الإلكتروني، إذ سيساعدك هذا التوثيق بشكل كبير جدًّا في عملية بيع الموقع إضافة إلى تقديم رؤية مالية واضحة. 4- احرص على وجود إحصائيات جيدة لتعقب حركة الزواركما هو الحال في توثيق شؤون موقعك المالية، فإنّ عليك إثبات حركة الزوار وسلوكهم تجاه موقعك. يطالب أغلب المستثمرين / المُشترين في هذه الأيام بوجود أداة Google Analytics في أي موقع يرغبون في شرائه، وذلك لأنّها الأداة الأكثر شهرة في هذا المجال، إضافة إلى شهرتها بصعوبة التلاعب بالنتائج التي تقدّمها. احرص على تنصيب أداة Google Analytics في موقعك في مرحلة مبكرة، إذ ليس بمقدور هذه الأداة تعقّب حركة الزوار بأثر رجعي، ما يعني أنّ قرار تنصيبها قبل بيع موقعك بأشهر معدودات سيكون قرارًا متأخّرًا جدًّا. 5- لا تخلط بين الحسابات المصرفية الشخصية وحسابات المشاريع أو حسابات مشاريع مختلفةإيداع واردات الموقع في حساب مخصّص لذلك أمر ضروري للغاية، ويمكن لهذا الحساب أن يكون حسابًا مصرفيًّا، أو حسابًا في PayPal أو في حساب فرعي. وستجني فائدة ذلك في وقت لاحق؛ ذلك لأنّ منابع الواردات المتعددة والتي تصبّ في حساب واحد تجعل من تحديد مصادر هذه العائدات في وقت لاحق أمرًا صعبًا. بالإضافة إلى ذلك يجب أن يكون لديك حساب منفصل للنفقات، والتي تتضمن ما تنفقه على منصات الإعلانات مثل Google AdWords. 6- وثق جميع العلاقات في نشاطك التجاريتأكّد من توثيق جميع العلاقات الاستراتيجية في نشاطك التجاري وحاول تثبيتها بواسطة العقود إن أمكن ذلك. ربّما تكون هناك ثقة متبادلة بينك وبين شركائك، وقد تكون مسرورًا جدًّا في العمل معهم بالاستناد إلى اتفاقيات شفهية، لكنّ هذا لن يكون حال من سيرغب في شراء موقعك، وسيساهم هذا الأمر في التقليل من فرص نجاحك في بيع الموقع، أو التقليل من قيمته بشكل كبير. 7- استخدم حساب استضافة منفصلحاول دائمًا أن تستخدم حساب استضافة منفصل لكل موقع ترغب في بيعه مستقبلًا. لن يكلفك الأمر الكثير من المال، وستكون قادرًا على تسليم موقعك مع حساب الاستضافة بكل سهولة ويسر، متجنّبًا بذلك الكثير من الوقت والجهد الذي ستبذله لتحويل الموقع إلى المشتري دون القيام بهذه الخطوة. 8- افصل بين علاقات العمل والعلاقات الشخصيةيفضّل أن يكون هناك صندوق بريد إلكتروني خاصّ بكل مشروع تجاري تملكه أو تديره. فقد يطلب منك المشتري في كثير من الأحيان الوصول إلى بعض الرسائل القديمة المتعلقة بالعملاء والداعمين والشركاء، وسيسبب اختلاط هذه الرسائل مع الرسائل الشخصية أو رسائل المشاريع الأخرى الكثير من المشاكل التي تكون في غنى عنها. 9- اجعل توقعاتك واضحة ولا تصدق كل ما يقوله لك السماسرةحين تهيّئ موقعك للبيع يجب عليك أن تعرف قيمته الحقيقية، وتقييم الموقع أمر معقد ولا توجد قواعد مسلّم بها في هذا الشأن، ولكنّ يمكنك الاطلاع على بعض القوائم العامة التي تشتمل على الأسعار التي تباع بها المواقع الأخرى. ويمكنك الحصول على هذه القوائم من المواقع الإلكترونية الخاصة بالسماسرة، أو من المتاجر الإلكترونية العامة مثل Flippa و BizBuySell، ولكن تذكّر دائمًا أن ما ستحصل عليه من أسعار لا يطابق بالضرورة سعر البيع النهائي، إذ يتراوح الاختلاف بين السعرين من 10% (عند السماسرة ذوي السمعة الحسنة) إلى 50% (عند السماسرة الذين يبالغون في تقييم المواقع). قد يقدّم إليك الكثير من السماسرة تقييمًا مجّانيًا لموقعك، ولكن لا تثق بهذا التقييمات ثقة مطلقة، فغالبًا ما يميل السماسرة إلى المبالغة في تقييم موقعك ليحصلوا على توقيعك، وما إن ينال هؤلاء الحقوق الحصرية حتّى يخفّضوا ذلك التقييم، كما يخفّض بعض السماسرة ليعقد معك الصفقة بالسرعة الممكنة. أمّا السمسار ذو السمعة الحسنة فلا يبالغ في التقييم ولا يخفضّه، لذا يكون أفضل مصدر يمكنك الاعتماد عليه في هذا المجال. 10- ابحث عن سمسار جيدهناك العديد من المخادعين والدجّالين الذين يتصيّدون الفرص لتحقيق مآربهم، لذا توخّ الحذر الشديد في اختيار السمسار الذي ستتعامل معه، ولا تنخدع بأولئك الذين يوقّعون معك عقودًا حصريّة طويلة الأمد مقدّمين إليك وعودًا زائفة بأسعار خياليّة أو عمولة منخفضة. 11- لا تتجاهل مشروعك التجاري أثناء عملية البيعأعتقد أن أكبر الأخطاء التي يرتكبها من يرغب في بيع موقعه هو عرض ذلك الموقع للبيع ثمّ تجاهله وعدم الاعتناء به بصورة مستمرة. قد يبدو الأمر بديهيًّا، ولكنّي واجهت الكثير من هذه الحالات خلال السنوات الخمسة التي قضيتها في هذا المجال. يقيّم المستثمرون مشروعك التجاريّ بناء على أدائه الحالي والسابق، وليس على أدائه السابق فقط، ومن الضرورة بمكان إيلاء الرعاية اللازمة بمشروعك التجاري خلال المدّة التي يكون فيها معروضًا للبيع، ففي أغلب الأحيان يؤدّي انخفاض بسيط في الواردات إلى انخفاض كبير في سعر الموقع. ترجمة –وبتصرّف– للمقال 11Tips to Selling Your Website for Profit لصاحبه Bryan O'Neil.1 نقطة
-
لو كنت أبًا، أمًا، كاتبًا مستقلاً، أو لم تكن أي مما سبق، يمكن لهذه المقالة أن تغير حياتك. كثير منا يدخل في عالم العمل الحُرّ، مُمنّين أنفسنا بالحرية في العمل، وبحرية ترتيب الوقت وأن نقرر مع من نعمل، وأي المشاريع نختار، ليس هنالك من يتحكم في دخلنا، وفي ما نكسبه من مال في أعمالنا التجارية أو في حياتنا. تبدو الأمور جذابة بغض النظر عمن أنت، وهذه الأمور تصبح أكثر جاذبية خاصة عندما يكون لك عائلة وأطفال، أعني أنها تبدو فكرة عظيمة، فكرة البقاء في المنزل مع الأطفال، وتكون هناك لاستقبالهم عند العودة من المدرسة، وحتى إنجاز العمل المنزلي ما بين المشاريع، هذا هو بالضبط ما كنت اعتقد أنه يمكنني عندما ولدت ابنتي، إلا أن ذلك لم يحدث تمامًا كما كنت أتخيله، إليكم قصتي قصتيكنت أكتب وأدوّن لعدة سنوات بدافع المتعة في المقام الأول، وللحصول على بعض المال الإضافي، ولكن بعد أن ولدت ابنتي، كان من الواجب الحتمي أن أكون معها في المنزل، ولذلك قررت أن أترك العمل بالطريقة النظامية وأعمل من منزلي ككاتبة مستقلة. ولأتأكد أن نجاحي حتمي في هذا القرار خطوت بجد باتجاه التدريب الذاتي على أن أكون كاتبة مستقلة، حيث بدأت بمتابعة المختصين في هذا المجال، مثل السيدة ليندا - Linda Formichelli، كارول - Carol Tice، ورالف - Mridu Khullar Relph وغيرهم من الكُتاب المشاهير في المدونات لحاسبهم الخاص. كنت أراقبهن وهن يعملن ويكسبن، ولكن بدون كأنهن لا يبذلن جهداً كبيراً، وهذا من منبع إمكاناتهن الشخصية، ولكن التجربة علمتني، أن الفترات القصيرة في الصباح وفي الظهر وما قبل النوم، ليست كافية لتبني إمبراطوريتك الخاصة ككاتب مستقل. كنت أعمل طيلة أيام الأسبوع ومعظم الأمسيات لكي أنهي بعض الأعمال الكتابية التي طُلبت مني، كان بيتي في حالة من الفوضى يرثى لها، وكان الطعام مقتصرًا على الأكل الجاهز، وغير ذلك الكثير. وبعد ذلك كله وجدت صعوبة في إيجاد الوقت لعرض وبيع كتاباتي وللترويج لنفسي ككاتبة مستقلة، والأكثر سوء من ذلك كله، لم يكن لدي الوقت الكافي لزوجي وطفلتي. أصبحت بائسة، لم استطع تفهُم ما يجري حولي، فقد استطاعت معظم النساء من حولي أن يبنين لأنفسهن حياة عملية ناجحة ككاتبات مستقلات من بيوتهن، ولكنني لم أستطع فعل ذلك وبنفس الكفاءة. هنا راودتني فكرة التخلي عن هذا المشروع الذي بدأ وكأنه يقودني إلى لا شيء. هل في الحقيقة أنا كاتبة غير جيدة، كما كنت اعتقد؟هل أنني لم أرغب بالكتابة بكل كياني وجوارحي؟أم أن هناك شيء أكثر من ذلك لم أفقهه؟أيًا ما كانت الأسباب، كنت مصممة على عدم العودة للوظيفة الثابتة مرة أخرى. وبدا لي أنني بحاجة لمساعدة شخص خبير في هذا المجال، شخص مقتدر يقودني ويضعني على المسار الصحيح، لذلك وفي لحظة يأس بعثت برسالة إلكترونية لكارول أخبرها بما أواجهه من صعوبات، لأكون كاتبة مستقلة واعمل من المنزل، وأعرض عليها مقابل مادي لقاء هذه المهمة. ولكن بدلاً من أن تقبل مساعدتي، ردت تقول : هل أنت جادة أنك ترغبين بفعل ذلك كله وحدك؟ أخبرتني أنني لست بحاجة للمساعدة، كلما يلزمني هو أن أتفهم كيف أتعامل مع الواقع. فيوم العمل لدى كارول ينتهي بلحظة وصول أطفالها من المدرسة، ذلك لأنها تعلم تمامًا بمُجرّد وصول أطفالها إلى المنزل فإنه من المستحيل أن تكتب موضوعًا ذا قيمة. لذلك كانت تعمل في المشاريع الكبيرة عندما يكون أطفالها في المدرسة وتترك الأشياء البسيطة لما بعد عودتهم. وأما الثنائي ليندا وزوجها وهما يعملان سويًا من المنزل، فهما يتشاركان في رعاية طفلهما، وعلاوة على ذلك أن والدة ليندا تأخذ ابنهما مرة في الأسبوع حتى تستطيع هي وزوجها العمل كامل اليوم من غير انقطاع. وبالنسبة لرالف أيضًا، فهي تتقاسم مع زوجها المسؤولية في رعاية الأطفال والقيام بالواجبات الاجتماعية تجاه الأصدقاء والأقارب، كلما استدعت الحاجة لذلك. فتوصلت حينها لخلاصة أن نجاحهن كسيدات أعمال لا يعني بالضرورة أن لديهن الوقت الكافي ليتمشين بملابس زاهية في المنتزهات ويحضرن ألذ أصناف الطعام لعائلاتهن ويحضرن الاجتماعات المدرسية وينظفن المنزل أو ينشغلن بحياكة القطع الصغيرة ليملأن بذلك وقت الفراغ، كما كنت أتصور. الواقع أن محاولة إقامة عمل خاص مستقل وتربية أطفال والقيام بمتطلبات البيت والعائلة وتخصيص زمن للأسرة و الأصدقاء، يبدو ذلك كله خلطة جاهزة للفشل. فبعد أن أيقظتني كارول بذلك الرد من أحلامي الوردية، عرفت أنه لا بُد أن أتخلى عن فكرة أن أكون الأم المثالية وأن أتنازل عن الصورة الخيالية التي رسمتها للواقع، وأن أراجع كل ما كنت أفعله و أتصوره. وجاءت لحظة الحقيقة، وكان لابُد أن أتحكم فيما أريد أن أفعله، وكانت الخطوة الأولى لي هي: حديث من القلب إلى القلب مع زوجي، ولأنه الوحيد الذي له دخل مادي من عمله خارج المنزل، فنحن بحاجة إلى من يرعى الطفلة بشكل كلي أثناء النهار، ولأن زوجي يتفهم ما أريد أن افعله أقترح أن يأخذ ابنتنا مرة كل نهاية أسبوع للتنزه، ليترك لي المجال للعمل كل اليوم والتركيز في الأعمال الخاصة، بالإضافة لذلك وجدت مربية لمدة يومين في الأسبوع تجالس طفلتي وأنا أعمل في غرفة المكتب في الطابق العلوي. ولكنني لم أتوقف عند هذا الحدّ، فبدأت التحدث والتشاور مع صاحبة لي في مجال الكتابة وبدأنا بتقليب الأفكار، في كيف تكون منتج من غير أن تهمل في رعاية الأطفال. في ذلك الوقت كنت عضوة في مجموعة كارول للكُتاب المستقلين، واستغليت ذلك بالتواصل مع الآخرين للحصول على أفكار إضافية تساعدني في تربية الأطفال وإدارة الوقت وغيرها من الأمور التي عانيت منها. ثم وضعت كل هذه الأفكار تحت الاختبار ، فلاحظت أن إنتاجي بدأ يتصاعد طردياً، وأصبحت قادرة على أن أكمل كل مسؤولياتي الكتابية وأن استمر في تسويق إمكانياتي الكتابية. فحققت دخلاً لا بأس به في تلك السنة إضافة لتمتعي بالإجازات وساعات عمل محددة في الأسبوع، والأفضل من ذلك كله أنني لا زلت زوجة وأمًا، وأجد دائمًا وقتًا أكون فيه لنفسي، كانت بحق تجربة مذهلة. فإذا كان أحد الوالدين كاتب مستقل، ولا زال يعاني من عقدة أن يكون أمًا أو أبًا مثاليًا، هنا بعض النقاط التي جمعتها من تجاربي السابقة وهي: اعملي على توفير مقدم رعاية لأطفالك، يمكن أن تكون رعاية نهارية أو مربية في البيت لساعات أو صديق أو قريب، لو كانت الأمور المالية متأزمة قليلاً، أوصي بأن تتواصل الأمهات ويرتبن بينهم دور لرعاية أطفال المجموعة بالتناوب.أخّري ما تطلق عليه كارول "الأحمال الثقيلة" إلى أوقات المدرسة أو القيلولة، بحيث أنك تعملين بشكل أكبر في المهام الصعبة التي تحتاج لتركيز عندما يكون الأطفال بعيدين، والأعمال الخفيفة بعد عودتهم.تعوّدي على النهوض مبكرًا أو النّوم متأخرًا أو كليهما، فالصحو مبكرًا أو النوم متأخرًا يعطيك وقتًا أكثر للعمل بحكم أن الأطفال لا يزالون في أسرّتهم.علّمي أطفالك اللعب باستقلالية، فليندا علمت طفلها ليعمل في مشاريعه المسلية بهدوء في ساعات عملها بتركيز، ألغاز أو تلوين أو اللعب بالدمى، بحيث يتعلم أن له مهامه الخاصة ليكملها عندما تكون أمه مستغرقة في الكتابة،لو فشل كل ذلك قدم لطفلك تطبيقات مثيرة أو أشغله بأفلام تناسب خياله وعمره.داومي على إنشاء قائمة واقعية بالمهام التي تريد القيام بها عمليًا، دعونا نواجه الأمر فكونك أمًا تعمل من المنزل، فأن ذلك لا يعني أنك تستطيعين أداء كل المهام التي كتبتها في الورق، فقائمة يومية بثلاث إلى خمس مهام ستكون أكثر واقعية.ابدئي بكتابة قائمة بما فعلتيه، لأننا أحياناً نُحبط عندما لا نستطيع إنجاز كل ما قررنا إنجازه في ذلك اليوم، وذلك ليس معناه أنك لم تحققي بعض المهام. في هذه الحالة فكري في ما تم إنجازه وليس فيما لم يُنجز، وعندها في نهاية اليوم سوف تفاجئين بمدى الإنتاجية التي حققتها.غيري الموقع، خارج المنزل، في غرفة أخرى، أو مقهى أو شرفة ما، فإن تغيير الوضع والظروف المحيطة، ربما يكون كل ما تتطلبه لزيادة إنتاجيتك، حتى تغيير الوضع من طاولة المكتب للأريكة ربما يغير من تسلسل الأفكار.اعملي كل بحثك في الإنترنت دفعة واحدة قبل أن تفصلي الاتصال، فإن الإنترنت هي من أكثر الأماكن التي يضيع فيها الكثير من الوقت، فكثيراً ما تُحدث نفسك أن زيارة قصيرة لفيس بوك و مرور سريع على البريد الإلكتروني لن يضر، ولكنك لحظة تفكر بهذه الطريقة تكون قد وقعت في الشرك.حدّدي المواضيع التي تريدين البحث فيها أكثر أو أن تتأكّدي من صحتها ، فبذلك يمكنك أن تُواصلي الكتابة في فترة واحدة من غير العودة للنت في كل مرة.حدّدي زمنًا لمواقع التواصل الاجتماعي والبريد الإلكتروني واجعليها قاعدة وحافظي عليها ، ذلك يكفيك شر أن تعودي لهذه المواقع كل حين ووقت، فإن هذا يساعدك في الحفاظ على الزمن.حمّلي برامج مثل Freedom أوAntisocial، فمهمة هذه البرامج أن تمنعك من دخول مواقع التواصل لفترة محددة، وعندها ليس لك خيار سوى القيام بعمل مجدي.حاولي معرفة الوقت الذي تكونين فيه أكثر إنتاجية، هذا مهم حين تريد أن تعمل في مشاريع أكثر إنتاجية.اضبطي مُنبّه الساعة ، اعملي لمُدّة 45 دقيقة متواصلة وأعطي نفسك بعدها فسحة قصيرة، فإن ذلك يعطيك وقتًا كافي للتّركيز ومع مرور الوقت ستكون عادة شخصية جيدة، وربما تستغنين مع الوقت عن هذا المنبه.مارسي الرياضة وخذي قيلولة، لأنك ستندهشين بما تفعله قيلولة قصيرة أو رياضة لعدة دقائق، ستعطيك طاقة أكثر وبالتالي إنتاجية أكبر.خصّصي زمنًا لنفسك، فحتى الموظفين يأخذون إجازات، وأنت أحق بها إذا كنت تريد مواصلة عملك بنجاح وخصوصًا لو كان لديك أطفال.استعيني بمصادر خارجية، لماذا تفعلين كل ما تريد فعله بنفسك، في حين يمكنك استئجار آخرين بأجر أقل، فربما يكلّفك قليلاً لكنه أجدى من أن تعمل ذلك بنفسك، كشخص لتنظيم البريد الخاص و شخص يبني موقعك الخاص وأخر يُدير حساباتك على مواقع التواصل الاجتماعي والزمن الذي ستكسبه بالاستعانة بالمصادر الخارجية يتيح لك فرص للبحث عن أعمال أخرى أكثر مردوداً مما تدفعين.استأجري آخرين، وفّري لنفسك زمنًا أكثر باستئجار شخص يُنظّف المنزل أو شخص يحضر الطعام وقومي بالتّسوق عبر الإنترنت وما إلى هنالك.والآن ماذا عنك؟في النهاية، ليس عليك فعل كل ما كتبته في هذا الموضوع، فلك حرية التطبيق، وأنت الأكثر معرفة بما يصلح لك ولعائلتك. جرّبي، تكلّمي، شاوري، ثم اختاري ما يناسبك. هذه النقاط ليست سوى أفكار لتبني حولها الإستراتيجية التي توفر لك الوقت، والأهم أن تتخلى عن فكرة الأم أو الأب المثالي. وعندها فقط يمكنك التخلي عن وظيفتك الحالية وتوفّري وقتًا أكثر لعائلتك وأطفالك.... ترجمة -وبتصرّف- للمقال: How to be a Successful Entrepreneur and a Great Stay at Home Parent.1 نقطة
-
يمكنني أن أفيدك ببعض النصائح التي استقيتها من صديق لي يعمل على اليوتيوب، استطاع أن يجلب أكثر من 30000 مشترك في ظرف سنة واحدة، ما قام به هو الآتي: - نشر فيديو واحد كل يوم، فيديو يقوم هو بتصويره يتحدث فيه عن نصائح مختلفة في مجال التنمية الذاتية والبيزنس بشكل عام، يظهر بالصوت والصورة. - أهم شيء مكّنه من النجاح هو الانضباط بحيث نجح فعلا في نشر فيديو كل يوم لمدة عام كامل. - استحداث مسابقات من حين لآخر، في ظرف سنة قام بمسابقتين، يعطي فيها فرصة لربح بعض الجوائز كالكتب والاشتراك في بعض الكورسات التي يقوم بها. - أهمية المسابقات تكمن أنها تعطيك مشتركين إضافيين بشكل مجاني، تقوم على عملية رابح رابح، أي المستخدم يقوم بنشر فيديوهاتك، يضغط لايك، ويقوم بكتابة تعليق، ويشترك في القناة، مقابل أن تعطيه جائزة للرابح في القرعة بطبيعة الحال. - مشاركة بعض الجوانب من حياتك، هذا يجعل المشاهد يتابعك دائما، لأن مثل هذه الفيديوهات تجعله يتعلق بك، فأنت تدخله في حياتك من دون أن يشعر وبطبيعة غريزة الفضول التي يتميز بها الإنسان تجعله يريد أن يعرف عنك أكثر، وبالتالي يتابعك. - محاورة أصحاب القنوات المميزة من حين لآخر، فأنت يجعلك تتصل بمشتركين قنوات أخرى كبيرة، وبالتالي ستجلبهم لقناتك أيضا.1 نقطة
-
هناك عدة طرق للقيام بذلك فيمكنك تحديد أجزاء الشعر الذي تريدين تلوينه ومن ثم تغيير الألوان أو يمكن تغيير ألوان الصورة كلها من hue/saturation ثم تغيير اللون إلى اللون الذي تريدينه والآن أضيفي قناع إلى هذه الطبقة وحددي هذا القناع من لوحة الطبقات ثم استخدمي الفرشاة السوداء المموّهة بالحجم المناسب للرسم فوق الأجزاء التي لا تريدينها أن تتلون واستمري بذلك حتى يبقى فقط الجزء من الشعر المطلوب تلوينه بالتوفيق1 نقطة
-
إنّ تقدير حجم السوق عنصر من العناصر المهمّة في خطة مشروعك التجاري وكذلك في عرضك التقديمي، وهو سؤال سيُطرح عليك من قِبل المستثمرين المحتملين، وستجد نفسك مدافعًا عن هذا اﻷمر حتى لو كانت غالبية المعلومات والفرضيات مستقاة من مصادر مختلفة. وكما يشير عنوان هذا المقال فإنّي سأتكلم حول كيفية تقدير حجم السوق الخاص بك، ولكن كيف ستصبح معتادًا على تقدير حجم السوق الخاص بك وما الذي يجب عليك فعله إن أفرطت أو فرّطت في عملية التقدير؟ أقدّم إليك في هذا المقال بعض النصائح التي ستفيدك في هذا الموضوع المهمّ. ما السبب وراء أهمية حجم السوق الخاص بك؟هناك ثلاثة أسباب تفسّر أهمّية قضاء بعض الوقت في تحليل رؤيتك وتفصيلها لحجم السوق. السبب اﻷول وهو واضح ومعروف على نطاق واسع، يبيّن حجم السوق الخاصّ بك الحد اﻷقصى الذي يمكنك الوصول إليه في تنمية شركتك (العائدات) دون الحاجة إلى إضافة المزيد من المنتجات أو القيام بأمور جديدة لتحقيق زيادة في حجم السوق الخاصّ بك.السبب الثاني هو أن المستثمرين يرغبون في رؤية طريقة تفكيرك اتجاه الجوانب المختلفة من حجم السوق (سنبيّن هذا بعد قليل) والطريقة التي تتبعها في التغلب على هذه اﻷمور مع مرور الوقت.السبب الثالث هو أنّ ذلك يعطي الفرصة لتثقيف المستثمرين المحتملين وشركاءك في المشروع التجاري حول السوق من وجهة نظرك الشخصية، وبالخصوص إن كنت تملك منتجًا مبتكرًا أو منتجًا ﻻ يتطلب مزيدَ شرحٍ كي يفهمه اﻵخرون.ولكن ما هو الحجم الكافي؟غالبًا ما يكون هناك تبادل بين حجم السوق وحصتك السوقية المعقولة عبر الزمن. على سبيل المثال فإن حصولك على حصة 2% في سوق قيمته 10 مليارات دولار سيعود عليك بنفس العائدات في حال حصولك على حصة 20% من سوق قيمته مليار دولار، أو 80% من سوق قيمته 250 مليون دولار. القيمة واحدة في الحالات الثلاث وهي 200 مليون دولار. ولكن في حال حصلت على حصة 80% فلن يكون هناك متّسع للنمو إلا إذا كان ذلك السوق ينمو بسرعة كبيرة. وفي حالة الحصول على حصة 2% فأنت لاعب صغير جدًّا في هذا السوق، ولكن إن كان مجال عملك مبتكرًا جدًّا، ناميًا ويسعى خلفه أصحاب الحصص السوقية الكبيرة، فإنّ هذه الحصّة ستكون جيّدة. وبعبارة أخرى، بإمكان هذا الأمر أن يجعلك تحصل على عروض شراء (للشّركة النّاشئة) تكون مُغرية جدّا. أو سيمنحك هذا فرصة التوسع إلى أجزاء مجاورة وقريبة من سوقك المُستهدف الحالي لتستمر في تحقيق النمو وتحقيق أفضل مكانة مُمكنة في السّوق.. وإن اكتشفت لاحقًا خللًا أو نقصًا في قيمة العرض اﻷولية أو نموذج المشروع التجاري الخاص بك، فسيكون لديك حينها متّسع لإعادة التّمحور وتحقيق النجاح. وكما ترى فهناك الكثير من الخيارات المتاحة في كلتا الحالتين ما دام حجم السوق كبيرًا. وكقاعدة عامة، فاﻷسواق الكبيرة أفضل من اﻷسواق الصغيرة، والأسواق التي تحقق نسب نمو مرتفعة أو تلك التي يمكن تحريكها ببعض اﻷفكار المبتكرة تكون مفضلة على اﻷسواق الراكدة. اﻷمر اﻷساسي هنا هو فهم ديناميكية السوق الخاص بك، وكيف يمكنك التلاؤم معها، وكيف يمكنك تفسير هذا كله وبشكل جيد للمستثمرين والشركاء المهمّين. السوق الكلي المتوفر (Total Available Market (TAMالسوق الكلي المتوفّر بسيط من الناحية النظرية، ويعرّف بأنّه مقدار اﻷموال التي ستحصل عليها عندما تبيع ما تقدّمه من منتجات إلى جميع زبائن السوق الخاصّ بك، حتى لو لم يكن بعض الزّبائن مثاليين لمُنتج الآن. لنلق نظرة على بعض اﻷمثلة لتتضح الصورة بشكل أكبر: الشّركات: لنفترض أنّك تملك منتجًا تقوم ببيعه للشّركات الكبيرة بسعر 150,000$ كمعدل. ولنفترض أيضًا أن السوق الكلي المتوفر هو جميع المنظمات الموجودة في قوائم Fortune 5000 و Forbes Global 2000 و Fortune Largest Private Companies. لنفرض اﻵن أنّنا حصلنا على 8000 منظمة مختلفة فقط (هناك شركات تظهر في أكثر من قائمة). ستكون قيمة السوق الكليّ المتوفّر هي 1.2 مليار دولار ($150,000 × 8,000).المستهلكون: لنفترض أنّك تبيع تطبيقًا للهواتف الذكية بسعر 4.99$، وفي زمن كتابة هذا المقال فإنّ عدد مستخدمي الهواتف الذكية يصل إلى ما يقارب الملياري مستخدم، لذا ستكون قيمة السوق الكلي المتوفر هي 10 مليارات دولار (4.99$ × 2 مليار).إنفاق السوق: لنفترض أنّك تقدّم منتجًا فريدًا لسوق الرعاية الصحية المنزلية، وأنّك تحصل على نسبة 1% من قيمة ما ينفقه مزودو خدمة الرعاية المنزلية عند استخدامهم لهذا المنتج. ولنفترض كذلك أن حجم الإنفاق العالمي على خدمات الرعاية الصحية يصل إلى 350 مليار دولار، ستكون قيمة السوق الكلي المتوفّر حينئذ 3.5 مليار دولار (1% × 350 مليار دولار).وسّع آفاق تفكيرك عندما تقدّر قيمة السوق الكلي المتوفّر ولكن لا تذهب بخيالاتك بعيدًا جدًّا، لاحظ مثلًا أنّي عندما قدّرت عدد الشّركات الكبيرة لم أدخل في حساباتي جميع المشاريع التجارية مهما كان حجمها، وبالنسبة إلى العملاء فلم تتضمن حساباتي جميع سكّان الكرة اﻷرضية. ﻻحظ كذلك استخدام أحد الأمثلة لمقدار اﻹنفاق الكلي ضمن السوق (المثال الثالث) بدلًا من المقادير القياسية مثل عدد الشّركات الكبيرة أو عدد المستخدمين. يمكن اﻻستفادة من مقدار إنفاق السوق في وصف حجم السوق الخاصّ بك، ما دامت عائداتك مرتبطة بالمقدار الكلي الذي يتم إنفاقه في مجال معيّن، كما هو الحال في المثال الذي وضّحته سابقًا. السوق القابل للخدمة (Serviceable Market (SAMقد لا تتمكن من تحقيق النموّ اللازم للتوجّه إلى سوقك الخاصّ بأكمله، وهذا يعني أنك تستطيع تقديم الخدمات إلى شريحة مُحدّدة منه. تُدعى هذه الشريحة بالسوق القابل للخِدمة (أي السّوق الذي يُمكنك تقديم خدمات له). يمكن لسوقك القابل للخِدمة أن ينمو عندما يتّسع نطاق عملك جغرافيًا أو عند تضمينك لنماذج تجارية جديدة وقنوات بيع جديدة. لنحاول معرفة مقدار السوق القابل للخِدمة مستعينين باﻷمثلة السابقة. الشّركات: لنفترض أنّ موظّفي الدعم الفني والمبيعات في شركتك يتواجدون في الولايات المتحدة اﻷمريكية فقط، ومنتجك مُتوفّر باللغة الإنجليزية فقط. وهو مفيد الآن فقط للشّركات التي تملك مراكز بيانات متعددة ومنتشرة في أماكن مختلفة. من أصل 8000 شركة لا يتوافق مع هذه المعايير سوى 3000 شركة فقط، لذا فإن سوقك القابل للخِدمة هو 450 مليون دولار (150,000$ × 3000).المستهلكون: لنفترض أن تطبيق الهواتف الذكية الخاص بك يعمل على أجهزة Android وباللغة اﻹنجليزية فقط. من أصل 2 مليار مستخدم للهواتف النقالة هذه المعايير هناك 500 مليون مستخدم فقط تتطابق عليهم هذه المعايير، لذا يكون سوقك القابل للخِدمة 2.5 مليار دولار (4.99$ × 500 مليون).إنفاق السوق: لنفترض أنّ لديك ترخيصًا قانونيًا لبيع منتجك الخاصّ بالرعاية الصحّيّة المنزلية في الولايات المتحدة اﻷمريكية فقط، حيث يتم إنفاق 50 مليار دولار سنويًا على هذا القطاع. إذًا يكون سوقك القابل للخِدمة 500 مليون دولار (1% من 50 مليار دولار).السوق المستهدف الابتدائي Initial Target Marketكثيرًا ما يكون السّوق المُستهدف الابتدائي الخاصّ بك أصغر من السوق القابل للخِدمة، وذلك ﻷنّك تعرف أن شريحة من السوق القابل للخِدمة ستنجذب إلى المنتج الذي ستقدّمه. على سبيل المثال، قد يلائم المنتج الخاص بالشّركات في المثال السابق قطاعات الخدمات الماليّة وخدمات التأمين، ونتيجة لذلك ستعتمد الشركة خطابًا ونظام تسعير وقنوات بيع محسّنة لتستهدف بها قطاع الخدمات المالية ومزودي خدمات التأمين. أما بالنسبة إلى المستهلكين فيمكن أن يتوجّه المنتج الذي تقدّمه إلى النساء فقط واللاتي تتراوح أعمارهنّ بين 25 و39 سنة واللاتي يمتلكن أطفالًا أيضًا. أعتقد أنّك قد فهمت الفكرة، يبدو اﻷمر كمرشِّح Filter آخر أمام السوق القابل للخِدمة يحدّد الشريحة التي تستهدفها في هذه المرحلة. كيف تخاطب المستثمرين بشأن حجم السوق الخاص بكيجب أن تحذر من حصول بعض حالات سوء الفهم العرضية عندما تتحدّث عن حجم السوق الخاصّ بك أمام المستثمرين، إذ يعتقد بعض المستثمرين أن حجم السوق هو السوق القابل للخِدمة وليس السوق الكليّ المتوفّر، لذا حين تخبرهم أن حجم السوق الخاص بالمنتج الذي ستقدّمه للمستهلكين هو 10 مليارات دولار (كما في المثال السابق) سينظر المستثمرون إلى كلامك على أنّه ضرب من الجنون وأنّك بعيد كل البعد عن الصواب. في الواقع، يمكن أن تحصل على العبارة التالية عندما تدمج الأنواع الثلاثة لحجم السوق والتي ذكرناها في هذا المقال: “بعد أن نطلق منتجنا في الشهر القادم مستهدفين بذلك سوقنا الابتدائي المُتمثّل في شريحة المُراهقين في الولايات المتحدّة والذين يمتلكون أجهزة هواتف ذكية تعمل بنظام Android، سنقّدم خدماتنا إلى سوق بحجم 250 مليون دولار، ولكن بعد دعم نظام iOS وإضافة الميزة XYZ الخاصة بطلاب الجامعات في وقت ﻻحق من هذه السنة، سنقدم خدماتنا إلى سوق بحجم مليار دولار. ونتوقع بعد مرور ثلاث سنوات أن نعقد شراكة مع 3 من أصل أفضل 10 مصنعين للهواتف الذكية في العالم، اﻷمر الذي سيوسّع حجم السوق الخاصّ بنا إلى 5 مليارات دولار". الخلاصةإن حجم السوق الخاصّ بك من الجوانب المهمة والضرورية في خطة العمل الخاصّة بك وما ينتج عنها من محادثات مع المستثمرين. ومن الضروري بمكان أن تجري بعض اﻷبحاث لتصل إلى نماذج وافتراضات معقولة يمكنك من خلالها تقدير حجم السوق الخاصّ بك وبأنواعه الثلاثة. وإن جوبهت بالمعارضة، فدافع عن نفسك مستندًا إلى منهجيتك في البحث والافتراضات التي وضعتها على هذا اﻷساس، وإن لم تستطع إقناع المستثمر بحجم السوق الخاصّ بك، فاعلم أنّ هناك مشكلة في الافتراضات التي وضعتها وأنّ عليك إعادة حساباتك مرة أخرى. لا تنسَ كذلك تضمين بعض العوامل اﻷخرى مثل نمو السوق وفرص الابتكار والانفتاح عندما تتحدث حول السوق الخاص بك. يمكن لهذه العوامل أن تكون جذّابة بل ربّما تكون أكثر جذبًا حتّى من مجرد التطرّق لحجم السوق وحسب. ترجمة –وبتصرّف– للمقال Estimating Your Market Size لصاحبه Gordon Daugherty. حقوق الصورة البارزة: Designed by Freepik.1 نقطة