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

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

טיפ דוקר: שימוש ב Access Tokens במקום בסיסמאות

26/05/2021

אם אתם כותבים אימג'ים ומעלים אותם ל Docker Hub וודאי יש לכם כבר חשבון ב Docker Hub וכבר חיברתם את כלי שורת הפקודה לחשבון עם docker login. מה שלא בטוח ששמתם לב זה ש docker login יצר קובץ בשם config.json בתוך תיקיית .docker בתיקיית הבית שלכם, ובתוכו דוקר כתב ב Plain Text את הסיסמה שלכם לדוקר האב.

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

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

  1. אפשר לראות דרך ממשק הניהול שלהם איזה פעולות נעשו דרך ה Access Token, ואם היה משהו חשוד אז לבטל.

  2. אפשר להשתמש ב Access Token שונה לכל מכונה, ואז לפחות תדעו איזה מכונה נפרצה (כי אי אפשר עדיין להגדיר הרשאות ל Access Token).

  3. בחיבור דרך Access Token אי אפשר לעשות פעולות ניהוליות בחשבון כמו החלפת סיסמה.

יצירת ה Access Token היא ממש פשוטה - נכנסים לממשק הניהול של דוקר האב, בוחרים בטאב Security ולוחצים New Access Token. בשביל להתחבר עם ה Access Token מפעילים docker login וכשדוקר מבקש את הסיסמה אנחנו מדביקים את ה Access Token במקום.

והתוצאה: יש לנו קובץ config.json בתיקיית ~/.docker שמכיל את אותו Access Token במקום את הסיסמה. שמרו עליו טוב.

מבלבל בכוונה

25/05/2021

מחוץ לקונטקסט, כשאנחנו לא בעניינים, הרבה פיצ'רים מרגישים מבלבלים בכוונה. למה Dockerfile צריך את הפקודה EXPOSE? או VOLUME? למה ריאקט היה צריך את componentWillMount (שלשמחתנו כבר בוטל)? למה typeof null צריך להיות object ב JavaScript? ולמה HTML Audio צריך לקבל ילדים מכל מיני פורמטים, כשיש פורמט אחד שכל הדפדפנים יודעים לנגן?

היו רגועים. אף אחד לא ניסה לבלבל אתכם.

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

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

רק ככה אפשר להבין את כל הפינות של השפה, כולל אלה שנראות לגמרי נטולות הגיון.

גם המוח שלכם עושה את זה?

24/05/2021

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

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

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

  1. אולי רק אבדוק כמה דקות מה חדש ב ynet? (ביי ביי 10 דקות יקרות)

  2. אולי יש ספריה שמישהו כבר כתב שפותרת את זה? (ביי ביי 5 שעות שלעולם לא יחזרו)

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

  4. אולי אני בתחום הלא נכון? (ביי ביי חצי שעה על מחשבות חסרות ערך)

  5. בחברה הלא נכונה?

  6. בחיים הלא נכונים?

  7. מה קורה עם ההתחממות הגלובאלית עכשיו?

  8. רגע כבר זמן לאכול צהריים? ערב? לסגור את המחשב?

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

סטאקבליץ, נוד ו Web Assembly

23/05/2021

סטאקבליץ הודיעו לאחרונה שהצליחו לקמפל את Node.JS בתוך Web Assembly ועל הדרך חיברו את התקני הרשת שלו ל Service Worker API. הנה מה שזה אומר בשבילנו ובקצרה:

  1. סטאק בליץ בונים סביבת פיתוח בתוך הדפדפן, קצת כמו VS Code רק אונליין.

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

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

  4. אבל זה לא נגמר שם - כי כשאתה מחבר את קווי הרשת של Node.JS ל ServiceWorker API אתה בעצם משתלט על התקשורת היוצאת מהדפדפן: כל בקשת רשת שיוצאת מהדפדפן עוברת קודם דרך אותו Node.JS פנימי שרץ אצלי בתוך הדפדפן. זה אומר שדפדפן יכול "לפנות" לשרת שרץ גם הוא בתוך הדפדפן, ובאופן אוטומטי ה Service Worker יתפוס את הבקשה לפני שהיא יוצאת מהדפדפן ויעביר אותה לאותו תהליך Node.JS פנימי שרץ באותו דפדפן עצמו.

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

  6. וכאילו שזה לא מספיק, בזכות השימוש ב PWA בתוך סטאקבליץ יש כפתור "Install" שמאפשר להתקין אותם בתור אפליקציית Desktop.

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

הקישור הזה (לפתוח מכרום בלבד) ייצור גם לכם כזה שרת בדפדפן: https://stackblitz.com/fork/nextjs

שווה לנסות. העתיד של הרשת מעולם לא נראה מעניין יותר.

