הבלוג של ינון פרק

טיפים קצרים וחדשות למתכנתים

לכתוב הוראות לעצמך

17/03/2020

אחת הטכניקות היותר יעילות בלימוד נושא חדש מתבססת על הרעיון שכדאי לנו מאוד להיות האנשים שכותבים את ההוראות במקום רק לעקוב אחר הוראות. הקפיצה הזו - ממעקב אחר הוראות לכתיבת הוראות נותנת לכם הבנה הרבה יותר טובה של הדבר שאתם לומדים (לא משנה מהו).

לכן אם לדוגמא החלטתם ללמוד ריאקט ונכנסתם לקורס פה באתר, מה שרוב האנשים יעשו זה לראות את שיעורי הוידאו ואז ללכת לנסות לפתור את התרגיל. הבעיה שזה ממש קשה ולא יעיל.

במקום זה כדאי להתחיל להתאמן הרבה לפני התרגיל: מיד אחרי שצופים בוידאו הדבר הכי טוב לעשות הוא לנסות לשחזר אצלכם על המכונה בדיוק את מה שראיתם. אבל השוס האמיתי יהיה לא לעצור שם, ואחרי שהצלחתם לשחזר את הוידאו אצלכם על המכונה ללכת ולכתוב לעצמכם הוראות חדשות (על דף) בהן אתם מסבירים לעצמכם איך לבנות את מה שהרגע בניתם. אחרי שיש לכם את ההוראות תוכלו למחוק את כל הפרויקט ולנסות מחדש, והפעם להיעזר בהוראות שלכם.

המעבר מצפיה סבילה בוידאו לניסיון פעיל למצוא את הדרך הטובה ביותר להסביר את זה הוא קשוח. אנחנו רגילים לחשוב שלמידה זו פעולה סבילה, שגם בוידאו, כמו בכיתה, מישהו צריך להסביר לנו ואנחנו רק צריכים לשבת ולספוג. אבל האמת שאם בכיתה זה עוד איכשהו עובד לחלק מהאנשים, בוידאו זה עובד הרבה פחות טוב.

לאור הקורונה והעובדה שלמידה מרחוק היא כאן כדי להישאר, הגיע הזמן לבנות הרגלי למידה מרחוק טובים יותר. ולכתוב לעצמכם את ההוראות זו התחלה מצוינת.

שאלות מראיונות עבודה: פונקציות ב JavaScript

16/03/2020

שאלת ראיונות עבודה פשוטה על פונקציות שנתקלתי בה לא מזמן ואפילו הצליחה לבלבל חבר - מה ההבדל בין שתי שורות הקוד הבאות, וכיצד נכתוב פונקציה add שתגרום לשתיהן לעבוד במכה אחת:

    add(2, 5); // 7
    add(2)(5); // 7

השאלה מעניינת כי היא עוזרת לנו להבין משהו על ערכי החזר של פונקציות ועל רעיון שנקרא Currying. אבל קודם קצת הסבר על שתי צורות ההפעלה:

  1. בשורה הראשונה אני פשוט מפעיל את הפונקציה עם שני פרמטרים ומצפה לקבל חזרה את סכומם.

  2. בשורה השניה יש כבר שתי הפעלות. כאן אנחנו רואים שאם העבירו רק פרמטר אחד לפונקציה אז אנחנו צריכים להחזיר פונקציה חדשה שתמיד תוסיף את ערך פרמטר זה לפרמטר שהיא מקבלת ומחזירה את התוצאה. דרך אחרת לכתוב את השורה השניה תהיה:

const add2 = add(2);
// now add2 is a new function

const result = add2(7);
// now result is 7

דרך קלה לכתוב את הקוד היא להתמקד בעובדה שאנחנו מדברים על פונקציה שמקבלת שני פרמטרים ולהסתכל ממש על מספר הפרמטרים, או במילים אחרות לכתוב את הקוד הבא:

function add(x, y) {
  if (arguments.length === 2) {
      return x + y;
  } else if (arguments.length === 1) {
    return y => add(x, y);
  }
}

console.log(add(2, 5));
console.log(add(2)(5));

עוד צעד קדימה יכול להיות להוציא החוצה את החלק בקוד שמתעסק בהפעלה חלקית של הפונקציה לפונקציה נפרדת, למשל נוכל לקרוא לה partialify:

