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

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

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

02/09/2021

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

aaaabbccc

אז אנחנו מחליפים את רצף ה a-ים ב a4, את רצף ה b-ים ב b2 ואת רצף ה c-ים ב c3 ומקבלים:

a4b2c3

אם התוצאה ארוכה יותר מהמחרוזת המקורית יש להחזיר את המחרוזת המקורית, ואם התוצאה קצרה יותר יש להחזיר את התוצאה המכווצת.

המשך קריאה

התור בפוטו צפון

01/09/2021

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

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

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

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

קריטריון

31/08/2021

האם הוא פותר בעיות מהר?

האם הוא רואה את כל מקרי הקצה הרלוונטיים?

האם הפיתרונות שלה תמיד הכי יעילים?

האם התקשורת איתה טובה?

האם הוא יתאמץ לפתור בעיה בכוחות עצמו?

האם הוא ידע לבקש עזרה כשצריך?

האם היא תסכים ללמוד טכנולוגיה חדשה כשהפרויקט דורש את זה?

האם היא לומדת מהר?

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

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

בואו נכתוב שרת GraphQL ב Node.JS כדי לראות איך זה עובד

30/08/2021

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

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

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

https://github.com/ynonp/express-graphql-demo

המשך קריאה

רגע, לא כולם משתמשים בקוברנטס???

29/08/2021

את הכותרת הבאה בהאקרניוז קלטתי מקילומטר: "עם עבודת 9 עד 5 ושני ילדים, הצלחתי לבנות את ה MVP הראשון שלי". בום. חייב לראות מה זה ומי זה ומה הקסם הסודי. שתי פיסקאות פנימה הגיעה רשימת הטכנולוגיות: Laravel, jQuery, MySQL ואיחסון על Digital Ocean. לפי המחיר של 5$ לחודש אני די בטוח שלא מדובר בקלאסטר הקוברנטס הנוצץ שלהם.

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

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

במקרה של Free Option Screener, אתר עם עיצוב מכוער הוא לא חיסרון אלא הזדמנות לשחק עם React ו AntD אחרי שאתה יודע בדיוק מה אתה רוצה לבנות. אתר שמאוחסן על VM הוא קורבן מעולה לניסוי במעבר ל Kubernetes, כי יש למה להשוות וכבר יש לך Workflow של פיתוח והעלאת גירסה.

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

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

מה ההבדל בין `docker compose` ל `docker-compose` ?

28/08/2021

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

הסיפור הרשמי של שתי הפקודות הוא פשוט - הכלי docker-compose הוא סקריפט פייתון, הוא היה שם קודם וקוד המקור שלו (אם מצאתי נכון) הוא כאן: https://github.com/docker/compose.

לעומתו docker compose מסומן בתור compose גירסה 2, כתוב ב go וקוד המקור שלו (בהנחה שמצאתי נכון) הוא כאן: https://github.com/docker/compose-cli.

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

  1. גירסה 2, כלומר docker compose תומכת ביצירת קונטיינרים בעננים של מייקרוסופט ואמזון באמצעות אינטגרציה מובנית. מספיק ליצור context, לכתוב docker compose up ויש לכם קונטיינרים באוויר ב ECS או ACI.

  2. על הלינוקס שלי, בגירסה 2 כשאני מעלה מכונות עם docker compose up ואז לוחץ Ctrl+C אני נשאר תקוע על איזה הודעת "המכונות עצרו". בגירסת docker-compose up לחיצה על Ctrl+C עוצרת את המכונות אבל גם מחזירה אותי למסוף.

  3. גירסה 1 כלומר docker-compose תומכת בכתיבת הלוג ל syslog ונראה שגירסה 2 לא. במילים אחרות קובץ קומפוז כזה:

version: '3'
services:
  worker:
    image: // image
    logging:
      driver: syslog
      options:
        syslog-address: "udp://XXX.papertrailapp.com:XXXX"
        tag: "{{.Name}}/{{.ID}}"

שמצאתי כאן בסטאק אוברפלו ובמקומות נוספים יעבוד עם docker-compose up אבל לא יעבוד עם docker compose up.

  1. קומפוז גירסה 2 (הגירסה בלי המקף) תומך ב Apple Silicon.

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

טיפ JavaScript: שדה אופציונאלי באוביקט

27/08/2021

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

const key = 'name';

const data = {
    [key]: 'bob'
};

