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

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

איך ללמוד דרך וידאו

14/08/2022

לא צריך יותר מכמה דקות ביוטיוב כדי להיתקל בסרטים שמכילים את המילים Full Course: סרטים של שעתיים, שלוש ואפילו 8 שעות על טכנולוגיה מסוימת, בה מרצה בדרך כלל נחמד מספר ומספר על הטכנולוגיה, ואפילו בונה פרויקטים לדוגמה וכמובן הכל מצולם ומסודר. פה למשל יש מדריך פייתון של 4 שעות עם 35 מיליון צפיות: https://www.youtube.com/watch?v=rfscVS0vtbw

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

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

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

  3. סכמו לעצמכם את הנקודות המרכזיות בוידאו תוך כדי צפיה, ברמה של כל 2-3 דקות לעצור ולכתוב מה קרה שם.

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

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

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

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

שבע כפול שתיים

13/08/2022

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

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

הנה שבעה פרויקטים שאתם יכולים להתאמן עליהם בכל אחת משתי השיטות:

  1. משחק סנייק

  2. משחק טטריס

  3. בלוג

  4. צ'ט מיידי מרובה משתמשים

  5. שידור וידאו "חי" עם הערות מהצופים

  6. ניהול כספים אישי

  7. משגר משימות (בסנון הזה)

פרודוקטיביות ואג'יליות

12/08/2022

צוותים שעובדים ב Agile רגילים להשתמש בקוד בתור הדרך "לגלות" את הבעיה או מה הלקוח רוצה. בין שנים עשר העקרונות האג'יליים השניים האלה מעבירים את המסר:

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

  2. תוכנה עובדת היא המדד העיקרי להתקדמות.

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

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

אבל הבעיה שאנחנו לא חיים בספרינט בודד.

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

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

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

  2. תשומת לב מתמשכת למצויינות טכנית ועיצוב ותכנון נכון מגדילים את היכולת האג'ילית.

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

טיפ טייפסקריפט: יצירת שלד לממשק מהרשת

11/08/2022

החבילה json-to-ts היא חבילת JavaScript מדליקה (כתובה בטייפסקריפט כמובן) שיכולה לחסוך הרבה עבודה כשכותבים קוד שעובד מול APIs. התפקיד שלה הוא פשוט לקחת אוביקט JSON ולהפוך אותו ל Interface בטייפסקריפט, ואנחנו יכולים להשתמש בה בתוך תוכנית בצורה הבאה:

import JsonToTS from 'json-to-ts';
import fetch from 'node-fetch';
const url = process.argv[2];

async function main() {
  const json = (await (await fetch(url)).json());
  JsonToTS(json).forEach( typeInterface => {
    console.log(typeInterface)
  })
}

main();

ניקח URL לדוגמה שמחזיר אוביקט JSON:

$ curl https://swapi.dev/api/people/1/ | jq

{
  "name": "Luke Skywalker",
  "height": "172",
  "mass": "77",
  "hair_color": "blond",
  "skin_color": "fair",
  "eye_color": "blue",
  "birth_year": "19BBY",
  "gender": "male",
  "homeworld": "https://swapi.dev/api/planets/1/",
  "films": [
    "https://swapi.dev/api/films/1/",
    "https://swapi.dev/api/films/2/",
    "https://swapi.dev/api/films/3/",
    "https://swapi.dev/api/films/6/"
  ],
  "species": [],
  "vehicles": [
    "https://swapi.dev/api/vehicles/14/",
    "https://swapi.dev/api/vehicles/30/"
  ],
  "starships": [
    "https://swapi.dev/api/starships/12/",
    "https://swapi.dev/api/starships/22/"
  ],
  "created": "2014-12-09T13:50:51.644000Z",
  "edited": "2014-12-20T21:17:56.891000Z",
  "url": "https://swapi.dev/api/people/1/"
}

וזה מה שיוצא כשאני מעביר אותו לתוכנית שלי:

$ node tsify.mjs https://swapi.dev/api/people/1/

interface RootObject {
  name: string;
  height: string;
  mass: string;
  hair_color: string;
  skin_color: string;
  eye_color: string;
  birth_year: string;
  gender: string;
  homeworld: string;
  films: string[];
  species: any[];
  vehicles: string[];
  starships: string[];
  created: string;
  edited: string;
  url: string;
}

