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

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

להפסיד משני העולמות (זמני טעינת אתר)

19/03/2023

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

בהרבה מערכות אחרות המידע הדינמי של העמוד הוא חלק בלתי נפרד ממנו, אבל בשביל לאפשר Scale גדול נבחר עדיין להשתמש בקבצי HTML/CSS/JS סטטיים, שימשכו את המידע הדינמי מהשרת בעליה דרך API. ההנחה היא שבמקרי קיצון משיכת מידע מ API תעמיס פחות על השרתים מאשר ייצור של Template מלא של ה HTML, ובנוסף קל יותר לפתח את המערכת עם הפרדה ברורה בין צוות ה Front End לצוות ה Back End.

בהרבה מערכות נוספות המידע הדינמי של העמוד הוא חלק בלתי נפרד ממנו אבל בגלל שהצוות קטן ומורכב ממתכנתי Full Stack, או שלא מתוכנן עומס של אלפי בקשות בשניה על ה API, שווה לנו לוותר על ה HTML הסטטי וליצור את ה HTML דינמית מתוך קוד צד שרת (לדוגמה קוד Rails או Django). דף HTML כזה שחוזר לדפדפן מכיל בטעינה הראשונית גם את כל המידע הדינמי של העמוד ואז הדפדפן יכול להציג את התוכן מיד איך שמקבל את התשובה לבקשה הראשונה. נכון, הפסדנו את היכולת להפיץ את ה HTML דרך CDN, אבל חסכנו צורך בבקשת רשת נוספת בשביל המידע הדינמי של העמוד.

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

תאכל תאכל

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 שנים". הבנה טובה של המוצר היא המפתח להבנה טובה של הארגונומיקה ולבניית תשתית ארגונית שתתאים לכם ולצוות שלכם.