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

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

הסבלנות משתלמת?

05/10/2020

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

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

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

אני יכול להתקשקש שעות בבניית העיצוב הכי יפה לאפליקציה שלי במקום לרוץ עם HTML/CSS פשוט ומדויק, כשברור שלפני שהמערכת עובדת ולפני שיש לי משתמשים אף אחד אפילו לא רואה את העיצוב החדשני. מצד שני אם לא אשקיע ב UX טוב לפני שאני מתחיל לכתוב את הקוד מחיר התיקון רק יעלה ככל שהמערכת הופכת מורכבת יותר.

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

איך להפעיל Selenium עם דפדפן בלי GUI על Github Actions

04/10/2020

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

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

המשך קריאה

העולם לא צריך עוד Pull Request

03/10/2020

אוקטובר מגיע וכל שנה מחדש אירוע Hacktoberfest של Digital Ocean מעורר תגובות דומות: מתחזקים של פרויקטי קוד פתוח לא מבינים למה פתאום הם מקבלים PR-ים מיותרים מאנשים שלא מבינים כלום בפרויקט שלהם.

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

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

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

פרקטיקה, תיאוריה ופאניקה

02/10/2020

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

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

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

איפה כונן D?

01/10/2020

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

כך כשאנחנו עוברים מ Windows ל Linux ברור שנצטרך להתרגל לכתוב ls במקום dir כל פעם שרוצים להציג את רשימת הקבצים. אבל הרבה יותר מוזר יהיה הרגע שנשאל "איך מגיעים לכונן D". ההבנה שכונן הוא בעצם תיקייה ושאנחנו צריכים לעשות פעולת mount כדי שנוכל לגשת לכונן הזה היא יותר ממה שרציתי לדעת.

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

מה בכל זאת כן עובד ב Zoom

30/09/2020

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

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

המשך קריאה

מילים שקשה להגיד

28/09/2020

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

לכל פונקציה ב JavaScript יש מאפיין משם length שמחזיר כמה פרמטרים הפונקציה מצפה לקבל. ב Python קצת יותר קשה לגלות את זה אבל עדיין אפשרי עם חבילת inspect, ב Ruby יש לכל פונקציה מאפיין בשם arity שמחזיר את הערך וב Clojure אנחנו צריכים לקפוץ שמיניות באוויר בשביל למצוא אותו.

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

a = { a: 10, c: 30 }
b = { a: 5, b: 20 }
res = a.merge(b) {|k, v1, v2| v1 + v2 }

# now res is: { a: 15, b: 20, c: 30 }

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

a = { 'a': 10, 'c': 30 }
b = { 'b': 20 }
res = dict(**a, **b)
# now res is: { 'a': 10, 'b': 20, 'c': 30 }

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

ויש עוד מאות כעסים קטנים כאלה בכל מעבר בין שפות, וזה בסדר. שווה לזכור שבכל מעבר כזה בין שפות מאוד קל למצוא חבילות שסוגרות את הפער. גם אם ל JavaScript אין את random.randint של פייתון, אנחנו עדיין יכולים לקבל פונקציונאליות זהה מ lodash; חבילת mergedict של פייתון מאפשרת לשלב בצורה אלגנטית בין מילונים ולקבוע מה לעשות עם ערכים מתנגשים בקלות ממש כמו ב Ruby.

ההבדלים האמיתיים בין שפות הם לא בפונקציה מסוימת שנמצאת או לא, אלא בגישה ובהשקפת עולם שונה: האם יש Type System? האם הוא מחייב? האם יש Class-ים? האם יש הגבלה על עומק הרקורסיה? איך בונים קוד מקבילי או מבוזר? האם זה מתקמפל? האם זה רץ על המכונה אליה אני מכוון?

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

לעצור את הטובים

27/09/2020

אחת הטכניקות הטפשיות (אך מפתות) של אבטחת מידע היא לבנות מנגנונים שיהיה קל מאוד לעקוף אותם ויעצרו רק את האנשים שאין להם כח להתאמץ יותר מדי. השבוע למדתי במקרה על דרך קלה לזהות גולשים שמשתמשים בסלניום כדי להפעיל בצורה אוטומטית אתרים: מסתבר שסלניום או יותר נכון ה chromedriver שהוא מפעיל מוסיף Cache לכל דף - אני לא לגמרי בטוח מה הוא שומר ב Cache הזה - אבל את ה Cache הוא שומר במפתח עם שם מוזר שמתחיל ב $cdc. לסקרנים שביניכם הנה הקוד שיוצר את ה cache בכרומדרייבר:

function getPageCache(opt_doc, opt_w3c) {
  var doc = opt_doc || document;
  var w3c = opt_w3c || false;
  // |key| is a long random string, unlikely to conflict with anything else.
  var key = '$cdc_asdjflasutopfhvcZLmcfl_';
  if (w3c) {
    if (!(key in doc))
      doc[key] = new CacheWithUUID();
    return doc[key];
  } else {
    if (!(key in doc))
      doc[key] = new Cache();
    return doc[key];
  }
}

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

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

זום

26/09/2020

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

המשך קריאה