אז נכון צריך לסדר את השם RootObject וצריך להפוך את כל המערכים מ any[] לסוג הנכון שלהם, אבל במהלך כתיבת קוד כלי כזה יכול לחסוך הרבה זמן. עכשיו רק נשאר לכתוב vim plugin שייתן לי לכתוב בקוד משהו כמו:

interface https://swapi.dev/api/people/1/

ויהפוך את זה אוטומטית לתוצאה של הסקריפט.

קוד יותר חשוב

10/08/2022

בין הסוגים של קוד שאנחנו כותבים:

  1. קוד שגורם לדברים לעבוד מהר יותר

  2. קוד שפותר באג ללקוח

  3. קוד שחוסך עבודה למתכנתת שכתבה אותו

  4. קוד שמוסיף פיצ'ר שכל הלקוחות רואים

  5. קוד שמוסיף פיצ'ר שרק חלק מהלקוחות רואים

  6. קוד שגורם לדברים להיראות יפה יותר

  7. טקסט שמסביר מה קוד שכתבתי עושה

  8. קוד שמשפר את החוויה כשיש מצב שגיאה

  9. קוד שבודק קוד אחר

  10. קוד שמשפר את החיים של מתכנתים אחרים בצוות

  11. קוד שעוזר לי להבין רעיונות חדשים

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

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

שלב 2

09/08/2022

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

ואז התחילו הבעיות:

  1. הבוט החדש לא הצליח לפצל הודעות ארוכות כמו שצריך

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

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

  1. את הקוד כתבתי ישירות על שרת ה Production ב vi.

  2. את הטוקן של טלגרם כתבתי Hard Coded בתוך הסקריפט.

  3. על Source Control או בדיקות לא היה מה לדבר.

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

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

  1. להעביר את הקוד לגיט מסודר.

  2. להוסיף בדיקות ל flows החשובים או לפחות לאלה שהיו שבורים.

  3. לבנות מנגנון Deploy מסודר שישתמש ב CI (במקום להעתיק קבצים עם rsync).

  4. להעביר החוצה סודות למשתני סביבה.

וזה בדיוק היה שלב 2 בפיתוח הבוט, שאולי חלקכם שמתם לב אליו בפירסומים והמחיקות שעשיתי במהלך אתמול. הקוד המעודכן של הבוט עלה לגיטהאב ואתם מוזמנים לקרוא אותו כאן: https://github.com/ynonp/blog-to-telegram

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

תוספת שניה לקוד היא הקובץ .github/workflows שמעלה מכונה שמתקינה את כל התלויות ומריצה את התוכנית פעם ביום בשעה שמונה בבוקר. אני מקווה שהמעבר ל Github Action יגרום לסקריפט להיות יותר יציב ולא להישבר גם אם השרת עמוס או שודרג. זה ה Workflow:

# This workflow will install Python dependencies, run tests and lint with a single version of Python
# For more information see: https://help.github.com/actions/language-and-framework-guides/using-python-with-github-actions

name: publish-daily-post-to-telegram

on: 
  workflow_dispatch:
  schedule:
    - cron:  "0 8 * * *" 


permissions:
  contents: read

jobs:
  publish:

    runs-on: ubuntu-latest

    steps:
    - uses: actions/checkout@v3
    - name: Set up Python 3.10
      uses: actions/setup-python@v3
      with:
        python-version: "3.10"
    - name: Install dependencies
      run: |
        python -m pip install --upgrade pip
        if [ -f requirements.txt ]; then pip install -r requirements.txt; fi
    - name: run
      env:
        TELEGRAM_TOKEN: ${{ secrets.TELEGRAM_TOKEN }}
      run: |
        python blog_to_telegram/publish_daily_post.py

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

כמובן ששלב שני הוא לא סוף הדרך. נשאר עוד:

  1. להוסיף Workflow שכל פעם שדוחפים קוד חדש יריץ אוטומטית את כל הבדיקות.

  2. להוסיף בדיקות (כרגע יש רק בדיקות למנגנון פיצול ההודעות).

  3. להוסיף קובץ Readme ותיעוד בתוך הקוד.

אבל זה יחכה לבאג הבא או ל Pull Request מכם. מה שיבוא קודם.

עלות חודשית

