ביטול מחיקה בריילס (כמו בג'ימייל)
מכירים את הכפתור Undo שמופיע בג'ימייל אחרי שמחקתם הודעה? עם הטכנולוגיה של היום לא חייבים להיות מהנדסת בגוגל בשביל לבנות דבר כזה גם למערכת שלכם. הנה מדריך קצר למימוש בריילס.
טיפים קצרים וחדשות למתכנתים
מכירים את הכפתור Undo שמופיע בג'ימייל אחרי שמחקתם הודעה? עם הטכנולוגיה של היום לא חייבים להיות מהנדסת בגוגל בשביל לבנות דבר כזה גם למערכת שלכם. הנה מדריך קצר למימוש בריילס.
מקריאה במודעות דרושים נראה לפעמים שכולם מחפשים נינג'ות או תותחים או סופרסטארים או מה שלא יהיה, וזו טרמינולוגיה קצת מלחיצה. רוב האנשים לא יגדירו את עצמם בתור נינג'ות ובינינו אני לא בטוח שהייתי רוצה לעבוד עם אלה שכן. ובכל זאת אנחנו יודעים שיש מתכנתים ומתכנתות שמצליחים תמיד למצוא עבודה גם בטכנולוגיה שאף פעם לא נגעו בה, ויש כאלה שגם אחרי 5 שנים ניסיון עדיין יתקשו להחזיק במשרה. אז כן אני חושב שאנחנו צריכים שם אחר בשביל האנשים האלה שאנחנו רוצים לעבוד איתם, אבל את התכונות שלהם יחסית קל לזהות:
אתר מילוג מגדיר את המילה מישלב בתור ״רמה לשונית בהתאם לסיטואציה או למעמד החברתי״. שווה לזכור שגם כשאתם כותבים וקוראים קוד יש משמעות למישלב, יש תבניות מסוימות שאופייניות לקבוצות מתכנתים מסוימות ואחרות שמאפיינות קבוצות אחרות. המישלב הוא שמאפשר לי לדעת המון על מתכנת או מתכנתת רק מלקרוא קטע קצר של קוד שהם כתבו.
ההבדל בין שתי הפונקציות הבאות הוא תהומי, למרות ששתיהן כתובות באותה שפה ועושות בדיוק את אותו דבר:
function ReturnFirstElement(array) {
if (array.length > 0) {
var result = array[0];
}
else {
var result = undefined;
}
return result;
}
const returnFirstElement = (arr) => arr[0];
ואני לא רוצה להתחיל בכלל לדבר על ההבדל בין שתי הפונקציות האלה:
function fib1(n) {
let [x, y] = [0, 1];
for (let i=0; i < n; i++) {
[x, y] = [y, x + y];
}
return x;
}
function fib2(n) {
let [x, y] = [0, 1]
for (let i=0; i < n; i++) {
[x, y] = [y, x + y]
}
return x
}
אתם יכולים לכתוב קוד במשלב מסוים במודע או שלא במודע, אבל אתם לא יכולים לכתוב קוד נייטרלי. כמעט תמיד משתלם לשאול - מי האנשים שאני רוצה לדבר כמוהם? ואז לראות איך הם כותבים ולהשתמש בדיוק באותה שפה. כי בתכנות בדיוק כמו בשפה מדוברת גם הסגנון מעביר הרבה מהמסר.
בלוג מקצועי הוא כלי עבודה מאוד חשוב למתכנתים היום, ולפחות בשבילי הכתיבה בבלוג זה משהו שאני מחכה לו במהלך היום. לפעמים זה בעקבות התמודדות עם תקלה מעניינת, לפעמים אחרי שלמדתי משהו חדש ולפעמים בעקבות תובנה לגבי המשך הקריירה.
בלוג מקצועי (לפחות בשבילי) מספק שלושה כיווני התפתחות בריאים לקריירה:
בלוג עוזר לסדר את המחשבות - אחרי התמודדות עם באג או בעיה תכנותית מעניינת התשובה הראשונה שאני מגיע אליה היא הרבה פעמים לא הטובה ביותר. כן, אני מצליח להגיע לקוד שעובד, אבל רק אחרי שאני מנסה להסביר לעצמי ולכם למה הקוד הזה עבד אני מבין שבעצם פספסתי כמה נקודות חשובות או כמה מקרי קצה, ואז אני חוזר לשולחן השרטוטים כדי לתקן את הפיתרון. הכתיבה על הבעיה פותחת אותה מחדש ונותנת הזדמנות לחשוב שוב על הפיתרון ולנסות לשפר. פוסט שמדבר על פיתרון מסוים גם עושה חשק לחפש את הפיתרון הטוב ביותר שאני יכול לבעיה.
בלוג עוזר לאחרים להכיר אתכם - בפוסט יחסית חדש מהבלוג מאיה כותבת אלגוריתמים מספרת מאיה איך התחילה לקבל הצעות עבודה מעולות אחרי פירסום של הבלוג שלה בלינקדאין. אני לגמרי מזדהה. היום מסמך קורות חיים כמעט לא אומר כלום על הבן אדם, כי כולם כותבים קורות חיים מפוצצים. בלוג טוב לעומת זאת זה סיפור אחר לגמרי. בלוג נותן לך הזדמנות להסביר דברים לעומק ולאחרים (שמתעניינים) באותם דברים הזדמנות לקרוא ולהתעמק בפיתרונות. אחרי שקוראים את הבלוג של מאיה אפשר לקבל את הרושם כאילו ישבתם איתה לפתור יחד בעיה טכנית (או 10). בלוגים מקצועיים רבים שאני קורא נותנים את ההרגשה הזו וזה כמובן דבר שפותח הרבה דלתות.
בלוג עושה חשק לנסות דברים חדשים - מכירים את המחשבה הזאת של "מעניין איך מנגנון כזה וכזה עובד?" שבאה ואז נעלמת? ובכן אם יש לכם בלוג אתם רק מחכים למחשבות כאלה וממש לא נותנים להן לברוח. מחשבה כמו "מעניין איך כותבים פותר סודוקו" הופכת לחומר הגלם ממנו אתם מייצרים את הפוסט הבא, וכך פוסט אחרי פוסט אתם מנסים יותר דברים וכך לומדים בעצמכם יותר.
ואם שכנעתי אתכם לפתוח בלוג אז כל מה שנשאר זה להראות איך, ובשביל זה הזמנתי ליום חמישי את ערן גולדמן-מלכא להעביר וובינר של שעה על כלי נפלא שנקרא Jekyll. ג'קיל הוא כלי קוד פתוח שאם הייתי צריך לבחור היום הייתי בטוח בוחר בו כדי לפתוח את הבלוג שלי: ההתקנה קלה, הוא מאוד ידידותי למתכנתים וכל הבלוג נשמר בלי צד שרת ורק עם דפים סטטיים. אז אם יש לכם שעה פנויה בחמישי בבוקר, ואחרי זה עוד כמה שעות בשבוע כדי אשכרה לכתוב בבלוג, מוזמנים להצטרף אלינו בקישור:
https://www.tocode.co.il/workshops/88
נ.ב. אם יש לכם כבר בלוג ורוצים לשתף ממש אשמח לקישור בתגובות (עדיף אחד שאפשר לקרוא ברסס).
כשהמקום בדיסק הקשיח שלי מתחיל להיגמר אני עובר עם זכוכית מגדלת על כל הקבצים והתיקיות ומחפש מה אפשר למחוק, כי בתחושה שלי דיסק קשיח של חצי טרה צריך להספיק לפחות לכל החיים. בכל מקרה בתוך החיפוש מצאתי ספריה קטנה בתיקיית הבית שנקראת ~/.npm
שתופסת לי היום קצת מעל ג'יגה.
מה שיותר מפתיע היה תוכן התיקיה: היא מכילה את כל החבילות שאי פעם התקנתי ובכל הגירסאות שלהן. זה כאילו מישהו לקח את כל תיקיות ה node_modules
של העולם והדביק את הכל יחד לתוך תיקיה אחת. אז הלכתי לתיעוד ומסתבר שזה בדיוק מה ש npm עושה כל פעם שאנחנו מתקינים חבילה. עוד קצת חיטוט בתיעוד ומסתבר שאפשר להשתמש ב cache הזה כדי להפוך את ההתקנות שלכם להרבה יותר מהירות. העברת הדגל --offline
ל npm install
גורמת ל npm להתקין את הספריה מהמטמון המקומי בלי לבקר באינטרנט כלל.
הנה השוואת זמנים קטנה בשביל לעשות גם לכם חשק:
$ time npm install --save express
real 0m3.625s
$ time npm install --offline --save express
real 0m1.646s
עכשיו רק נשאר למצוא איך להגביל את גודל ספריית ~/.npm
כדי שלא תתפוס לי את כל הדיסק.
אחד הדברים שמתכנתים הכי אוהבים לעשות כשמצביעים לנו על קוד שכתבנו ולא עובד הוא להתרגז ואז למלמל שזה עבד אצלי על המכונה. בינינו מבחינת הלקוח זה יכל לעבוד אצלך על המכונה, אצלך במקרר או על מאדים - מה שחשוב זה שעכשיו במחשב של הלקוח הקוד לא עובד.
בכל מקרה אחרי שמצאנו מה לא עבד וגם תיקנו אנחנו עדיין יכולים לבחור בין שני סיפורים -
אפשר לטעון שהבאג הזה באמת הסתתר כשכתבתי את הקוד אצלי על המכונה, ואי אפשר היה לצפות שמשהו כזה יקרה כשמעלים את הקוד לשרת. אפשר להמשיך ולטעון שאלה החיים ותמיד כשמעלים גירסא יש בעיות ואצל כולם זה ככה. וממילא לא נגרם נזק רציני ופתרנו את הבעיה תיק תק.
או שאפשר לחפש הרגלי תכנות טובים יותר, שיטות עבודה טובות יותר ומנגנוני בדיקה ו Deployment טובים יותר כדי למנוע את הבעיות האלה בעתיד.
וכן ברור ששינוי הרגלים לוקח זמן ושינוי תהליכי עבודה בארגון לוקח זמן. אם החלטתם בצוות להתחיל לכתוב בדיקות אוטומטיות למערכת הולך לקחת לכם לפחות חצי שנה עד שהבדיקות האלה יתחילו לזהות בעיות אמיתיות (לפעמים גם יותר). זה שכר הלימוד שאנחנו משלמים על המשחק הזה שנקרא קריירה בהייטק, שכר לימוד שאף פעם לא נגמר.
אחד האתגרים בפיענוח ופירוק באנדלים גדולים הוא להבין איזה מודולים נכנסו לבאנדל ולמה וובפאק בחר להכניס כל אחד מהם. שני דגלים של וובפאק שאני מאוד אוהב הופכים את האתגר הזה לממש פשוט:
הדגל display-modules מציג את כל המודולים שוובפאק הכניס לבאנדל, והדגל display-reasons מציג את הסיבות. בהפעלה לדוגמא זה נראה כך:
localhost:after ynonperek$ npx webpack --display-reasons
Hash: 1a41b54711f73da75381
Version: webpack 4.39.2
Time: 387ms
Built at: 10/23/2019 9:02:26 PM
Asset Size Chunks Chunk Names
app.js 1.16 KiB 0 [emitted] main
Entrypoint main = app.js
[0] ./src/main.js + 1 modules 387 bytes {0} [built]
single entry ./src/main.js main
| ./src/main.js 58 bytes [built]
| single entry ./src/main.js main
| ./src/panel.js 329 bytes [built]
| harmony side effect evaluation ./panel ./src/main.js 1:0-28
| harmony import specifier ./panel ./src/main.js 3:0-5
הבאנדל כולל נקודת כניסה אחת בשם ./src/main.js
שמורכבת משני קבצים: הקובץ main.js הוא נקודת הכניסה, והקובץ panel.js שיובא באמצעות import מתוך main.js. יותר מזה - אנחנו רואים ששורה 1 בקובץ main.js היא שהפעילה את ה import (בגלל ההודעה harmony side effect evaluation שנמצאת לידה), ובשורה 3 בקובץ main.js יש קריאה לפונקציה מתוך הקובץ panel המיובא.
עם האינפורמציה מול העיניים אני יכול להתחיל את האופטימיזציות - איזה קבצים גדולים מדי יש לי בבאנדל? האם אפשר להוציא חלק מהם לטעינה ב ajax? ואיזה מודולים נכנסו לבאנדל למרות שהייתי בטוח שכבר מחקתי אותם?
מאה אחוז כיסוי קוד זה לא יעיל וגם מזיק. הנה פונקציה פשוטה שתעזור להמחיש את הנקודה:
def square(x):
return 4
ברור שהפונקציה לא מעלה את הפרמטר שלה בריבוע אלא מחזירה ערך קבוע 4. זה לא מפריע לבדוק אותה ולקבל 100% כיסוי קוד:
import unittest
class TestSquare(unittest.TestCase):
def test_square(self):
self.assertEqual(square(2), 4)
if __name__ == '__main__':
unittest.main()
אבל עזבו לא יעיל, מאה אחוז כיסוי קוד זה ממש מזיק. זה מזיק כי זה אומר ששינוי קוד הולך להיות יותר איטי - במקום לשנות רק שורה אחת או מספר אחד, אנחנו צריכים לשנות גם בבדיקה שמכסה את השורה הזאת (ולפעמים שורה בודדת הולכת להשפיע על מספר בדיקות). חבילת בדיקות טובה היא כזאת שעוזרת לכם להיות בטוחים שהקוד שלכם עובד, שעוזרת לכם לבצע Refactoring בלי לפחד ששברתם משהו. באותו זמן חבילת בדיקות טובה לא צריכה להאט את קצב העבודה שלכם בצורה משמעותית, ולא צריכה לגרום לכם לחשוב פעמיים לפני שאתם משנים משהו בקוד.
מול הקוד הבא בריילס:
class Person < ApplicationRecord
validates :name, presence: true
end
אין צורך להוסיף אף שורת בדיקה. אם נוסיף בדיקה שיוצרת בן אדם חדש בלי שם ומוודאת שנזרקת שגיאה לא הרווחנו כלום אלא רק הפסדנו. הדרך היחידה של הבדיקה להיכשל היא אם אני אשנה את הלוגיקה של ה Validation כך ש"שם" הוא כבר לא שדה חובה עבור בן אדם. אבל אם החלטתי לשנות את הלוגיקה הזאת, זה קרה בכוונה והכישלון בבדיקה לא יעזור לי.
שנים של בית ספר לימדו אותי שכדאי להגיע לשיעור עם מחברת כדי לרשום את כל מה שהמורה אומרת, כי זאת הדרך להצליח במבחן. למרות האינטרנט, האוניברסיטה המשיכה באותו קו - כל מרצה לימד דברים בדרך שלו ובשביל להצליח במבחן היית צריך שהדרך שלו תהיה כתובה בדף המבחן. האפשרויות היו לכתוב או לצלם ממישהו שכתב.
מיד כשזה נגמר ועברתי לחיים האמיתיים זרקתי את כל המחברות והפסקתי לסכם. כשהחיים שלך זה תכנות אפשר למצוא הכל באינטרנט והרבה יותר מהר ממה שאתה מחפש במחברת. סטאק אוברפלואו וגוגל הם פשוט כלים טובים מדי. שנים כשהלכתי לכנסים מקצועיים לא העליתי בדעתי לכתוב כלום, מהסיבה שממילא אם משהו מעניין וחשוב אני אוכל למצוא אותו כשאגיע הביתה בחיפוש פשוט ברשת.
ודווקא בשנים האחרונות אני מבין שפשוט היה לי הכל הפוך בראש - מחברת קטנה היא כלי עבודה נהדר אם משתמשים בה נכון: אם נשתמש בה בשביל ליצור במקום בשביל לזכור. כשיש מחברת שנקראת "היום למדתי" אנחנו רוצים לפתוח אותה כל ערב כדי לכתוב מה למדתי באותו יום. והפתיחה הזאת עושה חשק במהלך היום לחפש דברים חדשים (כדי שיהיה מה לכתוב), מה שמעלה את הסיכוי שבאמת נמצא כאלה.
אז אם אתם מחפשים תירוץ טוב לחזור מהחופש ולקנות מחברת הנה שלוש סיבות שלי:
כשאנחנו כותבים דברים אנחנו משתפרים בהם. מי שכותב כל יום דף "היום למדתי" ילמד יותר דברים במהלך היום.
כשאנחנו כותבים דברים אנחנו מצליחים להתמיד גם במשימות קשות או ארוכות. משימה כמו "ללמוד Node.JS" יכולה לקחת חודשיים-שלושה של לימודים עד שמתחילים להרגיש טוב בסביבה זו. עם מחברת אפשר ליצור בקלות משימות יומיות קטנות, כאשר כל יום בערב אנחנו רושמים משימה או שתיים למחר. כשמתחילים לאבד מוטיבציה תמיד אפשר לדפדף אחורה ולראות את כל העבודה שכבר עשינו.
מחברת עוזרת לחשוב יותר לעומק על שאלות קשות. רוב האנשים אוהבים שאלות קלות, כלומר שאלות שאפשר למצוא את התשובה עליהן בחיפוש ברשת. שאלות קשות הן שאלות הרבה יותר מעניינות כמו "באיזה מצבים נעדיף להשתמש ב ES6 Classes ובאיזה מצבים ב React Hooks". אפשר ליצור טבלא כזו במחברת וכל פעם שיש לכם רעיון לכאן או לכאן לרשום אותו במקום המתאים. לעולם לא תוכלו לתת תשובה מלאה, אבל ככל שתלמדו יותר כך הטבלא תהיה מלאה יותר והמחברת תעזור לכם להתמקד.
וכן אפשר גם לציין ציורים של חיות חמודות אם זה הקטע שלכם. או להדביק מדבקות של פיירפוקס או מה שהולך היום. העיקר שיהיה לכם חשק לפתוח את המחברת ולכתוב.
לקח לי שניה וחצי להתאהב באפשרות של הגדרת קיצורי דרך באמצעות בלוק scripts בקובץ package.json, ואז עוד יומיים וחצי להתעצבן על עצמי שאני לא זוכר אף אחד מהקיצורים שהגדרתי. אם גם לכם זה קורה תשמחו לשמוע ש npm עצמו כבר מגיע עם מנגנון של השלמה אוטומטית שמתממשק ישירות ל bash שלכם.
זה עובד ככה: הפקודה npm completion
מדפיסה רצף של פקודות bash שמוסיפות למנגנון ההשלמה האוטומטית הרגיל של המעטפת גם השלמה של פקודות npm. וכן הוא מספיק חכם כדי להשלים את הסקריפטים כשכותבים npm run
. כל מה שאנחנו צריכים לעשות זה לקחת את הפלט של npm completion
ולשמור אותו לסוף קובץ ה .bashrc
שלנו, כלומר להפעיל פעם אחת את הפקודה:
npm completion >> ~/.bashrc
יוצאים מה shell ונכנסים חזרה ואז בפעם הבאה שנתחיל להקליד:
$ npm run <Tab>
נקבל השלמה אוטומטית מתוך הסקריפטים שמוגדרים בבלוק scripts ב package.json.