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

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

היום למדתי - איפוס הגדרות postcss בפרויקט vite

21/02/2024

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

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

module.exports = {
  plugins: {
    tailwindcss: {},
    autoprefixer: {},
  },
};

ואז יצרתי פרויקט vite חדש לגמרי בתיקייה:

/Users/ynonp/a/b/c/d/helloworld

הפעלתי npm run build בתיקיה וקיבלתי את הודעת השגיאה הבאה:

> helloworld@0.0.0 build
> tsc && vite build

vite v5.1.3 building for production...
transforming (1) index.htmlnode:internal/process/promises:289
            triggerUncaughtException(err, true /* fromPromise */);
            ^

[Failed to load PostCSS config: Failed to load PostCSS config (searchPath: /Users/ynonp/a/b/c/d/helloworld): [Error] Loading PostCSS Plugin failed: Cannot find module 'tailwindcss'
Require stack:
- /Users/ynonp/postcss.config.js

(@/Users/ynonp/postcss.config.js)
Error: Loading PostCSS Plugin failed: Cannot find module 'tailwindcss'
Require stack:
- /Users/ynonp/postcss.config.js

(@/Users/ynonp/postcss.config.js)
    at load (file:///Users/ynonp/a/b/c/d/helloworld/node_modules/vite/dist/node/chunks/dep-stQc5rCc.js:28883:11)
    at file:///Users/ynonp/a/b/c/d/helloworld/node_modules/vite/dist/node/chunks/dep-stQc5rCc.js:28908:16
    at Array.map (<anonymous>)
    at plugins (file:///Users/ynonp/a/b/c/d/helloworld/node_modules/vite/dist/node/chunks/dep-stQc5rCc.js:28907:8)
    at processResult (file:///Users/ynonp/a/b/c/d/helloworld/node_modules/vite/dist/node/chunks/dep-stQc5rCc.js:28977:14)
    at file:///Users/ynonp/a/b/c/d/helloworld/node_modules/vite/dist/node/chunks/dep-stQc5rCc.js:29107:14]

Node.js v21.5.0

וכן זה לקח הרבה יותר זמן לגלות שהסיבה להודעה היא בעצם הקובץ postcss.config.js שנמצא בתיקיית הבית שלי.

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

import { defineConfig } from 'vite'

// https://vitejs.dev/config/
export default defineConfig({
  css: {
    postcss: {},
  },
})

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

עוד מחשבה על תבנית ה index.ts שמייצא הכל

20/02/2024

בואו נדמיין פרויקט ריאקט שיש בו תיקייה בשם src/components/HomePage ובתוכה ערימה של תיקיות וקובץ אחד בשם index.ts:

.
├── EmptyState
│   ├── EmptyState.tsx
│   └── index.ts
├── ErrorState
│   ├── ErrorState.tsx
│   ├── ErrorState.types.ts
│   └── index.ts
├── RecentArticles
│   ├── RecentArticles.tsx
│   ├── RecentArticles.types.ts
│   └── index.ts
├── RecentArticlesCard
│   ├── RecentArticleCard.tsx
│   ├── RecentArticleCard.types.ts
│   └── index.ts
├── RecentArticlesContent
│   ├── RecentArticlesContent.tsx
│   ├── RecentArticlesContent.types.ts
│   └── index.ts
└── index.ts

תוכן הקובץ index.ts יהיה:

export * from './EmptyState';
export * from './ErrorState';
export * from './RecentArticles';
export * from './RecentArticlesCard';
export * from './RecentArticlesContent';

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

המשך קריאה

איך ליצור דף Github Pages לפרויקט שלך

19/02/2024

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

המשך קריאה

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

18/02/2024

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

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

זה היה אחרי שלוש שנים של עבודה על Atom. שלוש שנים של ניסיונות לשפר את הביצועים. שלוש שנים של התמודדות עם האתגר של כתיבת Desktop Application מהיר בכלים ווביים.

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

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

פיתרון Advent Of Code 2023 יום 12 ב Scala

17/02/2024

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

המשך קריאה

יותר מדי אינפורמציה

16/02/2024

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

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

"סיימתי קורס פייתון של 40 שעות וידאו ביודמי - היה מעולה ולמדתי המון"

"תגיד מה דעתך על AWS? התחלתי ללמוד להסמכה של CLF-C01 כי הבנתי שחייבים את זה בשביל להתקבל לעבודה כ MLOps"

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

אבל מעגל הקסמים הזה לא מסתיים.

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

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

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

זה לא מספר השורות

15/02/2024

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

def to_list_of_digits(s: str) -> list[int]:
    result = []
    for ch in s:
        if ch.isdigit():
            result.append(int(ch))
    return result

וזה עובד! אבל אז אנחנו מגלים שבעצם בפייתון יש מנגנון שנקרא List Comprehension ושאנחנו יכולים לכתוב את הפונקציה בצורה הרבה יותר קצרה:

def to_list_of_digits(s: str) -> list[int]:
    return [int(ch) for ch in s if ch.isdigit()]

עכשיו השאלה - האם נישאר עם הפונקציה? אולי עדיף לקחת את השורה האחת ופשוט לשים אותה במקום הקריאה? מי החליט שצריכה להיות כזאת פונקציה בכלל? ואולי אם הייתי מראש יודע על List Comprehension לא הייתי כותב את זה כפונקציה?

התשובה מורכבת אבל כדאי להשאיר בראש כמה נקודות-

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

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

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

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

מתי בכל זאת לתרום לפרויקט קוד פתוח?

14/02/2024

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

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

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

  1. כשהיא באה מתוך היכרות מעמיקה עם הפרויקט והמגבלות שלו.

  2. כשהיא באה מתוך כוונה אמיתית לשפר את מצב העניינים באקוסיסטם של הפרויקט.

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

טיפ פייטסט: איך ועל איזה בדיקות לדלג?

13/02/2024

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

[pytest]
markers =
    integration: integration test
    slow: slow test
    version: tests to run before deploying a new version

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

@pytest.mark.integration
def test_website():
    pass

ולהריץ את כל הבדיקות שמסומנות בקטגוריה integration:

$ pytest -m integration

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

$ pytest -m "not integration"

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

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

ננסה לענות על זה בכמה כללי אצבע-

  1. רוב הפיצ'רים של בדיקות הם יותר טובים כשלא משתמשים בהם. זה נכון לגבי mock-ים, לגבי before ו after וכן גם לגבי דילוגים. אם אתם יכולים בלי זה עדיף.

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

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

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

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

זה צריך לקחת שבועיים

12/02/2024

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

  1. לא בדקתי, אבל נראה לי שזה מה שהיה לוקח לי.

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

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

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

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

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

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

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