08/08/2022

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

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

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

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

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

  1. לכתוב סקריפטים קטנים בפייתון או ב bash, אפילו שאנחנו כותבים קוד ב Java.

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

  3. לבנות ממשקים או אפליקציות קטנות לדברים "שוליים" כמו ממשק שמראה למי בחברה יש יום הולדת החודש.

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

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

שלוש דוגמאות לתיעוד טוב מפרויקטי קוד פתוח

07/08/2022

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

המשך קריאה

מדריך logrotate

06/08/2022

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

המשך קריאה

היום למדתי: איך למצוא כתובת IP בלי ifconfig

05/08/2022

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

הפקודה ifconfig היא מיושנת ויש לה כמה מגבלות שלעולם לא יתוקנו, ולכן הפקודה המודרנית והמומלצת לשימוש היא ip. בשביל למצוא כתובת ip של מכונה אני יכול להפעיל:

$ ip addr show
1: lo: <LOOPBACK,UP,LOWER_UP> mtu 65536 qdisc noqueue state UNKNOWN group default qlen 1000
    link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00
    inet 127.0.0.1/8 scope host lo
       valid_lft forever preferred_lft forever
    inet6 ::1/128 scope host
       valid_lft forever preferred_lft forever
2: enp0s1: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc fq_codel state UP group default qlen 1000
    link/ether 52:54:00:1f:e8:4c brd ff:ff:ff:ff:ff:ff
    inet 192.168.64.4/24 brd 192.168.64.255 scope global dynamic enp0s1
       valid_lft 56632sec preferred_lft 56632sec
    inet6 fd5e:dcce:7fd0:a7fb:5054:ff:fe1f:e84c/64 scope global dynamic mngtmpaddr noprefixroute
       valid_lft 2591997sec preferred_lft 604797sec
    inet6 fe80::5054:ff:fe1f:e84c/64 scope link
       valid_lft forever preferred_lft forever
3: br-20cce5ed46b0: <NO-CARRIER,BROADCAST,MULTICAST,UP> mtu 1500 qdisc noqueue state DOWN group default
    link/ether 02:42:2a:b6:7a:9c brd ff:ff:ff:ff:ff:ff
    inet 172.20.0.1/16 brd 172.20.255.255 scope global br-20cce5ed46b0
       valid_lft forever preferred_lft forever
4: br-9946704f08d6: <NO-CARRIER,BROADCAST,MULTICAST,UP> mtu 1500 qdisc noqueue state DOWN group default
    link/ether 02:42:c3:91:58:ec brd ff:ff:ff:ff:ff:ff
    inet 172.18.0.1/16 brd 172.18.255.255 scope global br-9946704f08d6
       valid_lft forever preferred_lft forever
5: docker0: <NO-CARRIER,BROADCAST,MULTICAST,UP> mtu 1500 qdisc noqueue state DOWN group default
    link/ether 02:42:4d:37:b0:5c brd ff:ff:ff:ff:ff:ff
    inet 172.17.0.1/16 brd 172.17.255.255 scope global docker0
       valid_lft forever preferred_lft forever

וכמו עם ifconfig גם פה אני יכול לסנן את כל הבלאגן:

$ ip addr show | grep -w inet
    inet 127.0.0.1/8 scope host lo
    inet 192.168.64.4/24 brd 192.168.64.255 scope global dynamic enp0s1
    inet 172.20.0.1/16 brd 172.20.255.255 scope global br-20cce5ed46b0
    inet 172.18.0.1/16 brd 172.18.255.255 scope global br-9946704f08d6
    inet 172.17.0.1/16 brd 172.17.255.255 scope global docker0

אפשר גם להפעיל ולכבות איתה ממשקי רשת, אבל המתג שאני אהבתי הוא בכלל האות n, שמציגה את כל השכנים ברשת מפרוטוקול arp:

$ ip n
192.168.64.1 dev enp0s1 lladdr 52:ed:3c:d3:64:64 REACHABLE
fd5e:dcce:7fd0:a7fb:10c8:64d2:15b:ca05 dev enp0s1 lladdr 52:ed:3c:d3:64:64 router STALE
fe80::50ed:3cff:fed3:6464 dev enp0s1 lladdr 52:ed:3c:d3:64:64 router STALE

דף התיעוד הוא כאן: https://linux.die.net/man/8/ip

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

$ alias ifconfig="ip addr show"

ולהרגיש כאילו כלום לא השתנה.