هذا هو الكورس الأول في علوم الحاسب الجامعية: أساسيات البرمجة
, مُدرَّس باستخدام بايثون 3. يفترض عدم وجود خبرة سابقة في البرمجة. كل برنامج في
هذه المذكرة مكتمل وقابل للتشغيل — اكتبه، شغّله، غيّر سطرًا واحدًا، وتنبأ
بماذا سيحدث قبل التشغيل مجددًا. حلقة التنبؤ ثم التشغيل هي المهارة بأكملها.
الكورس عبارة عن سلم:
الوحدات 1.1 إلى 1.3 تبني الآليات: القيم والأنواع، الاختيار، التكرار.
الوحدة 1.4 تُعبئ العمل داخل دوال.
الوحدات 1.5 و1.6 تضيف المجموعات القياسية والملفات مع معالجة الأخطاء.
الوحدة 1.7 هي الانضباط الأعلى: تحليل المشكلات، الاختبار، تصحيح الأخطاء.
كيف تقرأ كل وحدة: قصة قصيرة تقول لماذا هي مهمة؛ صورة أو قاعدة إرشادية
تأتي قبل أي بناء نحوي؛ ثم القواعد الدقيقة؛ ثم أمثلة محلولة تتصاعد صعوبة,
كل منها يتبعها تتبع يمكنك التحقق منه بتشغيل الكود؛ ثم الأخطاء التي يرتكبها الناس فعليًا؛
ثم ملخص من ثلاثة أسطر. كل مثال هنا يمكن التحقق منه بطريقة ثانية —
تشغيلها. قراءة الكود دون تشغيله تشبه قراءة النوتة الموسيقية بدون
سماعها.
1.1
القيم والأنواع والإدخال/الإخراج
تُظهر تطبيق التسوق "4.20" — هل هذا نص أم رقم؟ إذا كان نصاً، فإن جمع
سعرين يعطي "4.203.50"؛ إذا كان رقماً، فيعطي 8.7. ما يحدث يعتمد على
النوع، والوحدة بأكملها 1.1 تتعلم رؤية الأنواع قبل تشغيل أي شيء.
الأسماء هي علامات على صناديق؛ التعبيرات تقرأ الصناديق وتنتج صناديق جديدة
قراءة التعبير هي "افتح الصناديق، احسب، أغلق صندوقاً جديداً": int
أرقام)، float (عشرية)، str (نص)، bool (True/False). الدالة type(...)
تحدد نوع أي قيمة — يمكنك استدعاؤها بحرية أثناء التعلم.
age = 21 # int
price = 4.20 # float
name = "Ada" # str
open_ = True # bool
print(type(age)) # <class 'int'>
المتغيرات هي أسماء مرتبطة بقيم؛ التعيين age = 22 يعيد ربط الاسم —
الأسماء هي ملصقات على صناديق؛ التعبيرات تقرأ الصناديق وتنتج صناديق جديدة
الأسماء هي علامات على صناديق؛ التعبيرات تقرأ الصناديق وتنتج صناديق جديدة
قراءة التعبير تعني "افتح الصناديق، احسب، أغلق صندوقًا جديدًا": count * 3.50
ترقية count = 6 — النتيجة هي int 6، ولا تكون أبداً float 3.50.
القاعدة تعزز int — النتيجة هي float21.0، وليس int 21.
التحويل صريح: int("21") هو 21، لكن "4" + 2 هو TypeError — بايثون
يرفض تخمين ما إذا كنت تقصد "42" أو 6. أخرج بـ print(...)؛ أدخل بـ
input(...)، الذي يُرجع دائمًا نصًا، لذا يجب تحويل الأرقام:
مثال محلول 1 (كاشير المقهى).count = int(input("Coffees? "))، ثم
print("Total:", count * 3.50). عند 6 قهوة يطبع هذا Total: 21.0 — وهو .0
يحدد نوع العائم، لأن int * float يُترقى إلى عائم. مراقبة النوع الخارج من
التعبير هو عادة 1.1 الكاملة. تتبعها بالحالة: input يعيد
النص "6"؛ int(...) يفتح صندوقًا جديدًا يحتوي على int 6؛ عملية الضرب
تُنشئ صندوقًا جديدًا لـ float21.0؛ print يعرضه.
مثال محلول 2 (الحادث الكلاسيكي، المصلح). يجمع مطبوع لافتات عددًا
على رسالة:
قم بتشغيله وترفع Python TypeError: can only concatenate str (not "int") to str —
القاعدة ترفض التخمين. الإصلاح يسمي التحويل صراحةً:
print("Sold " + str(count) + " today")، أو الأسهل print("Sold", count, "today"), which inserts the spaces for you. The lesson to carry: + يعني الجمع
للأرقام، والدمج للنصوص، ولا خلط صامت أبدًا.
أخطاء شائعة. نسيان أن input() تُعطي دائمًا نصًا، لذا
input() * 2 تكرار النص بدلاً من مضاعفة رقم. كتابة 4.20 + 6 و
توقع إجابة int — أي عائم في التعبير يُنتج عائمًا. الثقة في
0.1 + 0.2 == 0.3 (إنها False؛ التقريب الثنائي — يُظهر 1.2 الإصلاح).
ملخص: أربعة أنواع أساسية تحدد كل عملية؛ الأسماء وسوم، والتعيين يعيد الربط؛
التعبيرات تخلط الأنواع بالترقية مع العوادم؛ التحويلات صريحة و
input() تحتاج واحدة.
يجب أن يفرض بوابة الحديقة الترفيهية رسومًا مختلفة للأطفال والكبار وكبار السن — برنامج واحد، مسارات متعددة.
الاختيار هو كيفية اختيار البرنامج: if، elif،
العمر else، طالب: الفرع الحقيقي الأول يحدد السعر
العمر 70، طالب: الفرع الأول الصحيح يحدد السعر
الشروط هي أي تعبير منطقي؛ المقارنات (==، !=، <، >=) والـ
logic (and, or, not) build it. Two rules make every decision readable:
الفروع تُختبر من الأعلى إلى الأسفل؛ الفعل الأول الصحيح هو الفائز والباقي
يتم تجاهلهم.
المسافة البادئة ليست زينة — بل هي كتلة الكود. مسافة واحدة إضافية تغير الخطوط التي
تنتمي إلى الفرع.
temp = 37.5
if temp >= 38:
print("Fever")
elif temp >= 36 and temp < 38:
print("Normal")
else:
print("Low")
مثال محلول 1 (أسعار السينما). تحت 12 أو 65+، يُدفع 5، أما الطلاب فيدفعون 7،
مثال محلول 10 (فئات الدرجات، متصاعدة). نفس الهيكل الأساسي، الآن مع سلسلة
age = int(input("Age? "))
student = input("Student? y/n ") == "y"
if age < 12 or age >= 65:
price = 5
elif student:
price = 7
else:
price = 10
print("Pay", price)
التسلسل مهم: الفرع الأول الصحيح هو الذي يُلعب، ولهذا السبب يسبق التحقق من العمر
تحقق الطلاب — طالب عمره 70 سنة يجب أن يدفع 5، وهذا الترتيب يؤكد ذلك. شغّل
المثال بـ 70 و y لترى المسار الأيسر للمخطط الانسيابي.
مثال محلول 2 (فئات الدرجات، متصاعد). نفس الهيكل الأساسي، الآن مع سلسلة
حيث يحتاج كل elif إلى مقارنة واحدة فقط، لأن الاختبارات التي فوقها قد
فشلت بالفعل:
score = int(input("Score? "))
if score >= 80:
band = "A"
elif score >= 70:
band = "B"
elif score >= 60:
band = "C"
else:
band = "F"
print("Band:", band)
عند 79 يفشل الاختبار الأول وينجح الثاني: Band: B. التصاعد إلى
ملاحظة: لا يحتاج elif score >= 70 أيضًا إلى and score < 80 — الوصول إلى ذلك
السطر يُثبت بالفعل أن النتيجة أقل من 80. الاعتماد على هذا الاندفاع هو
ما يجعل السلاسل قصيرة؛ إعادة اختبار كل شيء هي الطريقة الأطول والأكثر خطأً للمبتدئين
النسخة.
تتطلب المقارنات ذات الفاصلة العائمة حذرًا: 0.1 + 0.2 == 0.3 هي False (الترميز الثنائي
التقريب)، لذا قارن مع هامش خطأ: abs(x - y) < 1e-9.
أخطاء شائعة. كتابة = بدلاً من == — وهو الخطأ الكلاسيكي، وPython
ملخص: الشروط تختار المسارات، الأولى التي تحقق الشرط تكتسب، والمحاذاة هي كتلة الكود؛ ترتيب الاختبارات من المحدد إلى العام؛ مقاربات الأعداد العائمة تتم عبر هامش خطأ، ولا تستخدم SyntaxError.
الحالة الخاصة بعد الحالة العامة، لذلك تفوز العامة دائمًا. استخدام
دفع فواتير elif يدوياً هو مهنة؛ باستخدام حلقة تكرار، هو برنامج. التكرار
تم اكتشافه.
شرط ما يتحقق. السؤال التصميمي دائماً: هل تعرف عدد الرحلات، أم أن شرطاً يقرر؟
اختبارات محددة ثم عامة؛ تقارن الأعداد العشرية بحدود tolerances، ولا تقارن أبدًا بـ ==.
1.3
التكرار: القيام بذلك مرة أخرى
دفع فواتير 5,000 يدويًا هو مهنة؛ باستخدام حلقة تكرار، يكون برنامجًا. التكرار
يعيد العمل: حلقة for تمر على سلسلة معروفة؛ حلقة while تعمل طالما أن
شرط متحقق. السؤال التصميمي دائمًا: هل تعرف عدد الرحلات، أم أن
شرط يقرر؟
total = 0
for i in range(1, 101): # 1..100 — range stops BEFORE its end
total += i
print(total) # 5050
استخدم for عندما يكون عدد الرحلات معروفًا؛ استخدم while عندما يقرر شرط ما. كل
while تحتاج ثلاثة أشياء مرئية في الكود: بداية المتغير، والشرط،
وشيء داخله يقترب من الخروج — وإلا فهي حلقة تكرار لا نهائية
حلقة**.
جدتتبع لحلقة المضروب
n = 5
factorial = 1
while n > 1:
factorial *= n
n -= 1 # the step toward exiting
print(factorial) # 120
جدالتتبع هو عادة التحقق في المساق للحلقات: تابع
المتغيرات جولةً بجولة، على الورق أولاً. بالنسبة لحلقة المضروب:
(n=5, f=1) → (4, 5) → (3, 20) → (2, 60) → (1, 120). قم بإنشاء الجدول يدوياً، ثم
أضف print(n, factorial) داخل الحلقة واترك بايثون يصحح لك.
مثال محلول 2 (بحث مع break، متصاعد). أوجد أول مضاعف لـ
7 الذي يكون أكبر من 100 — عدد الرحلات غير معروف، الشرط يحدد:
n = 100
while True:
if n % 7 == 0:
break # found it — leave the loop now
n += 1
print(n) # 105
التتبع قصير: 100، 101، …، 104 تفشل جميعها الاختبار؛ 105 تنجح وbreak
يخرج. break يغادر الحلقة مبكراً؛ continue يقفز إلى الجولة التالية. كلاهما
أدوات للوضوح — حلقة يجب أن تبحث حتى تجد شيئاً، ثم تتوقف، تكون أكثر
وضوحاً مع break. التصاعد التالي، مضاعفة المال: عند 5% سنوياً، كم تستغرق
1000 لتصل إلى 2000؟
balance = 1000.0
years = 0
while balance < 2000.0: # the condition itself is the goal
balance *= 1.05
years += 1
print(years, round(balance, 2)) # 15 2078.93
خمسة عشر عاماً، وتتوقف الحلقة لحظة انعكاس الشرط — جدالتتبع
سيظهر الرصيد يتجاوز الخط عند 2078.93، وليس الوصول بدقة إلى 2000.
أخطاء شائعة. تعديل القائمة (الوحدة 1.5) أو متغير الحلقة الذي أنت
for-تكرره. range(1, 100) عندما كان المقصود 100 — النهاية مستبعدة.
while whose exit step is missing or commented out: the condition never flips,
وتتجمد البرنامج.
ملخص: for لأعداد الرحلات المعروفة، while للشروط؛ كل حلقة تظهر البداية،
الشرط والخطوة؛ التتبع على الورق، ثم الطباعة بجودة break وcontinue من أجل
المخارج النظيفة المبكرة.
1.4
الدوال: تسمية مهمة مرة واحدة
يظهر نفس حساب السعر في خمسة أماكن؛ تتغير قاعدة الضريبة؛ أربعة من
الخمس يتم تحديثها. الدالة تُجمّع مهمة خلف اسم لتُكتب
مرة واحدة وتُثقى بها في كل مكان: المعاملات الداخل، قيمة الإرجاع الخارج. def
يعرّف؛ الاستدعاء يُنفّذ.
def total_price(count, unit=3.50):
"""Return the total for count items at unit price."""
return count * unit
print(total_price(6)) # 21.0
print(total_price(6, unit=4.0)) # 24.0
يعطي التعريف معاملاً (count، unit)؛ يزوّد الاستدعاء بـ
حجة (6). القيمة الافتراضية (unit=3.50) تجعل الحجة اختيارية.
return تعيد قيمة وتنهى الاستدعاء؛ الطباعة ليست إرجاعاً — دالة
بدون return تُرجع None، والمكلم الذي يحاول إجراء عمليات حسابية عليها
يحصل على TypeError.
كل استدعاء يحصل على نطاق محلي خاص به: الأسماء داخله غير مرئية
خارجه، وتختفي عند انتهاء الاستدعاء. تتتبع الاستدعاءات المتداخلة يقرأ:
المُجاري يتوقف ← المنفّذ يُنفّذ ← قيمة الإرجاع تستقر في المُجاري.
المتصل يتوقف ← الدالة المُستدعاة تعمل ← قيمة الإرجاع تستقر في المتصل.
مثال محلول 1 (الطلب شمل الرسوم).
def add_fee(amount):
"""Return amount plus a fixed 3 pence fee."""
return amount + 3
def order_total(unit_pence, quantity):
"""Return the order total: subtotal plus the fixed fee."""
return add_fee(unit_pence * quantity)
print(order_total(250, 4)) # 1003
العقد في نص التوثيق مهم: بنص كامل داخل، بنص كامل خارج. تتبع
order_total(250, 4): المجموع الفرعي 1000، add_fee يُعيد 1003 — وإطار
يُظهر المخطط أعلاه التوقف والتسليم.
مثال محلول 2 (خوارزمية حقيقية داخل دالة صغيرة، مُصعَّبة).
يعيد is_prime(n)True عندما لا يقسم أي عنصر من 2 إلى $\sqrt{n}$ الرقم n:
def is_prime(n):
if n < 2:
return False
d = 2
while d * d <= n: # only test up to the square root
if n % d == 0:
return False # found a divisor — answer known, stop
d += 1
return True
print([p for p in range(2, 30) if is_prime(p)])
# [2, 3, 5, 7, 11, 13, 17, 19, 23, 29]
تلتقي هنا عادتان في الدوال: إرجاع مبكر return يُنهِي الاستدعاء فور knowing الإجابة
(لا حاجة لمتغير علم)، والحد العلوي للحلقة d * d <= n مستمد من
التفريغ — إذا كان $n = a \times b$ مع $a \le b$، فإن $a \le \sqrt{n}$، لذا فإن اختبار ما وراء $\sqrt{n}$
يعيد اختبار قواسم تم رؤيتها سابقاً. شغّل الكود: القائمة ستكون تماماً الأعداد الأولية الأصغر من 30.
أخطاء شائعة. الطباعة داخل الدالة بدلاً من الإرجاع، مما يجعل النتيجة
غير قابلة لإعادة الاستخدام. نسيان الـ return في أحد المسارات — ذلك المسار يُنتج صامتاً
None. الوصول إلى المتغيرات المحلية للدالة من الخارج؛ فهي تزول عند انتهاء
الاستدعاء.
ملخص: def مرة واحدة، استدعاء من أي مكان؛ المعاملات تدخل، قيمة واحدة تخرج عبر return؛
الإرجاعات المبكرة تُنهي الاستدعاء؛ المتغيرات المحلية تظهر وتختفي مع الاستدعاء؛ وثائق الوصف تحدد
العقد.
1.5
المجموعات: القوائم، القواميس، الأزواج المرتبة، المجموعات
تحتاج كاشير المقهى إلى طلبات اليوم مرتبة، والقائمة حسب الاسم، وموقعاً لا
يجب أن يتغير، ومشروبات يومية فريدة. أربع مهام، أربعة حاويات — الاختيار
بينها هو قرار التصميم في الوحدة 1.5.
القائمة هي تسلسل مرتب وقابل للتعديل: marks = [72, 85, 61]، مُرقَّمة
من 0، ومقطوعة باستخدام marks[1:3]. القاموس يربط المفاتيح بالقيم:
price = {"flat white": 3.5, "tea": 2.8}، تُقرأ وتُكتب بواسطة مفتاح. الزوجة
هي تسلسل ثابت (53.1, -1.5) — مناسبة للإحداثيات التي لا ينبغي تغييرها. الـ
مجموعة تحتوي على عناصر فريدة دون ترتيب: {"a", "b"}.
marks = [72, 85, 61]
marks.append(90) # [72, 85, 61, 90]
best = max(marks) # 90
average = sum(marks) / len(marks) # 77.0
الاقتباس: اسمان، قائمة واحدة
التعيين لا ينسخ أبداً: a = [1]; b = a; b.append(2) يجعل a[1, 2] — القائمة
مشتركة، الأسماء ليست كذلك. هذا الاقتباس يعيد تجميع صناديق 1.1 مرة أخرى، الآن
بوسمين على صندوق واحد، ويشرح القاعدة التالية أيضاً: عند تعديل قائمة أثناء
looping over it skips elements — loop over a copy (for m in marks[:]) or build a
قائمة جديدة.
مفتاح القاموس .get(key, 0) يوفر 0 للمشهد الأول — الصيغة التي
يجعل العد سطرًا واحداً. تحقق يدوياً: "tea" تظهر ثلاث مرات في orders،
والعداد المطبوع يؤكد ذلك.
مثال محلول 2 (الأكثر مبيعاً في اليوم، متدرج). استناداً إلى العدّ،
أفرد العنصر الأعلى وعدده:
best = max(tally, key=tally.get)
print(best, tally[best]) # tea 3
يعتمد المعامل key=tally.get على طلب max لمقارنة العناصر حسب عددها بدلاً من
الترتيب الأبجدي — نفس حيل key= لترتيب أي مجموعة بأي معيار. أهمية
التدرج تكمن في أن البرامج الحقيقية تربط هذه الأدوات معاً (العد ثم الترتيب) بدلاً من
إعادة فحص orders مرتين.
اختيار المجموعة هو قرار التصميم: الطلب + التكرار → قائمة؛ البحث بالاسم → قاموس؛ تجميع ثابت → زوج مرتب؛ التميز → مجموعة.
الاسم ← قاموس؛ التجميع الثابت ← زوج مرتب؛ التفرد ← مجموعة.
افتراض أن tally[item] += 1 ينسخ قائمة؛ بل إنه يُشير إليها.
(KeyError) — .get هو الحل. توقع أن المجموعة أو القاموس يحفظ الترتيب.
بافتراض أن b = a ينسخ قائمة؛ فهو يشار إليها برفق.
ملخص: أربعة حاويات لأربع مهام؛ التعديل يشارك، ولا ينسخ أبدًا؛ .get
كتلة key= هي الحاجز الآمن: مهما حدث داخلها، تُغلق الملف.
تُغلق المقهى، تنقطع الكهرباء — وينجو حصيلة الصباح فقط إذا كان
البرنامج قد كتبه إلى القرص. الملف يدوم أطول من البرنامج. with open(path) as f: opens, closes on exit, and reads text; open(path, "w") يكتب
(ويفرغه أولاً — الحادثة الكلاسيكية).
with open("log.txt", "w") as f:
f.write("opened\n")
with open("log.txt") as f:
for line in f:
print(line.rstrip()) # rstrip removes the trailing newline
حقل with هو سكة الأمان: أي حدث داخله، يُغلق الملف.
القراءة تعطي الأسطر مع أسطر جديدة، لذا .rstrip() يقع في كل حلقة.
مثال محلول 1 (ملف الإعدادات المفقود). قراءة حجم نص من ملف إعدادات
قد يكون مفقودًا، أو قد لا يحتوي على عدد صحيح:
try:
with open("settings.txt") as f:
size = int(f.read().strip())
except FileNotFoundError:
size = 12 # no file yet: a sensible default
except ValueError:
size = 12 # the file holds "big", not a number
print("Text size", size)
شغّله ثلاث مرات — بوضع 16 في الملف، وبدون ملف، وبوضع big في
الملف — وسيقوم بطباعة حجم قابل للاستخدام في كل مرة، عبر ثلاث مسارات مختلفة. هذا هو جوهر الكود المتين: تحديد مسار واحد معقول
التعامل مع الخطأ المتوقع، حيث يمكنك الاستجابة له؛ اترك الباقي ينهار بصوت عالٍ.
له؛ ودع البقية تنهار بصخب.
مثال محلول 2 (حلقة إدخال متينة، متصاعدة). استمر في الطلب حتى يقوم المستخدم بإدخال
عدد صحيح:
عقد الدالة (x) والاستثناء (4) — وهو جوهر التطوير.
يطلب while True مجددًا؛ تنجح الجولة الثانية في int(...) ويخرج return
نسيان 1.3، بحيث تظهر الأسطر مزدوجة التباعد في المخرجات.
ملخص: 1.4 للقراءة والكتابة معًا؛ 1.6 يفرغ أولاً؛ الاستثناءات هي قيم — التقاط النوع المسمي المتوقع، وافتقر بعقلانية، واترك الباقي ينهار.
التصاعد.
أخطاء شائعة.open(path, "w") في المسار الخاطئ: يتم إنشاء الملف أو إفراغه قبل أن تلاحظ.
emptied before you notice. Catching Exception broadly and continuing with broken
state. Forgetting .rstrip(), so output shows double-spaced lines.
ملخص: استخدام with open(...) للقراءة والكتابة؛ استخدام "w" لتفريغ الملف أولاً؛
الاستثناءات هي قيم — التقط النوع المسمى الذي تتوقعه، واستعد بشكل معقول، ودع
البقية تنهار.
فريقان يكتبان نفس التطبيق؛ أحدهما يُسلمه خلال أسبوع، والآخر يغرق في العمل لمدة شهر. الفرق ليس سرعة الكتابة — بل أن كود الفريق السريع مبني من أجزاء صغيرة يمكن إثبات صحتها لكل جزء على حدة، بينما يقوم الفريق البطيء بتصحيح أخطاء تطبيق كامل دفعة واحدة.
difference is not typing speed — it is that the fast team's code is built from small
القيم — مثل البطاريات والمستشعرات ومصادر المنطق وشبكات الانحياز داخل كل مكبر صوتي.
الوحدة 1.7 هي تلك التخصص.
التجزئة تُقسّم المشكلة إلى وظائف لكل منها مهمة واحدة — كل صغيرة
بشكل كافٍ لاختبارها بشكل مستقل. الاختبار يقارن المخرجات الفعلية للوظيفة مع
المُتوقعة، عند الحدود: الصفر، واحد، فارغ، سالب، ضخم.
إن assert لا يُشعل أبداً هو اختبار ناجح. اكتب الاختبارات قبل كتابة
الجسم إن أمكن — فهي العقد القابلة للتنفيذ، والحلقة أعلاه
(أحمر ← أخضر ← إعادة هيكلة) هي هذه العادة التي تعمل باستمرار.
مثال محلول 1 (توسيع الاختبارات مع الوظيفة). قم بتوسيع order_total بخصم
10% على مبلغ £10 — حيث يُكتب الاختبار أولاً عند الحد الجديد:
تحقق من الاختبار الأوسط يدوياً: المجموع الفرعي 1003، وخصم عشر في المئة يعطي 902.7، و
int(...) يتم تقريبه للأسفل إلى 902. لاحظ assertion الأول أيضاً: عند 200 بنس وأربع
أكواب يبقى الإجمالي 803 — تثبت اختبارات الحدود أن الخصم يُشعل
وأنه لا يُشعل مبكراً.
مثال محلول 2 (تقطيع خطأ باستخدام أوامر الطباعة، متصاعد). إحصائيات 1.5
طباعة {'tea': 3} لكن السطر الأكثر مبيعاً يطبع المشروب الخاطئ. الطريقة:
(1) إعادة الإنتاج بأصغر مدخل يفشل؛ (2) طباعة القيم عند الحد
between the trusted part and the suspected part — here, the tally before the max;
(3) إصلاح شيء واحد؛ (4) إعادة تشغيل الاختبارات. نقل أمر الطباعة إلى منتصف الكود
كل تشغيل ينصف البحث: أربعة أوامر طباعة تكشف خطأً في برنامج مكون من ستة عشر سطرًا، ومع ذلك
فإنه يختبئ.
التصحيح هو تحديد الفارق بين ما تعتقد أن الكود يقوم به
وما يقوم به فعليًا — أمر الطباعة عند حدود الثقة/الشك هو الأداة.
أخطاء شائعة. اختبار المسار السعيد فقط: الحدود (الصفر، واحد، فارغ،
سالبة) هي حيث تنهار البرامج. كتابة أسبوع من الكود قبل أول اختبار،
ثم تصحيح جبال. إصلاح شيئين معًا، بحيث لا يعني أي منهما
anything.
ملخص: افكك حتى يختبر كل جزء بمفرده؛ تأكد من الحدود بمجرد وجود دالة
اكتب الاختبار أولاً عندما تستطيع؛ صحح باستخدام التقسيم الثنائي بأوامر الطباعة
عند حدود الثقة — وهي العادة التي يُبنى عليها الدرجة بأكملها.