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

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

תאכל תאכל

18/03/2023

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

במדעי המחשב תופעה כזו נקראת ״הרעבה״, בויקיפדיה הם מתארים את זה במשפט:

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

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

המשך קריאה

מיתוסים על קוד ישן

17/03/2023

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

  1. הקוד הישן מכוער ולא גמיש.

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

  3. בקוד הישן אין באגים כי כולם כבר תוקנו.

  4. כל בעיות האבטחה של המערכת הן בגלל הקוד הישן.

  5. הקוד הישן הוא הגורם העיקרי לאיטיות.

  6. בשביל לתקן באג בקוד הישן צריך למחוק את כולו ולכתוב הכל מחדש.

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

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

כשההגיון שלך וההגיון של המחשב לא תואמים

16/03/2023

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

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

תרגום טקסטים בפייתון עם AWS

15/03/2023

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

$ aws configure

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

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

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

$ pip install boto3

ואז להריץ סקריפט כמו זה:

import boto3

client = boto3.client('translate')

response = client.translate_text(
    Text='hola mundo',
    SourceLanguageCode='es',
    TargetLanguageCode='en',
)

print(response["TranslatedText"])

אם אתם לא יודעים את שפת המקור אפשר לכתוב auto ב SourceLanguageCode ואמזון ינסו לזהות אותה לבד.

בונוס למתקדמים - אם יש לכם הרבה טקסטים לתרגם, אפשר להעלות אותם ל S3 ולשלוח את התרגומון לרוץ על כל הקבצים ולתרגם את כולם. זה יכול לעזור כשצריך לבנות כרטיסיות מתוך רשימה ארוכה של מילים שאספתם. מידע נוסף על הפיצ'ר אפשר למצוא בתיעוד של בוטו בקישור: https://boto3.amazonaws.com/v1/documentation/api/latest/reference/services/translate/client/starttexttranslation_job.html

החשיבות של כללים

14/03/2023

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

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

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

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

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

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

היום למדתי: לא הופכים OpenStruct ל JSON

13/03/2023

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

הסיפור בקצרה - ברובי בדרך כלל הגישה למקום ב Hash נעשית עם סימן סוגריים מרובעים לדוגמה:

3.1.1 :001 > d = {foo: 10, bar: 20}
 => {:foo=>10, :bar=>20}
3.1.1 :002 > d[:foo]
 => 10
3.1.1 :003 >

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

3.1.1 :005 > require 'ostruct'
 => true
3.1.1 :007 > dd = OpenStruct.new(d)
 => #<OpenStruct foo=10, bar=20>
3.1.1 :008 > dd.foo
 => 10
3.1.1 :009 > dd.bar
 => 20

עד לפה הכל טוב ואפשר גם להפעיל to_json ולקבל את כל השדות בחזרה בתור JSON:

3.1.1 :002 > require 'ostruct'
 => true
3.1.1 :003 > require 'json'
 => true
3.1.1 :004 > OpenStruct.new({ foo: 10, bar: 20 })
 => #<OpenStruct foo=10, bar=20>
3.1.1 :005 > OpenStruct.new({ foo: 10, bar: 20 }).to_json
 => "\"#<OpenStruct foo=10, bar=20>\""

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

3.1.1 :001 > OpenStruct.new({ foo: 10, bar: 20 }).to_json
 => "{\"table\":{\"foo\":10,\"bar\":20}}"

מאיפה הגיע לשם ה table???

חיפוש ב Stack Overflow הביא אותי לתשובה הזאת. מסתבר שבמימוש של OpenStruct כל הפריטים נשמרים בתור ערכים של משתנה מחלקה בשם table, והקידוד ל JSON של ריילס פשוט מקודד את כל משתני המחלקה.

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

3.1.1 :077 > OpenStruct.new({a: 10, b: 20}).to_h.to_json
 => "{\"a\":10,\"b\":20}"

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

בעיות שכבר אין בפיתוח תוכנה

12/03/2023

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

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

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

  1. הפצת תוכנה - לפני 20 שנה היה מאוד קשה לכתוב אפליקציה אחת שתרוץ גם על Windows וגם על Mac. כשהאייפון הראשון יצא אי אפשר היה לדמיין פיתוח מערכת שתרוץ גם על מחשב וגם על טלפון, וכשאנדרואיד התחיל לתפוס תאוצה המצב רק נהיה יותר מבלבל. אבל אז האינטרנט השתלט והגיעו חנויות האפליקציות וכלי ה Cross Platform, ופתאום כל אחד יכול לשבת בבית ולכתוב אפליקציה קטנה שכולם בכל העולם יוכלו להפעיל.

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

  3. אבטחת מידע בסיסית - ב 2005 אפשר היה להיכנס לבסיס הנתונים של 90% מהאתרים ברשת עם פירצה מאוד בסיסית שנקראה SQL Injection. ב 2012 אפשר היה לשבור את רוב הרשת עם פירצה שנקראה XSS. טכנולוגיות חדשות הפכו את שתי הפריצות האלה ופריצות פשוטות רבות נוספות ללא רלוונטיות. נכון עדיין יש האקרים ועדיין צריך לאבטח את המוצרים שלנו, אבל הסיכון בפריצה למוצר שלכם (אם כתבתם בפריימוורק מודרני) הוא הרבה יותר נמוך ממה שהיה פעם.

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

ועכשיו שזה מאחורינו, מה עוד עוצר אותך?

שלושה פיצ'רים של בינג החדש שמשאירים את ChatGPT מאחור

11/03/2023

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

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

המשך קריאה

ארגונומיקה

10/03/2023

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

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

המפתחים שכותבים את Visual Studio נדרשים ליכולות שונות ולכלים שונים מאשר מפתחות הבונות משחק מחשב ואלה יצטרכו יכולות שונות ממפתחים הבונים יישום Saas. עם ההבדל הזה בראש כדאי ללכת לקרוא את הדיון המרתק בין דוד בוב לקייסי מורטורי בקישור: https://github.com/unclebob/cmuratori-discussion/blob/main/cleancodeqa.md

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

להוציא קבצים מגיט עם rm cached

09/03/2023

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

$ git add .
$ git commit -m 'fixed bug'

אופס.

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

ניסיון ראשון למחוק את התיקיה עם git rm ייכשל:

$ git rm .idea

fatal: not removing '.idea' recursively without -r

ואם אנסה להקשיב לו ולהפעיל git rm -r .idea אני אומנם אמחק את התיקיה מגיט אבל אאבד את קבצי הגדרות הפרויקט שלי.

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

  1. יש את העותק שאנחנו רואים בתיקיית העבודה.

  2. אפשר לחשוב על כל קומיט בתור עותק נוסף של הפרויקט.

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

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

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

$ git rm --cached -r .idea

rm '.idea/.gitignore'
rm '.idea/cached.iml'
rm '.idea/inspectionProfiles/profiles_settings.xml'
rm '.idea/misc.xml'
rm '.idea/modules.xml'

$ git commit -m 'removed .idea from project'

$ ls .idea
cached.iml              inspectionProfiles      misc.xml                modules.xml             vcs.xml                 workspace.xml