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

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

היום למדתי: הפקודה fc תאפשר לכם לערוך היסטוריה ולהריץ אותה שוב

09/11/2022

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

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

mkdir foo
touch foo/bar
cp /etc/passwd foo

אז אני יכול אחרי זה לכתוב:

fc -l mkdir cp

ולקבל את רשימת כל הפקודות מ mkdir עד cp כולל:

544      mkdir foo
545      touch foo/bar
546      cp /etc/passwd foo

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

mkdir bar
touch bar/bar
cp /etc/passwd bar

שומר ויוצא וכך יצרתי את תיקיית bar בדיוק כמו שיצרתי קודם את תיקיית foo.

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

למה מערך ריק שווה 0?

08/11/2022

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

המשך קריאה

לא הולך להיות כיף

07/11/2022

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

ואותו הבדל תוקף אותנו גם כשאנחנו באים לשדרג את הקריירה או הקוד שלנו:

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

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

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

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

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

ריילווי מציע דרך קלה וחדשה לפתח בענן

06/11/2022

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

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

המשך קריאה

תשתית בדיקות

04/11/2022

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

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

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

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

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

03/11/2022

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

הטריגר ב Github Action יראה כך:

on:
  push:
    tags:
      - 'deploy-*'

ואז אפשר ליצור את התג עם תוספת של timestamp ולדחוף אותו לשרת עם הפקודות:

$ git tag deploy-$(date +%s)
$ git push --tags

לא לדאוג, אני מכיר את find

02/11/2022

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

כל עוד מדובר ב 2-3 פרויקטים אין בעיה לעבור אחד אחד, אבל כשיש עשרות הרבה יותר כיף להשתמש ב find.

המשימה הראשונה היא למצוא את כל תיקיות הפרויקטים, כלומר התיקיות ברמה "הראשית". בשביל זה find מציע לנו את maxdepth, type ו mindepth. עבור דוגמה פשוטה שמכילה שלוש תיקיות פרויקטים בשמות a, b ו c אני מריץ:

$ find . -mindepth 1 -maxdepth 1 -type d

./a
./c
./b

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

אחרי שיש לנו את תיקיות הפרויקטים צריך בכל תיקיה להריץ את הפקודות:

mkdir app && mv * app

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

בשביל זה ל find יש כפתור exec. אבל אני לא יכול להריץ ישירות את ה && בתוך ה exec ולכן אני מריץ עותק חדש של bash שיפעיל את שתי הפקודות:

find . -mindepth 1 -maxdepth 1 -type d -exec bash -c "mkdir {}/app && mv {}/* {}/app" \;

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

קבוצות אטומיות בביטויים רגולאריים

01/11/2022

אחד השינויים המעניינים שתמצאו ברשימת החידושים של פייתון 11 נקרא Regular Expressions Atomic Grouping. מסתבר שמאחורי השם המפוצץ מסתתר תחביר פשוט וחמוד, שאפילו יכול להציל את המערכת שלכם מהתרסקות אטומית.

אחת הבעיות עם ביטויים רגולאריים נקראת Catastrophic Backtracking. קחו לדוגמה את הביטוי הרגולארי:

re = /W(X|Y+)+Z/

ואת הטקסט:

text = "WYYYYYYYYYYYYYYYYYYYYYYYYYYYYA"

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

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

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

re = /W(?>X|Y+)+Z/

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

שימו לב ששינוי קבוצה לקבוצה אטומית משנה את המשמעות של הביטוי. לדוגמה הביטוי הזה:

re = /a(bc|b)c/

יתאים לטקסטים abc ו abcc, אבל אם אני הופך את הקבוצה לאטומית והאופציה של bc תיכשל, המנוע לא יחזור לנסות את b ולכן הטקסט abc לא יתאים לביטוי a(?>bc|b)c. בסך הכל קבוצות אטומיות הן כלי מתקדם שחשוב להכיר אם אתם משתמשים בביטויים רגולאריים על קלט לא מפולטר ורוצים לוודא שקלט זדוני לא שובר לכם את השרת. והחל מפייתון 3.11 תוכלו להשתמש בהן גם בפייתון.

טיפ טייפסקריפט: ההבדל בין let ו const מבחינת Type Inference

31/10/2022

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

במילים אחרות ויותר ספציפי, הקוד הזה מגדיר את x להיות מהטיפוס הליטרלי 10:

const x = 10;

אבל הקוד הזה מגדיר את x להיות number:

let x = 10;

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

const movie = { name: 'Return Of The Jedi', rating: 5 };
let key = Math.random() > 0.5 ? "name" : "rating";
console.log(movie[key]);

ולא בגלל שטייפסקריפט כועס על הדירוג הגבוה של "שובו של הג'דיי". הוא פשוט רואה את ה let לפני ה key, מחליט ש key הוא string ולא מבין איך אפשר להשתמש ב string כללי בתור מפתח בגישה לאוביקט movie.

התיקון הכי קל הוא להפוך את הגדרת המשתנה ל const:

const movie = { name: 'Return Of The Jedi', rating: 5 };
const key = Math.random() > 0.5 ? "name" : "rating";
console.log(movie[key]);

וככה טייפסקריפט מבין שהטיפוס של key הוא האיחוד בין שני הטיפוסים הליטרליים name ו rating, ובגלל ששניהם מפתחות ב movie הוא מרשה לי להשתמש ב key בתור מפתח באוביקט.

נ.ב. לאלה מכן שפחות אוהבים להתחכם, אפשר לכתוב את אותה הדוגמה בלי ה random בכלל:

const movie = { name: 'Return Of The Jedi', rating: 5 };
let key = "name";
console.log(movie[key]);

אבל זה עלול להרוס את הכיף.