function partialify(f) {
  const requiredArgsCount = f.length;

  return function(...args) {
    if (args.length === requiredArgsCount) {
      return f(...args);
    } else {
      return f.bind(null, ...args);
    }
  }
}

const add = partialify(function add(x, y) {
  return x + y;
});

console.log(add(2, 5));
console.log(add(2)(5));

עכשיו אפשר להפעיל את הקוד גם על מקרים מתוחכמים יותר אבל שימו לב שהפיתרון עדיין מוגבל להפעלה חלקית אחת בלבד לפונקציה, כלומר הקוד הבא לא עובד:

const add = partialify(function add(x, y, z) {
  return x + y + z;
});

console.log(add(2)(5)(7));

נסו לראות שאתם מבינים למה, ואם כן נסו לתקן את הקוד של partialify כדי שכן יעבוד גם במקרה הכללי ביותר. הצלחתם? מוזמנים לשתף את הפיתרונות בתגובות.

נ.ב. את התרגיל לקחתי מהדף הזה שכולל רשימה ארוכה וטובה של שאלות ראיונות עבודה למתכנתי Front End. אם אתם אוהבים כאלה משחקים שווה להעיף שם מבט גם.

עזבו את טמקא - הנה אליאס פשוט שיגיד לכם כמה חולי קורונה יש בארץ

15/03/2020

אחד הדברים הממכרים בחיים המודרניים נקרא הסחות דעת. אתם יודעים זה הקטע שאנחנו קופצים לפייסבוק רק כדי לראות את השטויות שחברים משתפים במקום לסיים לפתור את הבאג שעוד רגע אנחנו פותרים. ובתקופות לחוצות רק טבעי שיכולת הריכוז יורדת ובמקום לפתור באגים אנחנו קופצים ל ynet רק כדי לראות כמה חולי קורונה כבר יש בארץ.

בקיצור אם גם לכם יש את הבעיה הזאת תשמחו לדעת שלא צריך יותר לעזוב את הטרמינל או ללכת ל ynet. גם לנתוני הקורונה יש API ועם אליאס קצר אנחנו יכולים לקבל את המספר בשניה מתוך שורת הפקודה. הפקודה מסתבר היא פשוט:

$ curl 'https://lab.isaaclin.cn/nCoV/api/area?latest=1&provinceEng=Israel' 2>/dev/null | jq '.results[0].confirmedCount'

ונכון לכתיבת שורות אלה המספר עומד על 154. כמובן שאנחנו לא מתכוונים לכתוב את כל השורה הארוכה הזו שוב ושוב, ולכן אפשר ליצור אליאס:

alias cocount="curl 'https://lab.isaaclin.cn/nCoV/api/area?latest=1&provinceEng=Israel' 2>/dev/null | jq '.results[0].confirmedCount'"

ומפה מספיק לכתוב cocount כדי לראות כמה מקרים יש, להיבהל או להירגע ולחזור לתקן באגים.

נ.ב. כתבתי פה פעם מדריך ליצירת בוט לטלגרם. אם נתקעתם בבית ואתם יותר מדי בלחץ מהקורונה בשביל לעבוד, נסו לחבר בין הפוסטים ולכתוב בוט לטלגרם שישלח לכם ולחברים עדכוני קורונה מלחיצים.

סקרנות

14/03/2020

הגישה הקלאסית להתמודדות עם בעיה, זו שלמדתם בבית ספר ותרגלתם שנה אחר שנה היא שבעיה זה משהו שצריך לפתור. לפי גישה זו החיים מלאים בתרגילים ומבחנים, המטרה של מבחן היא לבדוק שאנחנו יודעים את התשובה והמטרה שלנו בהתמודדות עם תרגיל או מבחן היא להגיע לתשובה הנכונה. הסקרנות, העניין והפיתרון היצירתי הם לא המטרה ובדרך כלל נדחקים הצידה.

בתרגום לקוד ילדים וגם מבוגרים מתבלבלים ומנסים ליישם את אותו עיקרון: מוצאים מה צריך לבנות, מחפשים דרך קצרה להגיע לשם ומתקנים כשדברים לא עובדים. עובד? מעולה, אפשר להמשיך למשימה הבאה. המחשבה של "אוקיי, זה עבד, עכשיו ננסה בעוד כמה דרכים כדי ללמוד עוד קצת על הבעיה" נדחקת הצידה. ללמוד עוד על הבעיה זאת לא המטרה.

