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

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

השוואה סובייקטיבית לגמרי בין neo4j ל datomic

29/04/2023

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

המשך קריאה

סיבה ותוצאה

28/04/2023

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

ורציתי לשאול אותה - למה את עושה את זה לעצמך? את הרי כבר כל כך ספורטיבית. בשביל מה את צריכה לצאת שוב לרוץ? למה לסבול ככה?

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

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

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

איפה להשקיע את זמן הלימוד שלי?

27/04/2023

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

שני הצירים מחלקים את העולם ל-4 ריבועים:

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

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

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

  4. ובצד שמאל למטה אני מוצא ספריות ופריימוורקים מסובכים שמנסים לפתור את כל הבעיות של העולם אבל כושלים (היוש אנגולר1).

עכשיו בחזרה לשאלה מהכותרת, איפה להשקיע את זמן הלימוד שלי?

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

חיפוש טוב יותר

26/04/2023

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

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

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

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

איך לא לייצר סיסמה אקראית

25/04/2023

ביקשתי מ Chat GPT לכתוב פונקציית פייתון שמחזירה סיסמה אקראית מתוך אורך ורשימה של תווים בסיסמה. זאת היתה התוצאה:

import random

def generate_password(length, symbols):
    password = ''
    for i in range(length):
        password += random.choice(symbols)
    return password

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

import string
import random

def generate_password(length):
    chars = string.ascii_letters + string.digits + string.punctuation
    while True:
        password = ''.join(random.choice(chars) for _ in range(length))
        if (any(c.islower() for c in password)
            and any(c.isupper() for c in password)
            and any(c.isdigit() for c in password)
            and any(c in string.punctuation for c in password)):
            return password

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

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

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

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

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

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

import os

def make_random_password(length=12, symbols='abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789@$^_+&'):
    password = []
    for i in map(lambda x: int(len(symbols)*x/255.0), os.urandom(length)):
        password.append(symbols[i])
    return ''.join(password)

הטעות שכולם עושים

24/04/2023

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

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

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

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

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

וזו הטעות הגדולה שכולם עושים.

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

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

מתי לחתוך

23/04/2023

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

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

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

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

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

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

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

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

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

טיפ יוניקס: פיצול קלט בעזרת הפקודה split

22/04/2023

הפקודה ifconfig (או בגירסתה העדכנית יותר ip a) מציגה רשימה של כל כתובות ה ip על המכונה. זה חלק מהפלט לדוגמה:

utun6: flags=8051<UP,POINTOPOINT,RUNNING,MULTICAST> mtu 1380
        inet6 fe80::4b03:c5a9:d358:bb3a%utun6 prefixlen 64 scopeid 0x17
        nd6 options=201<PERFORMNUD,DAD>
vmenet0: flags=8b63<UP,BROADCAST,SMART,RUNNING,PROMISC,ALLMULTI,SIMPLEX,MULTICAST> mtu 1500
        ether be:50:b2:b2:bc:7b
        media: autoselect
        status: active
bridge100: flags=8a63<UP,BROADCAST,SMART,RUNNING,ALLMULTI,SIMPLEX,MULTICAST> mtu 1500
        options=3<RXCSUM,TXCSUM>
        ether 52:ed:3c:d3:64:64
        inet 192.168.64.1 netmask 0xffffff00 broadcast 192.168.64.255
        inet6 fe80::50ed:3cff:fed3:6464%bridge100 prefixlen 64 scopeid 0x10
        inet6 fd5e:dcce:7fd0:a7fb:10c8:64d2:15b:ca05 prefixlen 64 autoconf secured
        Configuration:
                id 0:0:0:0:0:0 priority 0 hellotime 0 fwddelay 0
                maxage 0 holdcnt 0 proto stp maxaddr 100 timeout 1200
                root id 0:0:0:0:0:0 priority 0 ifcost 0 port 0
                ipfilter disabled flags 0x0
        member: vmenet0 flags=3<LEARNING,DISCOVER>
                ifmaxaddr 0 port 15 priority 0 path cost 0
        nd6 options=201<PERFORMNUD,DAD>
        media: autoselect
        status: active

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

המשך קריאה

היום למדתי: טקסט לדיבור באפליקציות ווב

21/04/2023

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

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

  1. האוביקט SpeechSynthesisUtterance מייצג משהו שאנחנו רוצים להגיד. יוצרים אותו עם new והפרמטר היחיד הוא הטקסט (אפשר בכל שפה).

  2. בשדה voice של אותו Utterance אנחנו כותבים את הקול שאנחנו רוצים שיגיד את המשפט. אפשר לקבל את רשימת כל הקולות מ speechSynthesis.getVoices(). יש עוד כמה שדות באוביקט זה שמאפשרים לנו לבקש ממנו לדבר יותר מהר או להתאים פרמטרים אחרים.

  3. אחרי שיש לנו Utterance מוכן נשלח אותו לפונקציה speak של window.speechSynthesis כדי לשמוע אותו.

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

וזה הקוד:

synth =  window.speechSynthesis;
voice = synth.getVoices().find(v => v.lang === "he-IL");

text = new SpeechSynthesisUtterance("היו שלום ותודה על הדגים");
text.voice = voice;

function say() {
  synth.speak(text);
}

btn.addEventListener('click', say);