لوحة المتصدرين
المحتوى الأكثر حصولًا على سمعة جيدة
المحتوى الأعلى تقييمًا في 08/02/17 في كل الموقع
-
كتبت قبل وقت ليس ببعيد مقالًا بعنوان “50 أداة استسراع نمو للمسوّقين في الشركات الناشئة”، وتصدرت به المرتبة الثالثة في نتائج جوجل للبحث عن كلمة “growth hacking tool”، وقد قرأ المقال إلى الآن -26 أكتوبر 2016، وقت نشر النسخة اﻹنجليزية للمقال الذي بين يديك- 11562 شخصا ويأتيه 300 زائر كل يوم، وأحصل على 20 اشتراكًا في مدونتي بسبب هذا المقال كل يوم أيضًا. كل ما فعلته للوصول إلى تلك المرتبة في هذه المدة الوجيزة هو اتباع نصائح برايان دين Brian Dean في مدونته، وأنا أعدك إن اتبعت تلك الخطوات التي سأسردها لك أن تصل إلى نفس النتائج أيضًا. 1. ابحث عن محتوى قيّم يتصدر نتائج جوجل ابحث عن محتوى في مجالك يجعل المواقع تشير إليه كمرجع لمقالاتها أو تذكره فيها، هذا يعني أن يكون المحتوى الذي تبحث عنه موجودًا في أول خمس نتائج للكلمة المفتاحية التي تريد أنت أن تتصدر نتائج البحث فيها، يجب أن تكون حالة يبحث عنها كثير من الناس، ويكون المحتوى أصليًّا ومفيدًا بحيث ﻻ يستطيع أحد - من العاملين بالتسويق - أن يقاوم الدخول إلى حسابه في ووردبريس واﻹشارة إلى ذلك المحتوى في مقالاته. اخترت عبارة “growth hacking tool” لتكون الكلمة التي أردت تصَدُّر نتائج البحث فيها، في أول خمس نتائج تحديدًا، لماذا؟ ﻷني أعرف أن استسراع النمو (Growth Hacking) يحصل على كثير من الاهتمام مؤخرًا، وقد رأيت النتائج التالية بعد قليل من البحث في أداة جوجل للكلمات المفتاحية. تبدو تلك الأرقام جيدة للغاية، لكن مصطلح البحث نفسه عام نوعًا ما، فالناس الذين يبحثون عنه قد يرغبون بمعرفة ما الذي يعنيه هذا المصطلح ببساطة، أو ربما كانوا يبحثون عن منافسيهم للمقارنة. أردت التركيز على من سيستخدم أداة استسراع النمو التي أبنيها، فهؤﻻء هم الذين أريد منهم الاشتراك في مدونتي، لهذا اخترت كلمة “growth hacking tool”، وكانت النتائج التي رأيتها حين بحثت في جوجل بهذه العبارة على النحو الظاهر في الصورة. -وصف الصورة- توجد - كما ترى من الصورة - مدونة Kissmetrics، مجلة Inc، وأسماء أخرى كبيرة لمواقع ومدونات ذات مرجعية في هذا المجال ولعبارة البحث تلك، وقد أردت أنا أن أزاحمهم في نتائج البحث. لذا ها أنا ذا قد عرفت نوع المحتوى الذي احتجته لكتابة تدوينتي التالية، وعلي الآن أن أكتب نسخة أفضل من تلك المنشورة في نتائج البحث. 2. اكتب أفضل من الموجود يقول برايان دين: يبدو الأمر سهلًا، أليس كذلك؟ إذَا كيف سنجعل المحتوى أفضل؟ إليك بعض النصائح. اجعله أطول في حالتي أنا، فقد رأيت أن هناك مقالًا بعنوان “35 أداة لاستسراع النمو”، وقررت أن أجعل مقالي بعنوان “50 أداة لاستسراع النمو”، ولو كان لدي وقت أطول لجعلتها مئة، كي يتغلب على الموجود بالفعل بأشواط بعيدة. محتوى حديث هناك أطنان من المحتوى القديم على الإنترنت. احرص أن يكون محتواك أحدث من الموجود حاليًا، فلا يجوز أن تتفوق عليك في نتائج جوجل مواقع يعود تصميمها إلى 2003! تصميم أفضل يجب أن يكون بمقالك لمسة تصميم جميلة وبسيطة، فاحتمال أن يشير أحدهم إلى مقال جميل التصميم أكبر من لو كان مقالًا نصيًا عاديًا. انظر لهذا المقال مثلًا: “20 نصيحة ﻹرسال رسائل بريدية أفضل“، فهو طويل للغاية ومفصل وشامل، لكن ذلك الجدول ذا التصميم الرائع الذي يحتوي عناصر المقال بشكل جذاب ييسر على القارئ استيعاب ما يريد كاتبه أن يشرحه. أريدك الآن أن تقارن بين ذلك المقال وبين مقال “أفضل طرق التسويق بالبريد الإلكتروني” شتان بينهما، أليس كذلك؟ تفصيل أكثر أَحصِ طول مقالات منافسيك التي تحتل المراتب الخمسة الأولى في نتائج البحث، وضاعف من عدد الكلمات. أنصحك أن تكتب مقالًا من خمسة آﻻف كلمة على الأقل، اجعله متخمًا بالمعلومات. من المهم أن تحقق كل تلك النقاط السابقة كما يشرح برايان قائلًا: الخطوة التالية أن تنشر مقالك بعد أن تعطيه لبعض معارفك وأصدقاءك كي يراجعوه. ملاحظة مهمة أردت ذكرها استخدمت إضافة Yoast لووردبريس كي أتأكد مرة أخرى أني أدخلت الكلمات المفتاحية التي أريدها في كل الأماكن المناسبة في مقالي: متنه وعنوانه وترويسته وغير ذلك. تخبرني تلك الإضافة كيف تبدو كثافة كلماتي المفتاحية، ألق نظرة بنفسك. يظهر في الصورة تحليل المقال من حيث استخدامه للكلمات المفتاحية، ويشير التحليل إلى النقاط التالية: الكلمة المفتاحية ﻻ تظهر في الفقرة الأولى من المقال. تأكد أن تضعها واضحة في الفقرة الأولى. كثافة الكلمة المفتاحية بالنسبة للمقال كله 0.84%، وهي نسبة قليلة. وُجدَت الكلمة المفتاحية 14 مرة في المقال. عنوان الصفحة يحتوي الكلمة/العبارة المفتاحية، لكنها ليست في البداية، اجعلها في بداية العنوان. عنوان الصفحة يحتوي على 35 محرفًا، وهذا أقل من الحد الأدنى الذي ننصح به وهو 40 محرفًا، استخدم المساحة الباقية لتضيف صورًا أخرى من الكلمة المفتاحية أو اكتب نسخة بها دعوة لاتخاذ إجراء Call to action. هذه الصفحة بها 6 روابط توجه إلى خارج المقال (روابط NoFollow)، وجميعها روابط لا تفيد الصفحة في شيء، وﻻ تزيد رتبة المقال. لم نعثر على وسوم للعناوين الفرعية (مثل H2) في المقال. هذه النسخة من المقال ترتيبها 60.1 في اختبار Flesch Reading Ease، وهذا يعني أنها جيدة. الصور في هذه الصفحة تحتوي على وسوم بديلة بها الكلمات المفتاحية للمقال. هناك 1662 كلمة في المقال، هذا أكبر من الحد الأدنى المنصوح به وهو 300 كلمة. لم تستخدم هذه الكلمة المفتاحية من قبل، جيدًا جدًا. الكلمة المفتاحية موجودة في رابط الصفحة. وصف الصفحة يحتوي على الكلمة المفتاحية الأساسية. ربما يجب أن تنظر في الوصف السابق لترى كيفية ظهور مقالك مقارنة بمنافسيك، هل يمكن جعله أفضل؟ تظهر أيقونة صغيرة بلون معيَّن أمام كل نقطة للدلالة على أن النقطة المذكورة مُنجَزة أم لا. كما أن تلك الإضافة تخبرني إذا كان هناك أي خطأ آخر يتعلق بتهيئة المقال لمحركات البحث. تعرض الإضافة - كما يظهر في الصورة السابقة - معاينة لكيفية ظهور المقال في نتائج بحث جوجل، كي يعدلها صاحب المقال إن كانت تحتاج إلى تحسين. 3. راسل من أشار في موقعه إلى المقالات التي كانت في المراكز الأولى في نتائج البحث لكلمتك المفتاحية. إن الوقت مناسب اﻵن بعد أن صارت لديك نسخة أفضل من المقال كي تبحث عمن أشار إلى المقال الأصلي المنافس لك في موقعه أو مدونته. في حالتي أنا، فقد أخذت مقال “35 أداة استسراع نمو للمسوقين الذين ﻻ يعرفون البرمجة” ووضعته في متحقق روابط خلفية مثل Open Link Profiler الذي يسمح بتصنيف النتائج حسب تأثيرها. بحثت في النتائج التي أشارت إلى المقال عن المدونات والمواقع ذات المرجعية، فهؤﻻء الذين أخطط أن أطلب منهم الإشارة إلى مقالي الذي نشرته. فمثلًا، لقد رأيت هذا المقال Here Are Our Five Favorite Articles Ee Read This Week وهو يضع رابطًا لمقال “35 أداة استسراع نمو”، فتصفحت محتواه ثم ذهبت إلى صفحة About في الموقع وقرأت بيانات الكاتب وبيانات القائمين على الموقع كي أتواصل معهم، وإليك نص الرسالة الذي أستخدمه (بناء على نصائح برايان دين): كنت أظفر غالبًا بنسبة 5-10% ممن أراسلهم، وفي حالتي أنا فإن الحصول على عشر روابط لمقالي الجديد جعلني أظهر في الصفحة الأولى لنتائج جوجل لعبارة “growth hacking tool”، و “growth hacking tools”. تذكر أيضًا أن جودة الروابط عامل مهم جدًا، فنجاحك في تطبيق هذا اﻷسلوب يعتمد على الجودة وليس الكم، أي جودة الروابط التي ستشير إليك وليس عددها. اقرأ إن شئت ماذا يقول برايان دين عن جودة تلك الروابط: دورك اﻵن لتجرب بنفسك هذا كل ما لدي ﻷخبرك به، وعليك الآن أن تختار كلمة مفتاحية تريد أن تتصدر نتائج البحث فيها، وابحث عن أفضل المقالات في نتائج تلك الكلمة، واكتب مقالات أفضل منها، ثم تواصل مع كل من أشار إلى تلك المقالات في مواقعهم، واطلب منهم الإشارة إلى مقالك الجديد. ربما يبدو ذلك عملًا مجهدًا، لكن عملك هذا سيعود عليك بالنتائج التي كنت ترغب فيها ﻷنك تعرف أنك ستتصدر نتائج جوجل إن بذلت جهدك. ترجمة -بتصرف- لمقال Link Building Study: How I Ranked #3 for my Term on Google in 14 days لصاحبه Dmitry Dragilev. حقوق الصورة البارزة محفزظة لـ Freepik1 نقطة
-
1 نقطة
-
مرحباً بك صديقي اعتقد ان متصفح chrome هو المتصفح الأمثل للتعامل مع Css3 لتتعلم اكثر عن دعم المتصفحات ل Css3 ومتى يجب عليك ان تضيف البادئة (-moz- , -wbkit- .... إلخ) قم بالدخول إلى هذا الموقع فقط ادخل اسم الخاصية وهو يعرض لك المتصفح الذي يدعمها ومتى يجب عليك ان تضيف البادئة https://caniuse.com1 نقطة
-
يشرح هذا المقال طريقة كتابة تعليمات تحوي متغيرات تخزن فيها قيمًا مختلفة، كالأرقام والكلمات، وتحوي أيضًا عوامل حسابية (operators)، وهي رموز تمثل عمليات حسابية. ثم يُعرّج على فكرة التركيب (أي استخدام مزايا اللغة التي تعرفنا عليها سابقاً مع بعضها)، كما يتحدث عن ثلاثة أنواع من الأخطاء البرمجية ونذكر فيه المزيد من النصائح عن تنقيح البرامج من الأخطاء. التصريح عن المتغيرات أحد أقوى المزايا لأي لغة برمجة هي القدرة على تعريف ومعالجة المتغيرات (variables). المتغير هو منطقة ذات اسم تخزّن قيمة (value). قد تكون القيم أرقامًا، أو نصوصًا، أو صورًا، أو مقاطع صوتية، وغيرها من أنواع البيانات. عليك أولًا التصريح عن متغير ثم تخزين القيم فيه. String message; هذا النوع من التعليمات يدعى تصريح (declaration)، لأنها تصرح أن نوع المتغير المدعو message هو String. لكل متغير نوع (type) يحدد نوع القيم التي يمكنه تخزينها. مثلًا، النوع int يخزن الأعداد الصحيحة، والنوع String يخزن السلاسل المحرفية. بعض الأنواع تبدأ بحرف كبير وبعضها الآخر يبدأ بحرف صغير. سنعرف معنى هذا التمييز لاحقًا، لكن الآن عليك الانتباه لكتابتها بشكل صحيح. ليس هناك نوع Int ولا string. لإنشاء متغير من النوع الصحيح، التعليمة هي: int x; حيث x هو اسم كيفي اخترناه للمتغير. بشكل عام، عليك اختيار أسماء المتغيرات بحيث تدل على دور المتغير في البرنامج. مثلًا، عندما ترى التصريحات التالية عن المتغيرات: String firstName; String lastName; int hour, minute; هذا المثال يصرح عن متغيرين من نوع String ومتغيرين من نوع int. عندما يتكون اسم المتغير من كلمتين أو أكثر، مثل المتغير firstName، جرت العادة على جعل الحرف الأول من كل كلمة حرفًا كبيرًا عدا الكلمة الأولى. أسماء المتغيرات حساسة لحالة الأحرف، ولذلك فالمتغير firstName مختلف عن المتغير firstName أو FirstName. يوضح هذا المثال أيضًا صيغة التصريح عن عدة متغيرات من نفس النوع في سطر واحد: كلًا من hour و minute هو عدد صحيح (متغير من النوع int). لاحظ أن كل تعليمة تصريح تنتهي بفاصلة منقوطة. يمكنك تسمية متغيراتك كما تشاء. لكن هناك حوالي 50 كلمة محجوزة، تدعى الكلمات المفتاحية (keywords)، ولا يسمح لك باستخدامها كأسماء لمتغيراتك. هذه الكلمات تشمل public، وclass، وstatic، وvoid، وint، التي يستخدمها المترجم لتحليل بنية البرنامج. هناك قائمة كاملة بالكلمات المفتاحية موجودة، لكن لا حاجة لحفظها. معظم المحررات المستخدمة في البرمجة توفر ميزة "تلوين الشفرة" (syntax highlighting)، التي تجعل الأجزاء المختلفة من البرنامج تظهر بألوان مختلفة. الإسناد بعد أن صرحنا عن بعض المتغيرات، سنستخدمها لتخزين بعض القيم فيها. يمكننا عمل ذلك باستخدام تعليمة الإسناد (assignment). message = "Hello!"; // give message the value "Hello!" hour = 11; // assign the value 11 to hour minute = 59; // set minute to 59 يبين هذا المثال ثلاث تعليمات إسناد، والتعليقات تظهر ثلاثة أساليب يستخدمها الناس أحيانًا عندما يقرؤون تعليمات الإسناد. قد تكون المفردات مربكة هنا، لكن الفكرة واضحة : عندما تصرح عن متغير، أنت تنشئ منطقة تخزينية لها اسم. عندما تطبق تعليمة الإسناد على متغير، فأنت تغير القيمة التي يحويها. كقاعدة عامة، يجب أن يكون نوع المتغير من نفس نوع القيمة التي تسندها إليه. مثلًا، لا يمكنك تخزين سلسلة محرفية في المتغير minute أو عددًا صحيحًا في message. من ناحية أخرى، هذه القاعدة قد تكون مصدرًا للإرباك أحيانًا، بسبب وجود العديد من الطرق التي تسمح لك بتحويل القيم من نوع لآخر، وأحيانًا تحول Java الأشياء تلقائيًا. لكن الآن عليك فقط أن تتذكر القاعدة العامة بأن المتغيرات والقيم يجب أن تكون من نفس النوع، وسنتحدث عن الحالات الخاصة لاحقًا. أحد مصادر الإرباك هو أن بعض السلاسل المحرفية تبدو مثل الأرقام، لكنها ليست كذلك. مثلًا، يمكن أن يخزن المتغير message السلسلة المحرفية "123"، المكونة من المحارف '1' و '2' و '3'، لكنها ليست مثل العدد الصحيح 123. message = "123"; // legal message = 123; // not legal يجب تهيئة المتغيرات (initialize)، أي إسناد قيمة لها أول مرة، قبل أن تستخدمها. يمكنك التصريح عن متغير ثم إسناد قيمة له لاحقًا، كما في المثال السابق. كما يمكنك أيضًا التصريح عن المتغير وتهيئته بسطر واحد: String message = "Hello!"; int hour = 11; int minute = 59; مخططات الحالة قد تظن أن تعليمة a = b هي تعليمة مساواة لأن Java تستخدم الرمز = لعملية الإسناد. لكنها ليست مساواة! المساواة عملية تبديلية، أما الإسناد فلا. على سبيل المثال، في الرياضيات إذا كان a = 7 إذًا 7 = a. لكن في Java a = 7; تعليمة إسناد مشروعة، لكن 7 = a غير مشروعة. يجب أن يكون الطرف الأيسر من تعليمة الإسناد متغيرًا (اسمًا لموقع تخزيني). في الرياضيات أيضًا، جملة المساواة صحيحة دائمًا. إذا كان a = b الآن، فإن a سيبقى مساويًا لـ b دائمًا. أما في Java، فتعليمة الإسناد قد تجعل قيمتي متغيرين متساويتان، لكن قد لا يستمران على هذه الحال. int a = 5; int b = a; // a and b are now equal a = 3; // a and b are no longer equal في السطر الثالث تغيرت قيمة a، لكن قيمة b لم تتغير، وبالتالي لم يبق المتغيران متساويان. المتغيرات في البرنامج مع قيمها الحالية تشكل حالة البرنامج (state). يُظهِر الشكل 2.1 حالة البرنامج بعد تنفيذ هذه التعليمات. تدعى هذه المخططات التي تظهر حالة البرنامج بمخططات الحالة (state diagrams). يُمثَّل كل متغير بصندوق يظهر اسم المتغير خارجه وقيمة المتغير داخله. أثناء تنفيذ البرنامج تتغير الحالة، لذلك عليك اعتبار مخططات الحالة كتمثيل لحظي لنقطة محددة في مسار التنفيذ. طباعة المتغيرات يمكنك عرض قيمة متغير باستخدام println أو print. في التعليمات التالية صرحنا عن متغير اسمه firstLine، وأسندنا له القيمة "!Hello, again"، وعرضنا تلك القيمة. String firstLine = "Hello, again!"; System.out.println(firstLine); عندما نتحدث عن عرض متغير فنحن نقصد قيمة المتغير عمومًا. أما لعرض اسمالمتغير، فعليك أن تضعه بين علامتي اقتباس. مثلًا: System.out.print("The value of firstLine is "); System.out.println(firstLine); خرج هذا البرنامج هو: The value of firstLine is Hello, again! بنية تعليمة عرض المتغير هي نفسها بغض النظر عن نوع المتغير. مثلًا: int hour = 11; int minute = 59; System.out.print("The current time is "); System.out.print(hour); System.out.print(":"); System.out.print(minute); System.out.println("."); خرج هذا البرنامج هو: The current time is 11:59. لوضع عدة قيم على نفس السطر، من الشائع استخدام عدة تعليمات print ثم تتبعها تعليمة println في النهاية. لكن لا تنسَ تعليمة println على العديد من الحواسيب، يتم تخزين خرج تعليمات print دون عرضه على الشاشة حتى استدعاء println؛ وعندها يظهر السطر كله دفعة واحدة. إذا أغفلت تعليمة println، فقد يعرض البرنامج الخرج المخزن في أوقات غير متوقعة أو ربما انتهى البرنامج دون طباعة أي شيء. العوامل الحسابية العوامل (operators) هي رموز تمثل حسابات بسيطة. مثلًا، عامل الجمع هو +، وعامل لطرح -، والضرب *، والقسمة /. يحول البرنامج التالي الوقت إلى دقائق: int hour = 11; int minute = 59; System.out.print("Number of minutes since midnight: "); System.out.println(hour * 60 + minute); في هذا المثال، لدينا التعبير (expression) التالي: hour * 60 + minute، الذي يمثل قيمة وحيدة بعد الحساب. عند تنفيذ البرنامج، يستبدل كل متغير بقيمته الحالية، ثم تطبق العوامل عليها. تدعى القيم التي تعمل العوامل عليها بالمعاملات (operands). نتيجة المثال السابق هي: Number of minutes since midnight: 719 التعابير هي تراكيب تتألف بشكل عام من أرقام، ومتغيرات، وعوامل. عند ترجمة وتنفيذ التعابير ستنتج لدينا قيمة وحيدة. مثلًا، التعبير 1 + 1 قيمته 2. وفي التعبير hour - 1 تستبدل Java المتغير بقيمته، وبذلك ينتج 11 - 1، الذي قيمته 1. أما في التعبير hour * 60 + minute فيستبدل المتغيران بقيمتيهما، وهذا يعطي 11 * 60 + 59. تنفذ عملية الضرب أولًا، معطية التعبير 660 + 59. بعد ذلك تجرى عملية الجمع التي تنتج 719. عمليات الجمع والطرح والضرب كلها تعمل كما تتوقع منها تمامًا، لكن عملية القسمة قد تفاجئك. مثلًا، نحاول في التعليمتين التاليتين حساب الجزء الذي مضى من الساعة: System.out.print("Fraction of the hour that has passed: "); System.out.println(minute / 60); الخرج هو: Fraction of the hour that has passed: 0 هذه النتيجة تحير الناس عادة. قيمة minute هي 59، وناتج قسمة 59 على 60 هو 0.98333، وليس 0. المشكلة هي أن Java تنفذ عملية "القسمة الصحيحة" عندما يكون المعاملين عددين صحيحين. عملية القسمة الصحيحة تقرب الناتج دومًا إلى العدد الصحيح السابق، حتى في الحالات التي يكون العدد الصحيح التالي أقرب مثل حالتنا هذه. يمكننا كحل بديل حساب النسبة المئوية بدلًا من العدد العشري: System.out.print("Percent of the hour that has passed: "); System.out.println(minute * 100 / 60); الخرج الجديد هو: Percent of the hour that has passed: 98 لقد قربت النتيجة للأسفل هنا أيضًا، لكن النتيجة الآن صحيحة تقريبًا على الأقل. النقطة العائمة هناك حل مناسب أكثر وهو استخدام أعداد النقطة العائمة (floating-point)، التي تمثل الأعداد العشرية كما تمثل الأعداد الصحيحة أيضًا. في Java، يستخدم النوع double (اختصارًا لعبارة double-precision) افتراضيًا لأعداد النقطة العائمة. يمكنك إنشاء المتغيرات من نوع double وإسناد القيم لها باستخدام نفس الصيغ التي استخدمناها للأنواع الأخرى: double pi; pi = 3.14159; تنفذ Java عملية "قسمة النقطة العائمة" (floating-point division) إذا كان أحد المعاملات أو كلاهما من النوع double. وهكذا يمكننا حل المشكلة التي واجهتنا في القسم السابق: double minute = 59.0; System.out.print("Fraction of the hour that has passed: "); System.out.println(minute / 60.0); الخرج هو: Fraction of the hour that has passed: 0.9833333333333333 ورغم فائدة أعداد النقطة العائمة، إلا أنها قد تسبب الإرباك. مثلًا، Java تفرّق بين القيمة الصحيحة 1 وبين القيمة العشرية 1.0، حتى لو بدا أنهما نفس العدد، فهما يختلفان بالنوع، وعلى وجه الدقة، لا يسمح لك بتنفيذ عمليات إسناد بين النوعين. مثلًا، ما يلي ليس مسموحًا لأن المتغير على الطرف الأيسر من النوع int أما القيمة المسندة له على الطرف الأيمن هي double: int x = 1.1; // compiler error من السهل نسيان هذه القاعدة لأن هناك حالات عديدة تحول فيها Java أحد الأنواع إلى النوع الآخر تلقائيًا. مثلًا: double y = 1; // legal, but bad style من المفترض ألا تكون التعليمة السابقة مشروعة، لكن Java تسمح بها عن طريق التحويل القيمة الصحيحة 1 إلى القيمة العشرية 1.0 تلقائيًا. هذا التساهل مريح، لكنه يسبب المشاكل للمبتدئين غالبًا. مثلًا: double y = 1 / 3; // common mistake قد تتوقع أن يعطى المتغير y القيمة 0.333333، وهي قيمة عشرية مشروعة، لكنه في الواقع سيعطى القيمة 0.0. السبب هو أن العبارة على اليمين هي نسبة بين عددين صحيحين، لذلك تجري Java عملية قسمة صحيحة، والتي تنتج القيمة الصحيحة 0. ثم يتم تحويلها إلى قيمة عشرية، الناتج هو 0.0. إحدى الطرق لحل هذه المشكلة (بعد أن تكتشف أن هذه هي المشكلة) هو جعل الطرف الأيمن عبارة عشرية. التعليمة التالية ستعطي y القيمة 0.333333، كما هو متوقع. double y = 1.0 / 3.0; عليك دائمًا إسناد قيم عشرية لمتغيرات النقطة العائمة في كتابتك. لن يجبرك المترجم على ذلك، لكنك لا تعرف أبدًا متى تظهر لك غلطة بسيطة وتعود عليك وبالًا. أخطاء التقريب معظم أرقام النقطة العائمة صحيحة تقريبيًا. يمكن تمثيل بعض الأرقام بدقة، مثل القيم الصحيحة ذات الأحجام المعقولة. أما الكسور الدورية، مثل 1/3، أو الأرقام غير النسبية، مثل π، فلا يمكن تمثيلها بدقة. الفرق بين العدد الذي نريد والعدد الذي نحصل عليه يدعى خطأ التقريب (rounding error). مثلًا، يجب أن تكون التعليمتان التاليتان متكافئتين: System.out.println(0.1 * 10); System.out.println(0.1 + 0.1 + 0.1 + 0.1 + 0.1 + 0.1 + 0.1 + 0.1 + 0.1 + 0.1); لكن الخرج سيكون كما يلي على معظم الحواسيب: 1.0 0.9999999999999999 المشكلة هي أن 0.1، وهو عدد عشري منته في الأساس 10، هو كسر دوري في الأساس 2، ولذلك يكون تمثيله في النقطة العائمة تقريبي حتمًا. وعندما نجمع الأعداد التقريبية معًا تتراكم أخطاء التقريب. الحساب بالنقطة العائمة له مزايا تفوق عيوبه في العديد من التطبيقات، كالرسوميات الحاسوبية، والتشفير، والتحليل الإحصائي، وإظهار (rendering) الوسائط المتعددة. لكن إذا أردت دقة مطلقة، عليك استخدام الأعداد الصحيحة بدلًا منها. خذ على سبيل المثال حساب بنك فيه رصيد قيمته 123.45$: double balance = 123.45; // potential rounding error في هذا المثال، ستصبح الأرصدة غير دقيقة مع الوقت واستخدام المتغير في العمليات الحسابية كالسحب والإيداع. ستكون النتيجة سخط العملاء أو دعاوى قضائية. يمكنك تفادي المشكلة بتمثيل الرصيد كعدد صحيح: int balance = 12345; // total number of cents هذا الحل صحيح طالما أن عدد السنتات لا يتجاوز أكبر قيمة صحيحة يمكن تخزينها، وهي حوالي 2 مليار. العمليات على السلاسل المحرفية بشكل عام، لا يمكنك تطبيق العمليات الرياضية على السلاسل المحرفية، حتى لو كانت السلاسل المحرفية تبدو وكأنها أرقام. التعابير التالية غير مشروعة: "Hello" - 1 "World" / 123 "Hello" * "World" العامل + يعمل مع السلاسل المحرفية، لكنه قد لا ينتج ما تتوقعه. يجري عامل + عملية ربط السلاسل (concatenation) أي دمج المعاملين بوصلهما معًا. وهكذا فإن "Hello" + "World" ستعطي السلسلة "Hello World". أو إذا كان لديك متغير اسمه name من النوع String، فسوف يدمج التعبير "Hello" + "Name" قيمة name مع كلمة الترحيب. بما أن عملية الجمع معرفة للأرقام والسلاسل المحرفية أيضًا، فإن Java تجري عمليات تحويل تلقائية قد لا تتوقعها: System.out.println(1 + 2 + "Hello"); // the output is 3Hello System.out.println("Hello" + 1 + 2); // the output is Hello12 تنفذ Java هذه العمليات من اليسار إلى اليمين. في السطر الأول، 1 + 2 يساوي 3، و 3 + "Hello" يساوي "3Hello". أما في السطر الثاني، Hello" + 1" يساوي "Hello1"، و Hello1" + 2" يعطي "Hello12". ترتيب الحساب عندما يظهر أكثر من عامل في تعبير حسابي فسوف تنفذ حسب ترتيب العمليات (order of operation). بشكل عام، تنفذ Java العمليات حسب ترتيب ورودها من اليسار إلى اليمين (كما رأينا في القسم السابق). لكن Java تتبع قواعد الرياضيات في العمليات الحسابية: عمليتي الضرب والقسمة لهما ”أولوية“ (precedence) على الجمع والطرح. لذا فإن 3 * 2 + 1 سيعطي 7، وليس 9، كما أن 2 / 4 + 2 تعطي 4، وليس 3. إذا كان للعوامل نفس الأولوية فسوف تنفذ بالترتيب من اليسار إلى اليمين. ففي التعبير الحسابي minute * 100 / 60، يتم تنفيذ عملية الضرب أولًا، وإذا كانت قيمة minute هي 59 فسوف ينتج لدينا 60 / 5900، والذي بدوره يعطي 98. لو أن تنفيذ العملية الحسابية جرى من اليمين لليسار، ستكون النتيجة 1 * 59 والذي هو 59، وهو جواب خاطئ. في أي وقت ترغب فيه بتجاوز قواعد الأولوية (أو أنك لم تكن واثقًا من تلك القواعد) يمكنك استعمال الأقواس. يتم تنفيذ العمليات ضمن الأقواس أولًا، لهذا فإن 3 * (2 + 1) يعطي 9. يمكنك استعمال الأقواس أيضًا لجعل العبارات الحسابية أسهل للقراءة، كما في 60 / (minute * 100)، مع أنها لا تغير النتيجة. لا تجهد نفسك في حفظ ترتيب تنفيذ العمليات، خصوصًا مع العوامل الأخرى. إذا لم يكن ترتيب التنفيذ واضحًا عند النظر إلى التعبير، فاستخدم الأقواس لجعله واضحًا. التركيب في الأجزاء السابقة كنا نتعرف على مكونات لغة البرمجة: المتغيرات، والتعابير، والتعليمات بشكل مستقل، دون أن نناقش طريقة استخدامها معاً. أحد أهم ميزات لغات البرمجة هي قدرتها على تركيب (compose) الأجزاء الصغيرة مع بعضها. مثلاً، نحن نعرف كيف نضرب الأرقام ونعرف كيف نعرض القيم. يمكننا دمج هاتين العمليتين في تعليمة واحدة: System.out.println(17 * 3); يمكن استخدام أي تعبير حسابي داخل تعليمات الطباعة. لقد شاهدنا مثالاً على هذا من قبل: System.out.println(hour * 60 + minute); يمكنك أيضاً وضع تعابير حسابية متنوعة على الطرف الأيمن لعملية الإسناد: int percentage; percentage = (minute * 100) / 60; لكن الطرف الأيسر لا بد أن يكون اسم متغير، وليس تعبيراً. ذلك لأن الطرف الأيسر يدل على موقع تخزين النتيجة، والتعابير لا تمثل مواقع تخزينية. hour = minute + 1; // correct minute + 1 = hour; // compiler error قد لا تبهرك القدرة على تركيب العمليات الآن، لكننا سنرى لاحقاً أمثلة تسمح لنا بكتابة حسابات معقدة بشكل مرتب وأنيق. لكن لا تبالغ كثيراً، فالتعابير الكبيرة المعقدة قد تصعب قراءتها وتنقيحها من الأخطاء. أنواع الأخطاء هناك ثلاثة أنواع يحتمل أن تحدث في البرنامج: أخطاء الترجمة. أخطاء التنفيذ. الأخطاء المنطقية. من المفيد التمييز بينها في سبيل تتبعها بشكل أسرع، وقبل أن نتحدث عنها واحدة واحدة، يمكنك الاطلاع على الفيديو الآتي الذي يشرحها بالتفصيل: تحدث أخطاء الترجمة (compile-time errors) عندما تخالف التراكيب النحوية (syntax) للغة Java. مثلاً، يجب أن تكون أزواج الأقواس متناظرة. ولذلك فإن (2 + 1) صيغة مقبولة أما (8 ليست كذلك. في الحالة الثانية، لن تتمكن من ترجمة البرنامج، وسيعرض المترجم رسالة خطأ. تدل رسائل الخطأ التي يعرضها المترجم على موقع حدوث الخطأ في البرنامج عادة، وأحياناً تخبرك بطبيعة الخطأ بدقة. على سبيل المثال، لنعد إلى برنامج hello world: public class Hello { public static void main(String[] args) { // generate some simple output System.out.println("Hello, World!"); } } إذا نسيت الفاصلة المنقوطة في نهاية تعليمة الطباعة، فقد تظهر لك رسالة خطأ كما يلي: File: Hello.java [line: 5] Error: ‘;’ expected هذا جيد جداً: موقع الخطأ صحيح، ورسالة الخطأ تخبرك بالمشكلة. لكن رسائل الأخطاء ليست يسيرة الفهم دوماً. أحياناً يعطي المترجم مكان اكتشاف الخطأ في البرنامج، وليس مكان حدوثه حقاً. وأحياناً يكون وصف المشكلة محيراً أكثر مما هو مفيد. مثلاً، إذا نسيت قوس الإغلاق المعقوف في نهاية main (سطر 6)، قد تحصل على رسالة تشبة الرسالة التالية: File: Hello.java [line: 7] Error: reached end of file while parsing هناك مشكلتان هنا. أولاً، رسالة الخطأ مكتوبة من وجهة نظر المترجم، وليس وجهة نظرك أنت. عملية الإعراب (parsing) هي عملية قراءة البرنامج قبل الترجمة؛ فإذا وصل المترجم لنهاية الملف قبل انتهاء الإعراب، فهذا يدل على نقصان شيء ما. لكن المترجم لا يعرف ما هو. كما أنه لا يعرف أين. يكتشف المترجم الخطأ عند نهاية البرنامج (سطر 7)، لكن القوس الناقص يجب أن يكون على السطر السابق. تحوي رسائل الأخطاء معلومات مفيدة، لذلك عليك محاولة قراءتها وفهمها. لكن لا تأخذها بشكل حرفي تماماً. ستمضي غالباً وقتاً طويلاً خلال الأسابيع الأولى في سيرتك البرمجية وأنت تتابع أخطاء الترجمة. لكن مع زيادة خبرتك، سوف ترتكب أخطاءً أقل وستعثر عليها أسرع. النوع الثاني من الأخطاء هي أخطاء التنفيذ (run-time errors)، وقد سمّيت كذلك لأنها لا تظهر قبل تنفيذ البرنامج. في Java، تظهر هذه الأخطاء عندما ينفذ المفسر شفرة بايت ويحدث خطأ ما. تدعى هذه الأخطاء "استثناءات" (exceptions) لأنها تدل عادة على حدوث شيء استثنائي (وسيء). أخطاء التنفيذ نادرة في البرامج البسيطة التي ستراها في الفصول القليلة الأولى، لذلك قد لا ترى واحداً إلا بعد حين. عند حدوث خطأ تنفيذي، يعرض المفسر رسالة خطأ تحوي معلومات تشرح ما حدث وتحدد مكان حدوثه. مثلاً، إذا أجريت عملية قسمة على صفر عن غير قصد فسوف تظهر رسالة تشبه ما يلي: Exception in thread “main” java.lang.ArithmeticException: / by zero at Hello.main(Hello.java:5) بعض هذه المعلومات مفيد في تنقيح البرنامج من الأخطاء. يتضمن السطر الأول اسم الاستثناء java.lang.ArithmeticException ورسالة تبين ما حدث بدقة أكبر "by zero /". يظهر السطر التالي العملية التي حدث فيها الخطأ؛ حيث يقصد بعبارة Hello.main العملية main في الصنف Hello. كما أنه يذكر أيضاً اسم الملف الذي عرفت فيه العملية (Hello.java) ورقم السطر الذي حدث فيه الخطأ (5). أحياناً تحوي رسائل الأخطاء معلومات إضافية لن تفهم معناها الآن. لذلك سيكون أحد التحديات معرفة الأجزاء المفيدة دون أن تغرق بالمعلومات الإضافية. وعليك أن تنتبه أيضاً أن السطر الذي سبب انهيار تنفيذ البرنامج قد لا يكون السطر الذي يحتاج للتصحيح. النوع الثالث من الأخطاء هو الأخطاء المنطقية (logic error). إذا كان هناك خطأ منطقي في برنامجك، فستتم ترجمته وتشغيله دون تولد أي رسالة خطأ، لكنه لن يعطي الناتج الصحيح المطلوب، بل سينفذ ما طلبته منه حرفياً. مثلاً، هذا برنامج hello world فيه خطأ منطقي: public class Hello { public static void main(String[] args) { System.out.println("Hello, "); System.out.println("World!"); } } هذا البرنامج يترجم وينفذ بشكل سليم، لكن الخرج هو: Hello, World! على فرض أننا أردنا أن يكون الخرج على سطر واحد، فهذا الناتج غير صحيح. المشكلة هي أن السطر الأول يستخدم println، بينما نحن أرنا غالباً استخدام print. قد يصعب التعرف على الأخطاء المنطقية لأنك ستضطر للعمل بالمقلوب: تنظر إلى مخرجات البرنامج وتحاول استنتاج السبب الذي يجعله يعطي هذه النتائج الخاطئة، وكيف تجعله يعطي النتائج الصحيحة. عادة لا يستطيع المترجم ولا المفسر مساعدتك هنا، لأنهما لا يعرفان ما هو الشيء الصحيح المطلوب. ترجمة -وبتصرف- للفصل Variables and operators من كتاب Think Java: How to Think Like a Computer Scientist لكاتبيه Allen B. Downey و Chris Mayfield.1 نقطة