הבעיה שבתור מנהלים לעתים נדירות אנחנו מחפשים עובדים שרק יבצעו משימות, ובתור עובדים הדבר האחרון שאנחנו רוצים זה לעבוד במפעל תיקון באגים ולהסתכל על מערכת בתור אוסף משימות שצריך לפתור. לאורך זמן זה פשוט לא מספיק מעניין.

האלטרנטיבה? להסתכל על הבעיה מתוך סקרנות, כשהיעד הוא לא להגיע לפיתרון אלא להגיע להבנה. לשים בצד את הפיתרונות המהירים מ Stack Overflow ולקרוא בשמחה את דף התיעוד המלא; לנסות לשנות את התוכנית גם אחרי שהיא עובדת ולשאול "מה עוד אני יכול לבנות עם זה?". זה ייקח זמן להתרגל ויש סיכוי שבהתחלה הבוסים לא יבינו למה אתם עובדים יותר לאט לאחרונה, אבל לאורך זמן זו הדרך הבטוחה והטובה ביותר להשתפר.

הפקודה id ב Python

13/03/2020

הפקודה id ב Python מחזירה מספר מזהה ייחודי של הדבר שנתתם לה. פקודה זו יכולה לעזור לנו להבין שינויים במהלך חיי האוביקט ולשים לב להבדל חשוב בין פעולות של שינוי מידע לשינוי משתנה. בואו נראה אותה בפעולה דרך מספר דוגמאות.

את הפקודה id אתם יכולים להפעיל על כל אוביקט פייתון:

>>> id('hello')
4298282256

>>> id([10, 20, 30])
4298103336

>>> id(4)
140548070459824

אם נפעיל את הפקודה מספר פעמים על אותו מידע נקבל תמיד את אותו ערך:

>>> id(5)
140548070459800
>>> id(5)
140548070459800
>>> id(5)
140548070459800
>>>

וזה עובד גם במבני נתונים מורכבים יותר:

>>> l = [10, 20, 30]
>>> id(l)
4298103336
>>> id(l)
4298103336
>>> id(l)
4298103336

אבל שימו לב מה קורה כשאני מנסה להפעיל את הפקודה על מידע חדש, אפילו שמבחינת הערך שלו הוא זהה לגמרי למידע הקודם:

>>> l = [10, 20, 30]
>>> t = [10, 20, 30]
>>> id(l)
4298159096
>>> id(t)
4298103336
>>>

למרות ששתי הרשימות זהות מבחינת הערכים שלהן, המזהה של הרשימה עצמה שונה מה שאומר לנו שמדובר בשתי רשימות שמתנהלות באופן עצמאי. שינוי ערכים ברשימה אחת לא ישפיע על הרשימה השניה.

ב Python יש לנו שני סוגי פעולות שאפשר להפעיל על משתנים וש id תעזור לנו לזהות טוב את ההבדל ביניהן: סוג אחד הוא פעולות המשפיעות על המשתנה והסוג השני הוא פעולות המשפיעות על המידע. כך הקוד הבא משפיע על המשתנה x - לפני הרצת הקוד הוא היה השם של המספר 4, ואחרי הרצת הקוד הוא הפך להיות השם של המספר 5:

>>> x = 4
>>> id(x)
140548070459824
>>> x += 1
>>> id(x)
140548070459800
>>>

מצד שני ברשימות אנחנו יכולים להשתמש בשני סוגי הפעולות. הקוד הבא החזיק ב x את הרשימה 10, 20, 30, 40; ואחר כך רשימה חדשה בה נוסף גם המספר 50:

>>> x = [10, 20, 30, 40]
>>> id(x)
4298242672
>>> x = x + [50]
>>> id(x)
4298242600
>>>

לעומת זאת הקוד הבא משנה ממש את הרשימה ש x מתיחס אליה, בלי לשנות את המשתנה x עצמו:

>>> x = [10, 20, 30, 40]
>>> id(x)
4298242672
>>> x += [50]
>>> id(x)
4298242672
>>>

