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

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

החיים שלי עם ביטויים רגולאריים

20/12/2018

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

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

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

    https://www.tocode.co.il/blog/2015-05-vim-html-image-gallery

  3. עוד כלי שתומך בביטויים רגולאריים הוא גיט ובפרט הפקודה git log שמקבלת פרמטר בשם grep. החיפוש הזה ייתן את כל הקומיטים שההודעה שלהם מתקנת Issue בן שלוש ספרות או יותר.
    $ git log -i -E --grep='(fix|close).*[0-9]{3}'
    
  4. ביטויים רגולאריים יכולים לעשות קסמים כשאתם צריכים החלפה מהירה של מילים בסקריפט. נכון של Bash ולכל סביבה יש את הכלים המיוחדים שלה להחלפות, אבל הייתרון בביטויים רגולאריים שתחביר אחד עובד תמיד: אנחנו נמצא אותם ב awk, sed וכמובן ב grep.

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

    text = 'hello.txt'
    puts text.chomp('.txt') # prints hello
    

    אבל אז אתם עוברים לפייתון ופתאום צריכים לכתוב קוד כזה:

    text = 'hello.txt'
    if url.endswith('.txt'):
        print(text[:len('.txt') + 1])
    

    בעוד שבאמצעות ביטוי רגולארי הייתם פותרים את הבעיה בשתי השפות עם אותו קוד בדיוק.

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

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

https://www.tocode.co.il/workshops/59

השוואת גבהים בריאקט - חלק 2

19/12/2018

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

המשך קריאה

אבל... זה עבד לי בפיתוח

18/12/2018

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

קרה לכם? ברור. בואו נרשום לקחים:

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

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

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

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

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

  6. לפעמים יש לנו תוספים או תוכנות שהתקנו בסביבה אחת ושכחנו מהם. אפשר להשתמש ב:

    apt list --installed
    

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

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

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

השוואת גבהים בריאקט

17/12/2018

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

המשך קריאה

דברים שאני מנסה כשכבר נגמרו הרעיונות

16/12/2018

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

  1. מתחיל למחוק קוד באקראי ולראות אם משהו מתחיל להתנהג אחרת.

  2. מוסיף מלא הדפסות Debug ומקווה שחלק מהמידע ייתן לי השראה.

  3. עושה הפסקה.

  4. חוזר ומגלה שהבעיה עדיין שם, ולי עדיין אין רעיונות.

  5. כותב בדיקות אוטומטיות.

  6. מוסיף עוד הדפסות ומנסה לחפש חוקיות.

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

  8. מתייעץ עם חבר.

  9. מתרגל לחיים עם הבאג.

רעיונות נוספים? מוזמנים לשתף בתגובות.

תסמונת המתחזה

15/12/2018

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

  1. אנחנו שואלים פחות שאלות, כדי שלא יחשבו שלא הבנו.

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

  3. אנחנו מסתירים כשלונות וחוסר ידע כולל באמצעות שקרים.

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

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

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

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

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

אתה לא חולה (או: שתי המלצות על פודקסטים)

14/12/2018

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

https://www.akimbo.me/blog/s-2-e-6-origin-stories

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

https://soundcloud.com/einatnathan/ep17

האזנה מהנה, ינון

לא יודע

13/12/2018

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

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

רק בבקשה אל תעצרו ב"לא יודע". זה לא בריא לכם וזה לא בריא לקוד שלכם.

מימוש סינגלטון ב Ruby

12/12/2018

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

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

class Critter
  @@instance = Critter.new
  def self.instance
    @@instance
  end

  def val
    5
  end
end

ואכן יש לנו מחלקה Critter עם מתודה בשם instance שמחזירה תמיד את אותו אוביקט:

c = Critter.instance
d = Critter.instance

puts c == d # true

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

require 'singleton'

class Critter
  include Singleton
  def val
    5
  end
end

c = Critter.instance
d = Critter.instance

puts c.val
puts d == c

הבעיות מתחילות כשננסה להסתיר את הפונקציה new. כאן לרובי יש סוג של פיתרון באמצעות הפונקציה private_class_method. כך נראה Critter שמסתיר את פונקציית new שלו:

class Critter
  include Singleton
  def val
    5
  end
  private_class_method :new
end

ובאמת מי שינסה לקרוא עכשיו ל Critter.new יקבל את השגיאה:

NoMethodError: private method `new' called for Critter:Class

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

require 'singleton'

class Critter
  include Singleton
  def val
    5
  end
  private_class_method :new
end

c = Critter.instance
d = Critter.send(:new)

puts d.val # print 5
puts d == c # false

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

טיפ רובי: בואו נחליף את הסוף של המחרוזת

11/12/2018

ל Bash יש פיצ'ר מדליק שמחליף במהירות את הסוף של מילה, מה שעוזר לנו לכתוב סקריפטים שמשנים שמות של קבצים. הקוד הבא ב Bash יחליף במהירות את כל הקבצים שמסתיימים ב old לסיומת new:

for fname in *.old
do
    mv "$fname" "${fname%old}new"
done

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

בקוד זה נראה כך:

glob("*.old").each do |fname|
    File.rename(fname, fname.chomp("old") + "new")
end

קסם נוסף שיש ל Bash בשרוול הוא מחיקת קטע מהתחלה של מחרוזת עם סימן הסולמית - אבל לא הצלחתי למצוא מקבילה טובה ברובי אליו.