לא מאמין שפספסתי את זה 3 פעמים כבר

21/05/2021

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

מאז חזרתי לפחות עוד פעמיים לתיעוד, כל פעם כשהייתי צריך לבנות משהו אחר. פעם אחת בשביל להבין בדיוק איך Image עובד או למה האימג'ים שלי יוצאים כל כך גדולים ופעם נוספת כדי ללמוד על Volumes ואיך לנהל Persistency בתוך docker-compose.

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

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

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

שתי תוכניות פעולה

20/05/2021

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

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

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

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

מה זה Serverless ולמה שיהיה לכם אכפת

19/05/2021

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

הנה הקוד רק בשביל שיהיה לנו קל לדבר:

const AWS = require("aws-sdk");

const dynamo = new AWS.DynamoDB.DocumentClient();

exports.handler = async (event, context) => {
  let body;
  let statusCode = 200;
  const headers = {
    "Content-Type": "application/json"
  };

  try {
    switch (event.routeKey) {
      case "GET /items":
        body = await dynamo.scan({ TableName: "Leads" }).promise();
        break;
      case "PUT /items":
        let requestJSON = JSON.parse(event.body);
        await dynamo
          .put({
            TableName: "Leads",
            Item: {
              id: requestJSON.email,
              name: requestJSON.name,
              email: requestJSON.email,
            }
          })
          .promise();
        body = `Put item ${requestJSON.email}`;
        break;
      default:
        throw new Error(`Unsupported route: "${event.routeKey}"`);
    }
  } catch (err) {
    statusCode = 400;
    body = err.message;
  } finally {
    body = JSON.stringify(body);
  }

  return {
    statusCode,
    body,
    headers
  };
};

יש פה פחות מ-50 שורות. הלידים נשמרים בתוך טבלה בבסיס נתונים ואפשר למשוך את כל הלידים באמצעות בקשת HTTP GET פשוטה, או פשוט דרך ממשק הניהול של AWS.

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

  1. הכל היה באוויר תוך חצי שעה. בלי Deployment, בלי לבנות Database, בלי להגדיר משתמשים ומה מותר למי ומה אסור. חמישים שורות ולדרך.

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

  3. יש לוג די מפורט של הבקשות הנכנסות מנוהל אוטומטית על ידי AWS.

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

  5. לא צריך לכתוב Dockerfile ו docker-compose.yml. שתיים-שלוש לחיצות ב GUI או מספר פקודות מה CLI מספיקות כדי לחבר את כל החוטים.

בצד החסרונות שווה לשים לב ש:

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

  2. צריך לעמוד בפיתוי ולא להדביק את הקוד לתוך הממשק הגרפי אלא ליצור Pipeline מסודר של גיטהאב לבניה ו Deployment.

  3. התיעוד של AWS ארוך מדי וכולל המון מידע לא רלוונטי.

  4. אין לי מושג כמה זה יעלה בסוף.

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

טיפ באש: איך לחפש קובץ JSON עם ערך במפתח מסוים

18/05/2021

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

בשביל ש jq תוציא ערך מתוך JSON אנחנו צריכים להעביר לה את הנתיב לאותו ערך. עבור קובץ JSON שטוח הנתיב הוא פשוט סימן נקודה ואחריו שם המפתח. לדוגמה אם ה JSON שלי כולל רק מפתח אחד בשם success והערך הוא בוליאני true או false אז הפקודה:

$ jq '.success' file.json

תדפיס את הערך של המפתח success.

ומה קורה כשיש לנו ערימה של קבצי JSON שצריך לחפש בהם? מסתבר שבעזרת find ו jq אפשר להגיע רחוק. הפקודה הבאה תחפש ותדפיס את כמות קבצי ה JSON בתיקיה בהם ערך המפתח success הוא true:

find . -name '*.json' -exec jq '"{}: " + (.success|tostring)' {} \;|grep true

מעניין לשים לב:

  1. סימן {} יוחלף על ידי find בשם קובץ או תיקיה לכל קובץ שמסתיים בסיומת json
  2. פקודת ה + של jq מחברת שני דברים. הראשון הוא שם הקובץ (כפי שמגיע מ find).
  3. הסימן השני שהעברתי ל + הוא סימן קו אנכי וזאת הדרך של jq להפעיל פונקציות. בעברית נתרגם את המשפט שם ל"קח את הערך במפתח success והעבר אותו דרך הפונקציה tostring".
  4. עד לפה נקבל בכל שורה שם קובץ ואחריו הערך שבמפתח success. את זה אפשר להעביר דרך grep כדי לקבל רק את הקבצים בהם הערך הוא true.

שלושה חלומות

17/05/2021

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

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

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