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

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

מי צודק?

03/04/2018

גווידו ון רוסום הוא היוצר של שפת Python. ב 2009 הוא פירסם מניפסט שיוצא כנגד Tail Recursion Elimination. הטענה שלו שזה מעודד הרגלי תכנות גרועים ולכן אסור להכניס יכולת כזו לשפה. ב 2011 חוזה ואלים כתב שפת תכנות בשם Elixir שמתבססת על הרעיון של Tail Recursion Elimination. חוזה טען שרקורסיה ולכן TRE הם המבנים הבסיסיים ביותר בתכנות, שהם עוזרים לייצר קוד קריא ויציב יותר ושלולאות הן האויב (כי לולאות משתמשות ב Mutable Data שהוא הרבה יותר גרוע).

בעולם מקביל, ספריית הקוד הכי פופולרית לבניית אתרים מאז ומעולם נקראת jQuery. שנים ארוכות היא היתה האפשרות הטובה ביותר וכמעט היחידה לפיתוח אתרים. ואז איפשהו ב 2009 לאנשים התחיל להימאס מ jQuery - ב 2010 ג'רמי אשכנז משחרר את Backbone ומישקו הברה את אנגולר: שתי ספריות ששינו ב 180 מעלות את התפיסה של פיתוח Web. בעולם של jQuery התפיסה המקובלת היתה ש JavaScript עובד על מידע ששמור ב DOM. בעולם של Backbone ועוד יותר מזה Angular, קוד JavaScript הוא זה ששמר את המידע וכתב אותו ל DOM כשהיה צריך. לימים React, Vue ו Angular2 המשיכו את הכיוון שטוען שהמידע נשמר ב JavaScript; ולאחרונה DHH שיחרר פריימוורק בשם Stimulus שחוזר לרעיון הישן שהמידע צריך להישמר ב DOM.

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

טעויות טובות ורעות

02/04/2018

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

כמובן שלא כל השינויים הם כאלה.

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

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

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

הדרך הנכונה

31/03/2018

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

הבעיה היא כשהולכים בדרך הלא נכונה.

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

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

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

השיטה הבטוחה להפוך למתכנתים טובים יותר

30/03/2018

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

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

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

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

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

ויש גם Side Effect נחמד: בפעם הבאה שתרצו לבצע Refactoring לקוד יהיה לכם הרבה יותר קל לגשת למשימה ולוודא שאתם לא שוברים כלום.

סיפור אחר לגמרי

29/03/2018

כמעט בכל המכללות היום מעודדים סטודנטים להשתמש בגיטהאב ולהעלות פתרונות לתרגילים לפרופיל שלהם שם. כן גם אני חוטא בזה בחלק מהקורסים כאן באתר ולראיה יש 190,118 מאגרים בגיטהאב ששמם datasciencecoursera. יש גם מיליון מאגרים בשם hello-world ועוד מיליון שנקראים test. אבל לתרום קוד לפרויקט קוד פתוח זה סיפור אחר לגמרי. לפני כמה חודשים הורדתי את הקוד של gcompris. הבן שלי עף על המשחקים האלה וכל הקוד כתוב ב QML אז חשבתי שיהיה נחמד לכתוב משחק בעצמי. הקוד לא התקמפל בגלל חוסר תאימות למק ב CMakeLists.txt. אני יודע CMake ומהר מאוד תיקנתי את הבעיה, קימפלתי והרצתי. השלב הבא היה לשלוח Pull Request בחזרה ל gcompris עם התיקון כדי שגם אחרים יהנו. בתגובה החברים שם אמרו שאם כבר באתי אולי אני יכול לעזור להם בעוד כמה בעיות שקשורות בתאימות למק ושעדיף להוסיף גם אותן לאותו Pull Request, ושהם גם לא יכולים לקבל ממני PR כי צריכים את השם המלא והחשבון גיטהאב שלי היה בשם ynonp. בסוף אחרי שלושה חודשים התיקון שלי (באורך שתי שורות) כן נכנס לפרויקט הרשמי. לתרום קוד לפרויקט קוד פתוח דורש יכולת לעבוד עם אנשים, להבין את העולם מנקודת המבט שלהם, להיות מוכן להיכנס לדיאלוג ולשפר את העבודה שלך עד שהיא תהיה ברמה מספיק טובה כדי שיקבלו אותה. במקום לעודד אנשים לפתוח עוד ריפוזיטורי בגיטהאב עדיף להתאמץ ולעזור להם לשלוח Pull Request, כל הדרך עד שמתקבל.

איוון יו

28/03/2018

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

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

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

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

אתם לא צריכים עוד קורס

27/03/2018

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

לא, אתם לא צריכים עוד קורס. אתם צריכים להתחיל ללמוד.

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

סגנון אחר

26/03/2018

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

...

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

...

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

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

על תבונה ורגישות (של מחשבים)

25/03/2018

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

print(sum(n * n for n in range(100)))
print(sum([n * n for n in range(100)]))

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

ב Ruby שתי השורות האלה אולי נראות דומה אבל השניה תכשיל את כל התוכנית (גם אם יש פונקציה בשם max שהוגדרה לפני כן):

puts max(2, 3)
puts max (2, 3)

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

find . -name '*.c'
find . -name *.c

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

שתי דרכים לכתוב קוד לשימוש חוזר

24/03/2018

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

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

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

  2. אפשר להתחיל עם מימוש אחד בלי חשיבה מתוחכמת על שימוש חוזר והיררכיית מחלקות. גם המימוש השני והשלישי יהיו פיתוח מאפס עם הרבה copy/paste ורק במימוש הרביעי לחפש את המשותף, לבנות ספריה גנרית ואיתה לכתוב מחדש את שלושת המימושים הראשונים.

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