זהו הקורס הראשון במדעי מחשב באוניברסיטה: יסודות התכנות
, המיועד עם Python 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, ומערבול Python
הכלל מעודד את int — התוצאה היא float21.0, לעולם לא int 21.
ההמרה מפורשת: int("21") הוא 21, אך "4" + 2 הוא TypeError — Python
מסרב לנחש האם התכוונת ל-"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; הכפל
יוצר קופסת float חדשה 21.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, תלמיד: הענף האמתי הראשון קובע את המחיר
התנאי הוא כל ביטוי בוליאני; השוואות (==, !=, <, >=) ו-
לוגיקה (and, or, not) בונות אותו. שתי כללים הופכים כל החלטה לקריאה:
הענפים נבדקים מלמעלה למטה; הענף האמיתי הראשון זוכה ושארם
מוחרצים.
הרווחים אינם קישוט — הם הבלוק. רווח אחד מעלה משנה אילו
שורות שייכות לענף.
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. האמנה בהמשך התוכנית (fall-through) כזו היא
מה שהופך את השרשרות לקצרות; בדיקה מחדש של הכל הוא הגרסה הארוכה והשגויה יותר של חובבן.
גרסה.
השוואות נקודה צפה דורשות זהירות: 0.1 + 0.2 == 0.3 הוא False (עיגול בינארי
), לכן השווה לסף סטייה: abs(x - y) < 1e-9.
שגיאות נפוצות. כתיבת = במקום == — הבאג הקלאסי, ו-Python
דוחה אותו בתנאים (SyntaxError) בדיוק כי הוא נפוץ כל כך. בדיקת
המקרה המיוחד לאחר הכללי, כך שהכללי תמיד מנצח. שימוש ב
elif עם תנאי שלא יכול לעולם להיגש כי ענף קודם כבר
תפס אותו.
סיכום: תנאים בוחרים מסלולים, ה-true הראשון מנצח, התחברות היא הגבלה; סדר
בדיקות ספציפי-לכללי; הצפות משווים לפי סף סטייה, לעולם לא לפי ==.
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) בתוך הלולאה והאפשר ל-Python לדרג אותך.
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. הה escalated הנוספת, הכפלת הכסף: ב-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 שבו חסר שלב יציאה או הוא מוגדר כהערה: התנאי לעולם לא מתהפך,
והתוכנית נתקעת.
סיכום: 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
החוזה בתוך המסביר (docstring) חשוב: פנסים שלמים נכנסים, פנסים שלמים יוצאים. מעקב
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 מסתיימת את השיחה ברגע שהתשובה
ידועה (אין צורך במשתנה סימון), וגבול הלולאה d * d <= n נובע מה
הסקת הנוסחה — אם $n = a \times b$ עם $a \le b$, אזי $a \le \sqrt{n}$, ולכן בדיקה מעבר ל-$\sqrt{n}$
בודק מחלקים שנראו כבר. הרץ אותו: הרשימה היא בדיוק המספרים הראשוניים מתחת ל-30.
טעויות נפוצות. הדפסה בתוך פונקציה במקום החזרת ערך, כך שהתוצאה
לא ניתנת לשימוש חוזר. שכחת ה-return בנתיב אחד — מסלול זה מייצר
None בשקט. גישה למשתנים מקומיים של פונקציה מחוץ לה; הם נעלמים כאשר השיחה
נסתיימת.
סיכום: חזרה אחת ב-def, שיחה בכל מקום; פרמטרים נכנסים, ערך אחד יוצא באמצעות return;
חזרות מוקדמות מסתיימות את השיחה; משתנים מקומיים נולדים ומתים עם השיחה; מסבירים (docstrings) מגדירים את
החוזה.
קופת המכירות של קפה זקוקה להזמנות היומיים בסדר, התפריט לפי שם, מיקום שאינו
צריך לסטות, ומשקאות יחודיים ליום זה. ארבע משימות, ארבע כלים — בחירה
ביניהן היא ההחלטה העיצובית של היחידה 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 שוב, עכשיו
עם תווית כפולה על קופסה אחת, והיא מסבירה גם את הכלל הבא: שינוי ברשימה בזמן
סיור בה דורש דלגת אלמנטים — סרוק על עותק (for m in marks[:]) או בנה
רשימה חדשה.
המפתח ה-.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() מתאים לכל לולאה.
שגיאות הן ערכים שמטביע Python כ-Exception: FileNotFoundError,
ValueError, KeyError, TypeError. try/except תופס סוג ממונה — לעולם לא
except: חשוף שמסתיר באגים אמיתיים.
דוגמה מודגמת 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")⟩ במסלול הלא נכון: הקובץ נוצר או
מתפנה לפני שתשים לב. לכידת ⟨Exception⟩ בצורה רחבה והמשכה עם
מצב פגום. שוכחים ל.rstrip(), ולכן התוצאה מציגה שורות בעלות רווח כפול.
סיכום: ⟨with open(...)⟩ לקריאה וכתיבה; ⟨"w"⟩ מפנה קודם כל;
שגיאות הן ערכים — לכיד את הסוג הממונה הצפוי, היכנע באופן הגיוני, והיתר
השאר נכשל.
שתי צוותות כותבות את אותו אפליקציה; אחת מושלמת אותה בשבוע, והשנייה טובעת במשך חודש. ההבדל
אינו מהירות הקלדה — אלא כך שהקוד של הצוות המהירה בנוי מחלקים קטנים
שהם יכולים להוכיח כל אחד מהם כנכון בעצמו, בעוד שהצוות האיטית מתקנת שגיאות באפליקציה שלמה בו-זמנית.
יחידת 1.7 היא המשמעת הזו.
פירוק מפצל בעיה לפונקציות עם משימה אחת בכל אחת — כל אחת קטנה
לספיק כדי לבדוק אותה בנפרד. בדיקה משווה תוצאת ביצוע בפועל של פונקציה ל
המצופה, בגבולות: אפס, אחד, ריק, שלילי, ענק.
יחידת assert שלא פעילה מעולם היא בדיקה עוברת. כתבו את הבדיקות לפני שתכתבו את
הגוף כשהאפשרות קיימת — הן החוזה שהפך לביצועי, ולולאה למעלה
(אדום → ירוק → עריפת קוד) היא ההרגל הזה פועל ברציפות.
דוגמה מפורשת 1 (הרחבת הבדיקות לצד הפונקציה). הרחיבו את order_total עם
הנחה של 10% מעל £10 — הבדיקה נכתבת תחילה, בגבול החדש:
בדוקו את הבדיקה האמצעית ידנית: סך חלקי 1003, הנחה של עשר אחוזים נותנת 902.7, ו
int(...) מעוגל כלפי מטה ל-902. שים לב גם לאסרט החשוב הראשון: ב-200 פניס וארבע
כוסות, הסך הכול נשאר 803 — מבחני הגבול מוכיחים גם שההנחה מופעלת
גם שאינה מופעלת מוקדם מדי.
דוגמה מודגמת 2 (חלוקה לשיניים של שגיאה עם הדפסות, חריגה). הספירה מ-1.5
הדפסות {'tea': 3} אך קו המכר ביותר מדפיס את המשקה הלא נכון. השיטה:
(1) לשחזר עם הקלט הכושל הקטן ביותר; (2) להדפיס את הערכים בגבול
בין החלק המאומת לחלק המוטרד — כאן, הספירה לפני ה-max;
(3) לתקן דבר אחד; (4) להריץ מחדש את הבדיקות. הזזת ההדפסה באמצע הקוד
בכל ריצה מחצית את החיפוש: ארבע הדפסות מוצאות שגיאה בתוכנה בעלת שש עשרה שורות, אך
ככל שהיא מסתרת.
תיקון שגיאות הוא מציאת ההפרש בין מה שמשתמרים התוכנית עושה
ובין מה she עושה בפועל — ההדפסה בגבול האמון/החשד היא הכלי.
שגיאות נפוצות. בדיקה רק במסלול השמח: הגבולות (אפס, אחד, ריק,
שלילי) הם המקום בו תוכניות נשברות. כתיבת שבוע של קוד לפני הבדיקה הראשונה,
ואז תיקון שוריית גבולות. תיקון שני דברים בו-זמנית, כך שאף אחד מהתוצאות לא משמעותי
כל דבר.
סיכום: פירוק עד כל חלק בודד נבדק לבדו; ביצוע אסרט על הגבולים ברגע שקיימת
פונקציה; כתיבת הבדיקה לפני הקוד כאשר אפשר; תיקון שגיאות באמצעות חלוקה לשיניים עם הדפסות
בגבולי האמון — הרגל שעליה נבנה כל תואר לימודים.
שיעורים אינטראקטיביים בנושא זה
לעבור על הדברים צעד אחר צעד, עם תרגילים לבדיקה מיידית.