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

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

טפסים דינמיים בריילס

30/12/2018

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

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

המשך קריאה

הדבר הנכון לעשות

29/12/2018

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

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

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

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

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

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

קוד שאי אפשר לבדוק

28/12/2018

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

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

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

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

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

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

פטריות

27/12/2018

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

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

טיפ גיט: איך לשנות את פורמט הלוג של git

26/12/2018

הפורמט הרגיל של git log ארוך מדי ובפרויקטים גדולים לא מאוד נוח לקריאה. ניסיון לשנות את הפורמט עם אליאס לא ממש עובד. הגדרתי בפרויקט את ה alias הבא:

git config alias.log "log --oneline"

וגיט התעלם באלגנטיות.

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

$ git config log.abbrevCommit false
$ git config format.pretty oneline

פתרה את הבעיה ומציגה יומן שנראה כך:

$ git log

5982b5b (HEAD -> master, dev) created a readme file
4945c9c fixed jade template
7b1978d add debug message
943e263 initial commit

הדפסת הודעות לוג לקובץ יומן ב Express

25/12/2018

מורגן הוא מודול תיעוד הבקשות של אקספרס והוא נמצא בכל פרויקט אקספרס שתיצרו עם Express Generator. תוכלו לזהות אותו לפי השורה הבאה בקובץ app.js.

app.use(morgan('dev'));

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

המשך קריאה

קומיטים קטנים ממש

24/12/2018
git

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

אל תדאגו - אני יודע גיט.

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

# My Cool Project

This is a demo project

ועכשיו נוסיף לו שני בלוקים של טקסט שאמורים להיות מפוצלים ל-2 קומיטים שונים:

# My Cool Project

This is a demo project

# Installation
you need to download this app and install it if you want to use it

fixing first issue
fixing second issue
fixing third issue

במקום לעשות cut-and-paste עם קובץ נוסף אפשר פשוט להפעיל את git add במצב אינטרקטיבי:

$ git add --interactive -p

diff --git a/readme.txt b/readme.txt
index d3ef36a..a53fb88 100644
--- a/readme.txt
+++ b/readme.txt
@@ -1,3 +1,12 @@
 # My Cool Project

 This is a demo project
+
+# Installation
+you need to download this app and install it if you want to use it
+
+fixing first issue
+fixing second issue
+fixing third issue
+
+

Stage this hunk [y,n,q,a,d,e,?]? 

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

# Manual hunk edit mode -- see bottom for a quick guide.
@@ -1,3 +1,12 @@
 # My Cool Project

 This is a demo project
+
+# Installation
+you need to download this app and install it if you want to use it
+
+fixing first issue
+fixing second issue
+fixing third issue
+
+
# ---
# To remove '-' lines, make them ' ' lines (context).
# To remove '+' lines, delete them.
# Lines starting with # will be removed.

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

# Manual hunk edit mode -- see bottom for a quick guide.
@@ -1,3 +1,12 @@
 # My Cool Project

 This is a demo project
+
+# Installation
+you need to download this app and install it if you want to use it
+
# ---
# To remove '-' lines, make them ' ' lines (context).
# To remove '+' lines, delete them.
# Lines starting with # will be removed.
# 
# If the patch applies cleanly, the edited hunk will immediately be
# marked for staging.
# If it does not apply cleanly, you will be given an opportunity to
# edit again.  If all lines of the hunk are removed, then the edit is
# aborted and the hunk is left unchanged.

שמירה ויציאה ותראו את הסטטוס:

$ git status
On branch main
Changes to be committed:
  (use "git reset HEAD <file>..." to unstage)

    modified:   readme.txt

Changes not staged for commit:
  (use "git add <file>..." to update what will be committed)
  (use "git checkout -- <file>..." to discard changes in working directory)

    modified:   readme.txt

הקובץ readme.txt מופיע גם בתור משהו שייכנס לקומיט הבא וגם בתור שינויים שלא ייכנסו לקומיט הבא. הפעלת diff תראה לנו את ההסבר:

$ git diff

diff --git a/readme.txt b/readme.txt
index 6076e63..a53fb88 100644
--- a/readme.txt
+++ b/readme.txt
@@ -5,3 +5,8 @@ This is a demo project
 # Installation
 you need to download this app and install it if you want to use it

+fixing first issue
+fixing second issue
+fixing third issue
+
+

בלוק הטקסט השני, שמסומן ב +, נמצא אצלי בתיקיית העבודה אבל לא ב Staging. לעומתו הבלוק שמעליו כן נמצא ב Staging area ולכן לא מופיע ב diff.

נפעיל קומיט כדי לשמור את השינוי:

$ git commit -m 'add installation instructions' 

ובסטטוס הבא נראה שהקובץ עדיין ב Modified אבל הפעם רק החלק השני שלו. עכשיו אפשר להמשיך ל add ו commit נוספים כדי להכניס את בלוק הטקסט השני:

$ git add .
$ git commit -m 'fixed more issues'

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

commit 3612ce51ab22876a6337b56050a1f16bff9ea9e9 (HEAD -> main)
Author: ynonp <ynonperek@gmail.com>
Date:   Sun Dec 23 14:49:12 2018 +0200

    fixed more issues

commit b4c25f7ac3cb7fdd3d8101750ff03cb2b3d7b5e1
Author: ynonp <ynonperek@gmail.com>
Date:   Sun Dec 23 14:47:38 2018 +0200

    add installation instructions

אוהבים גיט ורוצים ללמוד להשתמש בו טוב יותר? אני חושב שתהנו מקורס Git Hero שיש לנו כאן באתר שכולל מעל שש שעות של הסברים, דוגמאות וטיפים לשימוש חכם יותר ב Git. פרטים והרשמה בקישור https://www.tocode.co.il/bundles/git

תהנה מהדרך

23/12/2018

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

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

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

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

ניצחונות קטנים

22/12/2018

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

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

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

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

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

ביטויים רגולאריים וקסמים של וים

21/12/2018
vim

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

<img src="cat.png" />

והופך אותה לשורה שנראית כך:

<img src="cat-1.png" />

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

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

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

/\V\[0-9]\[0-9]

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

/\V\d\d

למצב קצת קסום אנחנו נכנסים עם \M בתחילת הביטוי ומצב זה ממש דומה ל"לא קסום בכלל" מלבד התווים ^ ו $ שלא צריכים שתכתבו \\ לפניהם.

למצב קסום אנחנו נכנסים עם \m בתחילת הביטוי. מצב זה מזכיר מאוד את grep ובו רוב הסימנים המיוחדים יעבדו בלי \\ אבל עדיין יהיו מספר סימנים מיוחדים שכן יצטרכו \\ לפניהם לדוגמא +, ? ו {}.

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

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

:s/\vsrc="(\w+)\.(\w+)"/src="\1-1.\2"/

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

התיקון הכי פשוט יהיה להוסיף \\ לפני סימן השווה ואז נקבל את הביטוי הבא שעובד:

:s/\vsrc\="(\w+)\.(\w+)"/src="\1-1.\2"/

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

:s/\Vsrc="\(\w\+\).\(\w\+\)"/src="\1-1.\2"/
:s/\msrc="\(\w\+\).\(\w\+\)"/src="\1-1.\2"/
:s/\Msrc="\(\w\+\).\(\w\+\)"/src="\1-1.\2"/

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

http://vimdoc.sourceforge.net/htmldoc/pattern.html#pattern