שמחזיר את האוביקט עם המפתח name ובו הערך bob.

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

const words = ['one', 'two', 'three'];
const wordsObject = words.map(w => ({ [w]: true })).reduce((a, b) => ({ ...a, ...b }));

// now wordsObject = { one: true, two: true, three: true }

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

const s1 = getStatus(task1);
// returns { status: 'PROCESSING' }

const s2 = getStatus(task2);
// returns { status: 'DONE', result: 8 }

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

function getStatus(task) {
    return {
        status: task.status,
        ...(task.status === 'DONE' && { result: task.result }),
    };
}

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

// prints: { status: 'PROCESSING' }
console.log(getStatus({ status: 'PROCESSING', result: 7 }));

// prints: { status: 'DONE', result: 7 }
console.log(getStatus({ status: 'DONE', result: 7 }));

מדריך Vue למתחילים - חלק 7 - ניהול מידע גלובאלי

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

פוסטים קודמים בסידרה:

  1. פרק 1 - פיתוח קומפוננטה ראשונה

  2. פרק 2 - תקשורת בין קומפוננטות

  3. פרק 3 - תבניות דינאמיות

  4. פרק 4 - ממשק ההרכבה Composition API

  5. פרק 5 - דוגמת פיתוח נגן YouTube ב Vue

  6. פרק 6 - יישומי Single Page Apps עם Vue Router

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

המשך קריאה

צעדים ראשונים עם grpc

25/08/2021

ספריית gRPC היא ספריית קוד פתוח מבית גוגל שתפקידה לחבר בין סרביסים במערכת שלכם בצורה יעילה ומהירה. אפשר לחשוב עליה בתור תחליף מהיר יותר ל REST APIs כאשר הרווח המרכזי של gRPC מבחינת ביצועים מגיע מהשימוש ב HTTP/2 ובשליטה טובה יותר של הספריה בפרוטוקול. מבחינת חווית משתמש הספריה מאפשרת כתיבת תוכניות מבוזרות כאילו אנחנו רצים על אותה מכונה באמצעות שימוש נרחב ב Stub-ים.

הספריה מגיעה עם תמיכה רשמית ב 11 שפות תכנות ואפשר למצוא חיבורים לעוד עשרות בחיפוש פשוט ברשת. בפוסט זה אציג שתי דוגמאות בשפת Python לשימוש ב gRPC בהתחלה כדי לכתוב שרת Echo ולאחר מכן להפוך אותו ל Chat.

המשך קריאה

זהירות - קוד עובד לפניך!

24/08/2021

המדד הכי גרוע לאיכות קוד הוא "עובד/לא עובד" ואני תמיד אעדיף קוד נכון שלא עובד על פני קוד עובד ולא נכון. ועם זה הלכתי לקשקש קצת עם JavaScript היום ובפרט עם testing-library. שימו לב לבדיקה הבאה שעוברת:

it('Increases after I click the button', async () => {
  const screen = render(Counter);
  const button = screen.getByRole('button', { name: 'Click Here' });
  await userEvent.click(button);

  expect(screen.getByText(/clicked 1 times/)).toBeTruthy();
});

זה קוד בדיקה למונה לחיצות שמוודא שאחרי שלחצתי על כפתור יופיע הטקסט clicked 1 times.

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

await userEvent.click(button);

זה רעיון יפה רק ש userEvent.click לא מחזיר Promise. קוד הבדיקה הבא (שגם עובד) הוא שקול לתוכנית הראשונה:

it('Increases after I click the button', async () => {
  const screen = render(Counter);
  const button = screen.getByRole('button', { name: 'Click Here' });
  userEvent.click(button);
  await undefined;

  expect(screen.getByText(/clicked 1 times/)).toBeTruthy();
});

אה וצריך לציין - אם מוחקים את שורת ה await ונשארים רק עם זה:

it('Increases after I click the button', async () => {
  const screen = render(Counter);
  const button = screen.getByRole('button', { name: 'Click Here' });
  userEvent.click(button);

  expect(screen.getByText(/clicked 1 times/)).toBeTruthy();
});

הבדיקה נכשלת.

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

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

it('Increases after I click the button', async () => {
  const screen = render(Counter);
  const button = screen.getByRole('button', { name: 'Click Here' });
  userEvent.click(button);

  expect(screen.findByText(/clicked 1 times/)).toBeTruthy();
});