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

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

שאלת ראיונות עבודה: Docker Compose

16/07/2020

נתון קובץ docker-compose.yml הבא:

version: '3.8'

services:
  db:
    image: postgres:latest
    environment:
      POSTGRES_PASSWORD: docker
      POSTGRES_DB: wordcount_dev
      POSTGRES_USER: docker
    volumes:
      - database_data:/var/lib/postgresql/data

  webapp:
    image: pydocker1-test:latest
    depends_on:
      - db
    ports:
      - 5000:5000

volumes:
  database_data:
    driver: local

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

ואם אתם לא בטוחים מה התשובה מוזמנים לבוא היום למפגש Docker ולגלות בעצמכם.

הזדמנויות

15/07/2020

הי כולם,

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

  1. אתם יכולים ללמוד כל נושא שבעולם מהמורים הטובים בעולם והרוב בחינם או כמעט בחינם. ויש לכם את כל היום כדי להשקיע בזה. שנה של ניסיון ב Machine Learning? קיבלת! שנה של ניסיון כמפתחת Front End? אין בעיה. ביבי משלם את החשבון.

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

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

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

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

איך ללמוד עם דדליינים?

14/07/2020

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

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

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

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

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

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

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

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

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

האם יש טעם ללמוד CSS לעומק?

13/07/2020

שאלה שחוזרת בפורומים וגם אני שואל את עצמי כל פעם עם טכנולוגיה אחרת -

״האם יש טעם ללמוד לעומק CSS? אולי אף פעם לא אצטרך את זה״

״האם יש טעם ללמוד גם Webpack? אני מסתדר טוב עם react-create-app״

״האם יש טעם ללמוד על React Hooks? הולך לי טוב עם קלאסים״

הקטע הוא שאם אתה שואל את השאלה הזאת אתה כבר לא בכיוון. מתכנתי Front End לומדים CSS כל הזמן, וכל יום לומדים דברים חדשים על CSS. מתכנתי React ממשיכים ללמוד כל הזמן דברים חדשים, על קלאסים, על הוקס ועל עוד מיליון נושאים מסביב.

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

(עכשיו אפשר לשאול שאלה יותר ממוקדת - מה המינימום CSS שצריך לדעת בשביל להתקבל לעבודה בתור מתכנת Front End? על זה גם אני שברתי את הראש די הרבה. בסוף הגעתי לרשימת נושאים ובניתי ממנה את פרק CSS בקורס פרונטאנד פה באתר).

פימסלר ודואולינגו

12/07/2020

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

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

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

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

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

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

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

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

שידרוגים ״לא כמו בספר״

11/07/2020

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

constructor: Function components don’t need a constructor. You can initialize the state in the useState call. If computing the initial state is expensive, you can pass a function to useState.

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

וזה מסתדר מעולה למי שעבד לפי הכללים ובאמת השתמש ב constructor רק בשביל לאתחל משתני State. אגב בדף התיעוד על Class Components מופיע המשפט הבא (בכתיב מודגש) רק בשביל לוודא שאנחנו מיושרים על הכלל:

If you don’t initialize state and you don’t bind methods, you don’t need to implement a constructor for your React component.

עד לפה תיאוריה :)

בחיים האמיתיים לא כל המשתנים נשמרים כמשתני State ומאותחלים בבנאי מכל מיני סיבות. הנה דוגמא קצרה שראיתי השבוע מתוך ספריית azure-devops-ui:

import * as React from "react";
import { Dropdown } from "azure-devops-ui/Dropdown";
import { Observer } from "azure-devops-ui/Observer";
import { DropdownMultiSelection } from "azure-devops-ui/Utilities/DropdownSelection";
import { dropdownItems } from "./Data";

export default class DropdownMultiSelectExample extends React.Component {

    private selection = new DropdownMultiSelection();

    public render() {
        return (
            <div style={{ margin: "8px" }}>
                <Observer selection={this.selection}>
                    {() => {
                        return (
                            <Dropdown
                                ariaLabel="Multiselect"
                                actions={[
                                    {
                                        className: "bolt-dropdown-action-right-button",
                                        disabled: this.selection.selectedCount === 0,
                                        iconProps: { iconName: "Clear" },
                                        text: "Clear",
                                        onClick: () => {
                                            this.selection.clear();
                                        }
                                    }
                                ]}
                                className="example-dropdown"
                                items={dropdownItems}
                                selection={this.selection}
                                placeholder="Select an Option"
                                showFilterBox={true}
                            />
                        );
                    }}
                </Observer>
            </div>
        );
    }
}

עכשיו לא באנו לפה לדבר על המשתנה selection שמאותחל בתור Member Field במקום בתור State Variable, אלא על השדרוג. אם מחר בבוקר נרצה לשדרג את זה מקלאס לפונקציה, לא מספיק לדעת את כל התיאוריה של ריאקט - צריך גם לשבור את הראש ולהבין מי כתב את המשתנה selection, למה הוא לא כתב אותו לפי הכללים ואיך הוא צריך לעבוד במבנה החדש.

לפעמים התשובה קלה (הופכים אותו למשתנה State) אבל לפעמים היא דורשת Refactoring משמעותי של הקוד ושל הקוד שסביבו. ריפקטורינג שהופך הרבה יותר קשה ככל שעבר יותר זמן מכתיבת הקוד המקורי.

בקיצור לטיפ היומי - כשאנחנו כותבים קוד לפי הכללים אנחנו דואגים לעתיד: אנחנו בונים לעצמנו מסלול שידרוג קל יותר ליום בו התחביר ישתנה ונרצה להתקדם. וכן אני יודע שלא תמיד קל לכתוב לפי הכללים, במיוחד כשאתם רק מתחילים לעבוד עם טכנולוגיה ולא יודעים בעל פה את כל התיעוד. לפחות בריאקט אני יכול לעזור. עוד שבוע וקצת אני מתחיל עבודת מנטורינג עם קבוצה קטנה של מתכנתים שרוצים ללמוד לכתוב ריאקט מסודר ולפי הכללים. בקבוצה אני קורא קוד אמיתי שאתם כותבים כדי לזהות תבניות שלא מסתדרות עם שיטת החשיבה של ריאקט ועוזר לכם להיגמל מהן ולמצוא פיתרונות טובים יותר. אנחנו גם נכתוב קוד יחד ונתמודד עם בעיות מהעולם האמיתי כדי להתאמן על שיטת חשיבה ריאקטית. מתחילים ב 19/7 ויש כבר קבוצת סלאק פעילה למקדימים. פרטים ורישום בקישור https://www.tocode.co.il/bootcamps/react.

קורס אימייל חדש: שש תוכניות ללימוד פייתון

10/07/2020

הי חברים,

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

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

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

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

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

גם ידע הוא תשתית

09/07/2020

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

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

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

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

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

פחחח אני כותב את זה ביומיים (או: החלק הקשה במערכות תוכנה)

08/07/2020

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

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

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

החיים בפרודקשן

07/07/2020

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

קחו את קוד ריילס הבא לדוגמא:

add_column :bundles_users, :joining_date, :date

execute <<-SQL
    UPDATE bundles_users SET joining_date = created_at
    WHERE joining_date is NULL
SQL

change_column :bundles_users, :joining_date, :date, null: false, default: -> { 'CURRENT_DATE' }

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

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

  2. אחרי זה מעתיקים את כל הערכים מעמודת created_at לעמודה החדשה שיצרנו

  3. ובסוף מוסיפים NOT NULL Constraint על העמודה החדשה כדי ששורות חדשות לא ייכנסו עם ערך NULL.

יכולים לראות איפה זה נשבר?

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

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