ההבדל בין שני סוגי הפעולות בא לידי ביטוי בתוכנית אמיתית אם יש לנו משתנה נוסף שמצביע על אותו הדבר. מסתבר שכשאתם משנים את הערך (כלומר ה id נשאר זהה אחרי הפעולה), כל השמות האחרים של אותו מידע יכילו עכשיו את הערך החדש. לעומת זאת כשמשנים את המשתנה השמות האחרים עדיין מצביעים על הדבר הישן, ולא משתנים.

במילים אחרות בקוד הבא המשתנה y יכיל אחרי ריצת הקוד גם את המספר 50:

>>> x = [10, 20, 30, 40]
>>> y = x
>>> x += [50]
>>> y
[10, 20, 30, 40, 50]

לעומתו בקוד הבא המשתנה y לא יושפע מהפעולה וימשיך להתיחס לרשימה הישנה:

>>> x = [10, 20, 30, 40]
>>> y = x
>>> x = x + [50]
>>> y
[10, 20, 30, 40]

כך הפקודה id ב Python, למרות שבדרך כלל לא נשתמש בה בתוך תוכנית אמיתית, יכולה לעזור לנו להבין מה הקוד שלנו עושה ולמצוא באגים שנובעים משינוי מידע שלא התכוונו לשנות.

מה לעשות כשמקבלים לינק חשוד בווטסאפ

12/03/2020

השבוע קיבלתי את ההודעה הבאה לווטסאפ:

שופרסל לכבוד "יום שישי השחור" בחודש נובמבר, מחלק את הקופונים החופשיים בשווי 900 ש"ח. קיבלתי את הקופון https://t.co/7MH01rxfwM

לא ברור למה כל הספאמרים של העולם עדיין מתפקדים ועדיין שולחים את השטויות שלהם בכל מיני תחפושות, אבל האמת שהם היו פה הרבה לפנינו וכנראה יישארו גם אחרינו אז עדיף שנלמד להתגונן, ולכן המדריך היום "מה לעשות כשמקבלים לינק חשוד".

הנחת עבודה ראשונה היא שאתם אנשים סקרנים שרוצים ללמוד מי שולח לכם לינקים ומה הוא רוצה. אם יש לכם דברים יותר טובים לעשות עם הזמן שלכם הדבר הכי טוב לעשות כשמקבלים לינק חשוד יהיה למחוק ולהתעלם.

הנחת עבודה שניה היא שמדובר בלינק שצריך ללחוץ עליו. זה לא מובן מאליו והיום יש הרבה לינקים שרק מעצם זה שמתקבלים אצלכם במכשיר כבר קורה משהו רע. זה קורה בגלל שתוכנות כמו ווטסאפ מנסות לבד להיכנס ללינקים בשמכם ולהביא חלק מהתוכן. לפעמים אפילו מעט התוכן שהן מביאות מספיק זדוני כדי לשבור לכם את המכשיר או להתקין תוכנת ריגול. אם זה המצב אין לי איך לעזור לכם.

לכן כותרת יותר מדויקת למדריך הזה תהיה "מה לעשות כשמקבלים לינק חשוד שלא שבר לי את המכשיר אבל כנראה מוביל לאתר ספאם חובבני ואני סקרן לדעת מה יש שם, מי בנה את האתר ומה הם רוצים". עם זה אני יכול לעזור לכם.

נחזור להודעה שקיבלתי ונלך לבדוק מאיפה הלינק הגיע. הדומיין t.co הוא דומיין של טוויטר. הם משתמשים בו כדי לקצר כתובות אינטרנט ארוכות כך שיכנסו בציוץ. קל למצוא את זה בגוגל אם מחפשים what is t.co וזה דף ההסבר של טוויטר על הלינקים האלה:

https://developer.twitter.com/en/docs/basics/tco

שימוש במקצרי כתובות הוא פרקטיקה נפוצה אצל ספאמרים שלא רוצים לספר מה הכתובת האמיתית שלהם. בעזרת האתר http://checkshorturl.com/expand.php אפשר לפתוח לינקים מקוצרים מסוג זה ובמקרה שלנו לגלות שהלינק מוביל ל:

https://lvreceitas.site/il-shuffersal-1/?w 

הכתובת lvreceitas.site לא נראית כאילו הגיעה משופרסל, אבל אני עדיין לא בטוח מה כן יש שם. לכן לפני שנכנס נפעיל whois קצר:

% whois lvreceitas.site
% IANA WHOIS server
% for more information on IANA, visit http://www.iana.org
% This query returned 1 object

