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

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

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

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]);

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

האתר החדש באוויר

30/10/2022

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

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

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

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

  4. נוסף "מצב חשוך" למי שאוהבים לקרוא מהטלפון בלילה.

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

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

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

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

היום למדתי: פיירפוקס ומאפיין auto complete

29/10/2022

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

The HTML autocomplete attribute lets web developers specify what if any permission the user agent has to provide automated assistance in filling out form field values, as well as guidance to the browser as to the type of information expected in the field.

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

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

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

<form method="post" action="/form" autocomplete="off">
  …
</form>

או ברמת ה input:

<input type="text" id="cc" name="cc" autocomplete="off" />

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

נ.ב. דוגמה? יאללה דוגמה. הנה קודפן: https://codepen.io/ynonp/pen/RwJPYYX. בקישור הזה אפשר לראות אותו על מסך מלא:

https://cdpn.io/pen/debug/RwJPYYX

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

ואם הודעות הקומיט לא מספיק אינפורמטיביות?

28/10/2022

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

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

  1. תוכלו לעשות ישיבה פעם בכמה זמן לעבור על קומיטים ולראות איזה מהם אתם אוהבים ואיזה לא.

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

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

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

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