refer:        whois.nic.site

domain:       SITE

organisation: DotSite Inc.
address:      F/19, BC1, Ras Al Khaimah FTZ
address:      P.O Box # 16113, Ras Al Khaimah - 16113.
address:      United Arab Emirates

contact:      administrative
name:         Shweta Sahjwani
organisation: DotSite, Inc
address:      F/19, BC1, Ras Al Khaimah FTZ
address:      P.O Box # 16113, Ras Al Khaimah - 16113.
address:      United Arab Emirates
phone:        +91.2230797500x8522
fax-no:       +91.2230797508
e-mail:       admin@radixregistry.com

ונגלה שהדומיין רשום על חברה באיחוד האמירויות, שזה כבר לא סימן טוב אבל אולי לא נורא, והשרת יושב בכתובת 77.72.1.15 שממוקמת בלונדון (את הכתובת מצאתי עם dig, ובשביל לגלות שהיא בלונדון הלכתי לאתר https://www.iplocation.net/).

השלבים הבאים בחקירה שלנו יהיו לגלות עוד קצת מידע על lvreceitas.site. תחילה נחפש בגוגל אם הם מופיעים ואם יש עוד דברים מעניינים באתר שלהם באמצעות הכנסת הטקסט הבא בתיבת החיפוש של גוגל: inurl:lvreceitas.site. במקרה שלנו אנחנו מוצאים שם עוד הטבה שנראית פיקטיבית של המוסד לביטוח לאומי, ועוד כעשרים הטבות של אתרים בחו"ל.

אפשר גם להמשיך ולבדוק את תעודות ה SSL של האתר באמצעות הפקודה:

$ openssl s_client -showcerts -connect lvreceitas.site:443

תקבלו הרבה פלט על המסך אבל המילה שופרסל לא מופיעה בו. שוב זה הגיוני כי הדומיין הוא לא של שופרסל ולא נראה שקשור אליהם בשום צורה.

התחנה האחרונה לסקרנים היא האתר https://www.site-shot.com/ שייקח תמונת מסך של כל אתר בלי שתצטרכו להיכנס אליו. זה נחמד כי ככה תוכלו לראות מה מנסים למכור לכם, למרות שבדרך כלל במיזמים כאלה אנשים ישכפלו ממש קמפיין אמיתי ולכן לדעתי לא נראה הבדל אמיתי בין אתר הספאם לבין אתר הקמפיין המקורי.

אז אומנם על השאלה הגדולה "מה הם רוצים" לא הצלחנו לענות, אבל אולי זה בעצם לא כזה משנה. הם רוצים לדעת מי החברים שלך, לכמה אנשים אתה שולח את ההודעה, כמה מהם באמת נכנסו ואולי בעתיד לנסות לשלוח לכם עוד הודעות כי הם יודעים שלחצתם. 900 שקל לקניות בשופרסל לא תראו מהם.

מדיניות Referer

11/03/2020

אחת הטעויות המצחיקות של האינטרנט היא הכותרת referer (שגיאת הכתיב מכוונת). אבל חוץ מלהיות תזכורת לעובדה שקשה מאוד לתקן טעויות אחרי שכולם מתחילים לעבוד בדרך מסוימת, רפרר גם עלולה לסכן ממש את המשתמשים שלכם.

תקופה ארוכה ברירת המחדל של דפדפנים היתה שבכל פעם שאנחנו מבקרים באתר אנחנו שולחים לאותו אתר גם את כתובת האינטרנט הקודמת שהיינו בה. הרעיון היה לעזור לבעלי אתרים להבין מי מפנה אליהם תנועה וכך אנשים יוכלו לדעת למי לשלוח ברכות לחג.

התנהגות זו נשמעת תמימה אבל יש בה מספר בעיות - אפילו אם נשים בצד את המשתמשים שאולי לא רוצים שכל אתר ידע איפה הם היו קודם (אם אתם כאלה אתם בטח כבר יודעים איך לבטל את שליחת ה Referer בהגדרות הדפדפן) - עדיין יש לנו בעיה עם כתובות אינטרנט המשלבות מידע אישי.

נסו למשל להעתיק קישור מדרופבוקס לגישה ישירה לקובץ. התוצאה היא משהו שנראה כך:

https://www.dropbox.com/s/4g6hce1gs57un9g/%D7%9C%D7%95%D7%97%20%D7%97%D7%95%D7%A4%D7%A9%D7%95%D7%AA%20%D7%AA%D7%A9%D7%A2%D7%96.doc?dl=0

את הקישור הזה אני כנראה רוצה לשמור בסוד ולתת אותו רק לחברים ספציפיים שצריכים לגשת לקובץ. עכשיו נניח שחבר כזה שיש לו את הקישור נכנס דרכו לדרופבוקס ואז ממשיך לאתר חדש, והדפדפן שלו שולח לאתר החדש את הכתובת "הקודמת" שהיה בה, אז הכתובת הקודמת כוללת מידע אישי ומנהל האתר החדש יכול לראות את הקישור ואף לגלוש באמצעותו לקובץ.

לכן דפדפנים תומכים היום בתגית meta שעוזרת להם להבין האם צריך או לא צריך לשלוח מידע בשדה Referer ואיזה מידע בדיוק צריך לשלוח. אתם יכולים לדוגמא לשתול ב HTML שלכם את הקוד הבא:

<meta name="referrer" content="no-referrer">

ואז הדפדפן לא ישלח בכלל כותרת Referer לאתר הבא שמשתמש יגיע אליו. אפשרות טובה נוספת היא המדיניות origin כלומר התגית:

<meta name="referrer" content="origin">

שתגרום לדפדפן לשלוח כותרת Referer אבל רק עם שם הדומיין בלי כתובת הדף הספציפי ממנו הגולש הגיע.

לאופציות נוספות ומידע נוסף על Referer שווה לבקר בדף התיעוד מ MDN.

אני אתחיל ב...

10/03/2020

יש המון חומרי לימוד באינטרנט ובעיה אמיתית להבין איזה מדריך יעזור לנו ללמוד הכי מהר את מה שאנחנו צריכים ללמוד. אחת הדרכים היא להסתכל על המרחק כלומר לראות איפה המדריך מתחיל ומה אבנה בו, ומתוך זה להבין כמה אני הולך ללמוד.

לדוגמא לא מזמן מצאתי מדריך שמסביר איך לזהות רגשות מתוך משפטים באמצעות AI. זה מדליק, והרבה אנשים (גם אני) חושבים לעצמם - אוקיי אני אתחיל בלהבין איך לזהות רגשות מתוך משפטים, ומתוך זה אני כבר אצליח להמשיך ולהבין איך AI עובד.

ואותו הגיון מופיע בכל דבר שאנחנו רוצים ללמוד:

  • אני אתחיל בלבנות אפליקציה עם React ו Redux, ומתוך זה אני כבר אבין איך ריאקט עובד

  • אני אתחיל בלהתקין שרת Linux עם nginx ו Web Application שכתבתי וזה כבר ייתן לי רעיונות לאיך Linux עובד.

  • אני אתחיל בלהעביר את הפרויקט שלי ל git ואחרי כמה שבועות בטח אבין איך גיט עובד.

הבעיה עם ההגיון הזה היא שבתוכנה זה לא ממש עובד. כשאנחנו כותבים קוד קשה לנו לראות את פערי הידע שאנחנו צוברים במהלך הכתיבה, ובסיום ה Tutorial כשיש לנו מערכת שעובדת קל להגיד לעצמך "אני בניתי את זה, אני יודע את זה". האמת היא שיש פער עצום (בתוכנה, אולי גם בתחומים אחרים אין לי מושג) בין מי שיודע לכתוב קוד לפי ההוראות לבין מי שיודע לכתוב את ההוראות. ב Tutorial אנחנו מנסים בכל שלב להבין את המינימום שצריך בשביל שנוכל לעבור לשלב הבא, כדי שנוכל בזמן נתון לבנות את הדבר הכי גדול שאפשר.

במקום זה מה שכן עובד לי היא הגישה ההפוכה: הנה שני דברים קטנים שאפשר לעשות עם React (בלי create-react-app, בלי TypeScript, בלי Redux, בלי MobX, בלי useEffect ובלי Styled Components). בוא נראה כמה דברים מעניינים אני מצליח לבנות רק עם שני הדברים הקטנים האלה. וכך, לאט לאט, אני מוסיף כל פעם עוד מילה חדשה ורואה איך היא משתלבת בדבר שאני בונה. הכלל היחיד - לפני שמוסיפים את המילה הבאה מנסים למצוא את מקסימום האפשרויות שאפשר לבנות עם הדברים שלמדנו עד עכשיו, כדי שנוכל להבין באמת את הכלים בהם אנחנו משתמשים.

אין מצב שזה אי פעם עבד

09/03/2020

כשאני מתחיל להסתכל בקוד בחיפוש אחר באג, לעתים קרובות אני אפעיל git blame כדי לראות מי הכניס את הבאג הזה למערכת (זה בדרך כלל אני) ולמה (זו בדרך כלל תהיה הודעת קומיט גנרית להחריד). יותר מדי פעמים, ובמיוחד במערכות גדולות, אני הולך לגלות שהבאג היה שם חודשים ארוכים ואולי אפילו שנים. אז איך זה שעד עכשיו אף אחד לא התלונן?

התשובה כמובן היא שלא כל באג בא לידי ביטוי. הנה תוכנית פייתון קצרה שמקבלת מספר ומדפיסה אותו בבינארי:

import sys

def print_binary(n):
    if n > 1:
        print_binary(n // 2)

    print(n % 2, end="")

num = sys.argv[1]
print_binary(int(num))
print()

היא עובדת ותדפיס לכם את הייצוג הבינארי של כל מספר שתעבירו כקלט. או לפחות כל מספר מספיק קטן, כי בגלל הרקורסיה הפונקציה שלנו לא תעבוד על מספרים גדולים מדי.

ברוב המקרים המצב אפילו יותר גרוע: הבאג יתחיל להופיע רק כשתשדרגו איזו ספריה, תעברו מערכת הפעלה, תתחברו לשרת מיותר לקוחות במקביל או תגיעו לשנה מסוימת. וזו אולי הסיבה הכי חשובה לכתוב בדיקות אוטומטיות: הבדיקה תזהה את הבאג בשניה שהוא יתחיל להשפיע, ולפני שהלקוחות יראו את הבעיה.

שברת קיבלת

08/03/2020

החלק הכי קשה בללמוד משהו חדש הוא המעבר מ"אני יודע לבנות לפי ההוראות" ל"אני יודע לכתוב את ההוראות", או היכולת לשלב כמה דברים שאנחנו יודעים לדבר חדש שלא הופיע בספר. דמיינו לדוגמא שאתם לא מכירים את השפה האנגלית כלל ואני מספר לכם שהמשפט I have a cat מתרגם ל"יש לי חתול", המשפט I have a dog מתרגם ל"יש לי כלב", חתול זה cat, כלב זה dog ותפוח זה apple. עכשיו אם תנסו להגיד "יש לי תפוח" באנגלית אני חושב שכולכם תטעו ותגידו I have a apple, כי מי בכלל חושב שאנגלית לא מסוגלים להגיד שתי אותיות ניקוד אחת אחרי השניה אז ממציאים n באמצע. זה פשוט כלל אחר.

ואותו דבר בתכנות - אם אתם לא יודעים פייתון בכלל אני יכול לספר לכם שהתוכנית הבאה מדפיסה על המסך את הטקסט hello ynon:

name = "ynon"
print("hello " + name)

ואספר לכם שהתוכנית הבאה מדפיסה על המסך את המספר 42:

x = 42
print(x)

סיכוי לא רע שבשביל להדפיס את הטקסט hello 42 תחליטו לכתוב את הקוד הבא:

x = 42
print("hello " + x)

שכמובן לא יעבוד, כי מי בכלל חושב שמסביב לפלוס חייבים לכתוב שני דברים מאותו סוג.

מה שיפה שכל טעות כזאת מקרבת אותנו עוד צעד להבנה של המערכת: כשפייתון צועק עליי שאני לא יכול לשים מסביב לפלוס שני דברים מסוגים שונים למדתי משהו חדש על פייתון ועל סוגי משתנים. גיליתי כלל חדש של השפה.

הדרך ללמוד משהו חדש לכן היא פשוטה, משעממת ועובדת - בונים משהו קיים לפי ההוראות, משנים קצת לפי מה שנראה לנו הגיוני מתוך כוונה לשבור את המערכת, ואם שברנו להסתכל על הטעות וללמוד ממנה כלל נוסף. תחזרו על זה מספיק פעמים ותוכלו גם אתם לכתוב את ההוראות, במקום רק לעקוב אחריהן.