ToCode
الذهاب إلى القناة على Telegram
1 420
المشتركون
لا توجد بيانات24 ساعات
+27 أيام
-230 أيام
أرشيف المشاركات
1 419
בנוסף לפונקציה
advanceTimersByTime אני רואה עוד דבר חדש: הקריאה לפונקציה act, שעוטפת את advanceTimersByTime. פונקציית act שייכת ל react-testing-library והיא נועדה לאפשר ל testing library לזהות שהיה שינוי ולרנדר מחדש את הקומפוננטה. בדרך כלל כשאנחנו עובדים עם שעונים אמיתיים ועם find הדבר הזה קורה אוטומטית, אבל במעבר לשעון מזויף אנחנו מאבדים את הפינוק וצריכים להגיד בצורה מפורשת ל testing library שקידום השעון גם יגרום ל render מחדש.
עכשיו באותה קלות אני יכול לכתוב קוד שידמה המתנה של 10 שניות ויוודא את הערך של השעון:
test('after 10 seconds the value changes to 10', () => {
render(<Timer />);
act(() => {
jest.advanceTimersByTime(10000);
});
expect(screen.getByText(/10/)).toBeInTheDocument();
});
וגם הוא ירוץ בצורה מיידית בזכות השעון המזויף.
## בדיקת עצירה והפעלה מחדש של השעון
עכשיו שאני יודע להזיז את הזמן קדימה אפשר לנסות לעצור את השעון ולראות שהוא באמת לא מתקדם כשהשניות עוברות. הנה הבדיקה הבאה:
test('clicking "stop" stops the timer', () => {
render(<Timer />);
const stopButton = screen.getByRole('button', { name: /stop/i });
userEvent.click(stopButton);
act(() => {
jest.advanceTimersByTime(1000);
});
expect(screen.getByText(/0/)).toBeInTheDocument();
});
## בדיקת שינוי קצב השעון
בדיקה אחרונה לקומפוננטה היא שינוי קצב השעון, וגם אותה אני כותב יחסית בקלות אחרי כל מה שראינו:
test('after changing the speed, the timer moves faster according to the new value', () => {
render(<Timer />);
const speed = screen.getByRole('spinbutton');
userEvent.clear(speed);
userEvent.type(speed, "500");
act(() => {
jest.advanceTimersByTime(1000);
});
expect(screen.getByText(/2/)).toBeInTheDocument();
});
הפעם כשאני מתקדם בשניה אני מצפה שהמספר יעלה ל-2, ובאמת כך קורה.1 419
# בדיקות שעונים עם react-testing-library
ספריית react-testing-library תומכת בצורה מלאה בקומפוננטות שעושות דברים ברקע בצורה אסינכרונית ובבדיקה שלהן. בפוסט זה נדבר על שעונים ונראה איך לבדוק קומפוננטות שמושפעות מזמן.
## הקומפוננטה
אני מתחיל עם הקומפוננטה הבאה:
import { useState, useEffect } from 'react';
export default function Timer() {
const [ms, setMs] = useState(1000);
const [ticks, setTicks] = useState(0);
const [ticking, setTicking] = useState(true);
useEffect(() => {
let clock = null;
if (ticking) {
clock = setInterval(() => {
setTicks(t => t + 1);
}, ms);
}
return () => {
clearInterval(clock);
};
}, [ticking, ms]);
function start() {
setTicking(true);
}
function stop() {
setTicking(false);
}
return (
<div>
<p>Ticks: {ticks}</p>
{ticking
? <button onClick={stop}>Stop</button>
: <button onClick={start}>Start</button>
}
<input type="number" value={ms} onChange={(e) => setMs(e.currentTarget.value)} />
</div>
);
}
הקומפוננטה מייצגת שעון אסינכרוני. כשהקומפוננטה נכנסת למסך השעון במצב "דולק" ואז כל שניה הקומפוננטה מציגה מספר עולה (מתחיל ב-0). אפשר ללחוץ על כפתור Stop כדי לעצור את השעון ואז שוב על כפתור Start כדי להפעיל אותו שוב, ואפשר לשנות את המהירות באמצעות שינוי הטקסט בתיבה.
## בדיקת מצב ראשוני
בבדיקה הראשונה על טיימר נרצה לוודא שהוא מופיע במצב הראשוני שהגדרנו, כלומר עם הערך 0, עם מהירות של שניה ועם הכפתור Stop:
test('initial values', () => {
render(<Timer />);
expect(screen.getByText(/0/)).toBeInTheDocument();
expect(screen.getByRole('button', { name: /stop/i })).toBeInTheDocument();
expect(screen.getByRole('spinbutton')).toHaveDisplayValue(1000);
});
## בדיקת התקדמות השעון
ועכשיו אפשר להמשיך לבדיקה יותר מעניינת - בואו נראה שאחרי שניה השעון באמת מתקדם. אנחנו יודעים שאחרי שהשעון יתקדם הטקסט יתעדכן למספר 1, ולכן יכולים לכתוב את הבדיקה:
test('after 1 second the value changes to 1', async () => {
render(<Timer />);
expect(await screen.findByText(/1/, {}, { timeout: 3000 })).toBeInTheDocument();
});
אני משתמש ב findByText כדי למצוא את האלמנט עם הטקסט 1. החיפוש עם find מחכה עד שהאלמנט יופיע, ובגלל זה עלינו לכתוב לפניו await. בגלל שיש await בקוד הבדיקה, פונקציית הבדיקה צריכה להיות מסומנת בתור async.
הפעלה של הבדיקה מגלה שהיא עובדת, אבל לאט. find מחכה לפעמים גם שתי שניות עד שהערך יתעדכן, כנראה בגלל שספריית הבדיקות לא רואה את השינוי בדיוק כשהוא קורה.
לכן ההעדפה שלנו בבדיקת קוד אסינכרוני במידת האפשר היא להפוך את הקוד לסינכרוני או לפחות למיידי. במקרה של שעונים הטריק הוא לדרוס את הפונקציות setInterval ו setTimeout ולייצר "שעון" מזויף, שאפשר להזיז אותו בצורה תכנותית. ג'סט מספק לי את הכלים לזה באמצעות הפונקציה:
jest.useFakeTimers();
אני מוסיף לתוכנית הבדיקה שלי את הקוד הבא:
beforeEach(() => {
jest.useFakeTimers();
});
afterEach(() => {
jest.useRealTimers();
});
הבלוק beforeEach מגדיר קוד שירוץ לפני כל בדיקה, והבלוק afterEach מגדיר את הקוד שירוץ אחרי כל בדיקה (יש גם beforeAll ו afterAll). אני משתמש בשני הבלוקים כדי להפעיל שעונים מזויפים לפני כל בדיקה, ולהחזיר את המצב לקדמותו בסוף הבדיקות.
עכשיו בקוד הבדיקות אני יכול לקרוא ל:
jest.advanceTimersByTime(1000);
כדי לזוז קדימה בזמן. אני מעדכן את קוד הבדיקה כדי להינות מהשעון המזויף החדש שלי:
test('after 1 second the value changes to 1', () => {
render(<Timer />);
act(() => {
jest.advanceTimersByTime(1000);
});
expect(screen.getByText(/1/)).toBeInTheDocument();
});1 419
# multipass היא הדרך הכי קלה לקבל מכונת אובונטו וירטואלית על המחשב שלכם
תוכנות כמו virtualbox או vmware הופכות את ההתקנה של מכונת לינוקס וירטואלית למאוד פשוטה, ובזכותן אפשר להתנסות עם הפצות חדשות ולהינות מהסביבה הגרפית השונה ומהאווירה השונה של כל הפצה. אבל לפעמים אנחנו רק רוצים להריץ משהו במסוף או לבדוק משהו יותר קטן, או לחלופין להריץ מספר מכונות בלי GUI שיתקשרו ביניהן ברשת. למצבים האלה תוכנות הוירטואליזציה עשויות להיות "יותר מדי". תוכנת Multipass מציעה פיתרון הרבה יותר מדויק ואלגנטי למי שרוצה להרים מכונות אובונטו וירטואליות, נטולות ממשק גרפי, על המכונה המקומית.
## המכונה הראשונה שלי
שלב ראשון הוא להתקין את multipass מהאתר שלהם בכתובת:
https://multipass.run/install
פשוט בוחרים את מערכת ההפעלה שלכם ועובדים לפי ההוראות. יש תמיכה מלאה ב Linux, Windows ו Mac (כולל מעבד אפל).
אחרי ההתקנה כותבים מהמסוף:
multipass shell
ויש לכם Shell לתוך מכונת אובונטו חדשה ונטולת ממשק גרפי.
## מה עוד
המכונה נוצרה עם דיסק של 5 ג'יגה וג'יגה זיכרון. היא מריצה את Ubuntu LTS האחרונה והיא מתחברת לאינטרנט דרך המכונה המארחת.
אפשר להוסיף עוד מכונות מגירסאות אחרות של Ubuntu, או עם גדלים אחרים באמצעות פקודת multipass launch, למשל בשביל להריץ מכונה חדשה של אובונטו 18.04 אני יכול לכתוב:
multipass launch 18.04 -n my-old-ubuntu
הפרמטר -n קבע את שם המכונה ואחרי זה בשביל להיכנס אליה אני אצטרך לציין את השם:
multipass shell my-old-ubuntu
הפקודה multipass find תציג לכם רשימה של כל האימג'ים שתוכלו להתקין במכונה הוירטואלית, ו multipass list תציג את כל המכונות שמותקנות אצלכם.
מולטיפאס גם תומכת ב cloud-init שזה סקריפטים איתם אפשר לקנפג את המכונה, לקבוע איזה חבילות יותקנו אוטומטית, איזה משתמשים יהיו, ערכים של קבצי קונפיגורציה וכן הלאה.
## איפה לומדים יותר
בתיעוד כמובן:
https://multipass.run/docs.
וגם אפשר להפעיל:
multipass help
ולקבל אינסוף מידע מועיל על הפקודות.1 419
# היום למדתי: הפקודה fc תאפשר לכם לערוך היסטוריה ולהריץ אותה שוב
זה אולי לא קורה לעתים קרובות, אבל לפעמים יש לנו פקודה או כמה פקודות מההיסטוריה שאנחנו רוצים להריץ שוב ושוב, ובזה בדיוק fc יכולה לעזור.
בשימוש הפשוט שלה הפקודה יודעת למצוא פקודות ישנות שהרצתם. לכן אם אני מפעיל:
mkdir foo
touch foo/bar
cp /etc/passwd foo
אז אני יכול אחרי זה לכתוב:
fc -l mkdir cp
ולקבל את רשימת כל הפקודות מ mkdir עד cp כולל:
544 mkdir foo
545 touch foo/bar
546 cp /etc/passwd foo
מה שיותר מדליק קורה אם אני מוותר על ה -l, ואז fc פותח את הרשימה בתוך עורך טקסט, מאפשר לי לשנות את הפקודות ובסוף מריץ את כולן. בדוגמה שלנו אני מוותר על ה -l ומקבל את כל הרשימה בעורך טקסט, משנה כל מופע של foo ל bar ומקבל את הקובץ:
mkdir bar
touch bar/bar
cp /etc/passwd bar
שומר ויוצא וכך יצרתי את תיקיית bar בדיוק כמו שיצרתי קודם את תיקיית foo.
שימו לב רק שאתם בודקים טוב טוב מה אתם מריצים כשאתם בתוך העורך, כי מרגע ש fc יצא לדרך אי אפשר לעצור אותו וזה שפקודה מסוימת הופיעה בהיסטוריה לא בהכרח אומר שאתם רוצים להריץ אותה שוב.1 419
# למה מערך ריק שווה 0?
לא תמיד אנחנו מסכימים עם השגעונות של ג'אווהסקריפט אבל הרבה פעמים כן יש איזה היגיון פנימי שיכול לעזור להסביר את הטירוף. ועם ההקדמה הזאת בואו נדבר על מערכים.
## קודם העובדות:
זה לקוח מ node.js גירסה 18, גם דפדפנים מתנהגים ככה:
> Number([])
0
> Number([4])
4
> Number([2, 3, 4])
NaN
כן בג'אווהסקריפט כשאני הופך מערך בגודל אפס למספר אני מקבל את המספר אפס, מערך של מספר יחיד ייתן לי את המספר הזה ומערך בגודל גדול יותר יהפוך ל NaN.
## אבל למה זה קורה?
בשביל להפוך אוביקטים לפרימיטיביים ג'אווהסקריפט משתמש בשלוש טכניקות (לפי הסדר הזה):
1. קודם כל הוא בודק אם לאוביקט מוגדר הסימבול Symbol.toPrimitive, אם כן יפעיל אותו.
2. אם אין toPrimitive מנסים להפעיל את valueOf.
3. אם גם זה לא עזר מפעילים את toString.
למערכים אין toPrimitive וה valueOf שלהם מחזיר את המערך עצמו, אז נשארנו רק עם toString:
> [].toString()
''
> [4].toString()
'4'
> [2, 3, 4].toString()
'2,3,4'
המחרוזת הראשונה ריקה ולכן הופכת לאפס, השניה הופכת למספר 4 ואת השלישית כבר אי אפשר להפוך למספר ולכן הופכת ל NaN.
## רגע תזכיר לי מה זה Symbol.toPrimitive
אוקיי אז הבנו למה מערכים מתנהגים ככה אבל מה זה בעצם Symbol.toPrimitive והאם אפשר להשתמש בו כדי לשנות את ההתנהגות?
לכל אוביקט ב JavaScript אני יכול להגדיר מפתח מיוחד שזה הסימבול toPrimitive שיהיה פונקציה, ויחזיר את האוביקט בצורת הפרימיטיב שלו. הנה זה בדוגמה:
> const x = {
[Symbol.toPrimitive](hint) { return 7 }
};
undefined
> Number(x)
7
המשתנה hint שעובר לפונקציה אומר לה מה סוג הפרימיטיב שאנחנו מצפים לקבל, ובהמרה למספר יש לו את הערך number.
אפשר להוסיף את הסימבול הזה לכל אוביקט שרוצים, כולל לכל המערכים. לדוגמה:
> Array.prototype[Symbol.toPrimitive] = () => 42;
[Function (anonymous)]
> Number([2, 3, 5])
42
ועם זה אפשר לתקן את ההמרה למספר כך שתהיה קצת פחות מוזרה - למשל אנחנו יכולים לעדכן את התוכנית כך שכל המרה של מערך למספר תחזיר את גודל המערך:
> Array.prototype[Symbol.toPrimitive] =
function() {
return this.length;
}
> Number([2, 3, 5])
31 419
# לא הולך להיות כיף
אני זוכר שישבתי עם חבר שעבד בתחום של Penetration Testing ואמרתי לו - "וואו יש לך את העבודה הכי כיפית בעולם, כל היום אתה מחפש חולשות במערכות ויכול לשבור דברים". "תמשיך לחלום" הוא ענה לי, "נכון, יש את החלק הזה שצריך לשבור דברים ולמצוא חולשות, אבל רוב היום אני רק כותב דוחות ומארגן יפה ומסודר את כל מה שמצאתי". ההבדל בין לעשות משהו בשביל הכיף ולעשות משהו בשביל עבודה מעולם לא נראה ברור יותר.
ואותו הבדל תוקף אותנו גם כשאנחנו באים לשדרג את הקריירה או הקוד שלנו:
1. בכתיבת פרויקט צד, ההתחלה נראית מלהיבה (איזה כיף אני הולך להתעסק עם מלא טכנולוגיות חדשות), עד שאתה מגלה שבשביל שדברים יעבדו טוב יחד מעבר ל Tutorial הבסיסי, צריך להתאמץ, לא להבין ולפעמים פשוט לזרוק עוד שורות קוד על הבעיה, בדיוק כמו בעבודה האמיתית.
2. לימוד תחום חדש עשוי להיראות כמו הדבר הכי מלהיב בעולם, עד שאתה מגלה שבשנה הראשונה הדברים היחידים שתצליח לבנות הם הרבה פחות מלהיבים מאלה שחלמת עליהם. שלפני שתצליח לבנות את המשחק שתמיד חלמת עליו תצטרך לבנות אינסוף משחקים פשוטים ומשעממים רק כדי ללמוד את היסודות.
3. הכנסת טכנולוגיה חדשה לפרויקט עשויה להיראות כמו רעיון ממש מלהיב, עד שמתחילים תכל'ס לכתוב את הקוד ורואים שדברים לוקחים יותר זמן ממה שקיווית, ואפילו התקנות והגדרות שנראו ממש פשוטות ב Tutorial הופכות לאתגר כשצריך לשלב אותן עם פרויקט אמיתי.
4. הרבה מתכנתים חולמים על פרויקט Green Field, שבו יוכלו להתחיל הכל מאפס, או על איזה Rewrite גדול שאחריו כל הבעיות יעלמו. ברוב המקרים הסיבה שפרויקט Green Field הוא פשוט יותר היא בדיוק בגלל שהתחלנו מאפס. ככל שמוסיפים פיצ'רים הקוד מסתבך והכיף שוב נעלם.
אז נכון תהליך הלימוד, תהליך הפיתוח, תהליך הקידוד, הם אולי לא מלהיבים כמו שהייתם רוצים שיהיו. אבל אל תתנו לבלבול הזה לייאש אתכם - לאורך זמן, שילוב טכנולוגיות חדשות ולימוד תחומים חדשים זו הדרך היחידה קדימה.
1 419
# ריילווי מציע דרך קלה וחדשה לפתח בענן
גיום ראוך מ vercel הגדיר את ורסל עצמה והרבה מהמתחרות שלה בתור "ענן שכבה 2", אם בחברות הענן המסורתיות אנחנו צריכים לשבור את השיניים בשביל לבנות אפליקציה - בחברות הענן החדשות אנחנו נקבל Deployments בלחיצת כפתור, חיבור לגיטהאב וגם אפשרות להרצה ובדיקה מקומית.
ריילווי היא אחת מחברות הענן החדשות האלה והנה כמה דברים שנראה לי שתאהבו בה:
## התקנת יישום חדש בשתי לחיצות
ריילווי מציעה לכם סביבת פיתוח מלאה בענן ובתשלום לפי שימוש, כשיישומים פשוטים ירוצו בחינם (אתם מקבלים מתנה 5$ בחודש), וככל שצריכים יותר כח מחשוב כך תתחילו לשלם.
הפיצ'ר הראשון שאהבתי שם היה התקנת יישום חדש בלחיצת כפתור מתוך אוסף אינסופי של תבניות יישומים שלהם. אתם יכולים לבחור יישום ריילס, Node.JS Express, Django, Flask, כל יישומי הפרונט אנד ואפילו PHP ו Rust. פשוט לוחצים "New Project", בוחרים את התבנית וריילווי כבר ייצרו עבורכם פרויקט חדש בגיטהאב שלכם לפי אותה תבנית, ויחברו אותו לענן שלהם כך שכל קומיט לגיטהאב גם יעדכן את הגירסה בענן.
תבניות הפרויקטים מורכבות כמובן ממכונה שמריצה את הקוד, אבל רבות מהן מכילות גם בסיס נתונים במכונה נפרדת ואחרי יצירת הפרויקט אפשר להוסיף (שוב דרך הממשק) גם Load Balancer ושאר פינוקים.
## לוח בקרה עם אפשרות לחזור אחורה
בנושא ה Deployment ובדומה ל next וגם ל render, גם פה אתם יכולים לראות כל Deployment שעשיתם בלוח הבקרה, אפשר לחזור גירסה אחורה אם גירסה מסוימת לא עבדה טוב, אפשר לראות את כל הלוגים של כל המכונות ולשנות הגדרות של מכונות - כולל להסתכל בנתונים בבסיס הנתונים ולעדכן אותם.
ריילווי תומכים במספר סביבות לכל פרויקט אז אתם יכולים להגדיר סביבת פרודקשן למשתמשים האמיתיים וסביבות פיתוח לכל מתכנת בצוות, והכל שוב בלחיצת כפתור.
## עבודה מקומית דרך ה CLI שלהם
פיצ'ר אחרון ומדליק הוא החיבור למחשב המקומי - אם ניקח לדוגמה פרויקט שמכיל יישום Node.JS Express שמתחבר לבסיס נתונים, אז בפיתוח מקומי אתם לא רוצים להתקין את כל הכלים ואת בסיס הנתונים בנפרד, אלא אתם רוצים לעבוד ממש על המכונות שבענן כדי לקבל תמונה כמה שיותר מדויקת של מה שקורה.
ריילווי מאפשרים את זה עם לקוח ה CLI שלהם. התקנתי אותו עם:
npm i -g @railway/cli
ואחרי זה מתוך תיקיית הפרויקט (כן צריך לעשות clone לפרויקט בגיטהאב שהוא יוצר לכם), אני מפעיל railway link ואז railway run npm run dev. קצת מסורבל אבל התוצאה היא שהאפליקציה מתחברת לבסיס הנתונים בענן של ריילווי וכל העבודה בפיתוח נעשית מול בסיס הנתונים בענן שהוקם בסביבת הפיתוח.
סך הכל ריילווי מציע חווית פיתוח מאוד נוחה וקלה למי שרוצה לקבל Deployment מהיר ליישומי ווב, ובשילוב עם מסלול חינמי זאת הצעה שקשה לסרב לה.1 419
# ארבע תשובות להתנגדויות נפוצות לטייפסקריפט
רוצים להכניס טייפסקריפט לפרויקט אבל חברי הצוות עושים פרצוף? הנה ארבע תגובות שלפעמים אנחנו שומעים על טייפסקריפט, ומה לענות בכל מצב.
## אני בחיים לא טועה בטיפוסים
אני מתחיל עם המתכנת הגאון שתמיד כל הקוד שלו עובד מהפעם הראשונה, בחיים הוא לא טועה בטיפוסים ויודע את כל ה API של כל הקוד במערכת בעל פה. "בשביל מה אני צריך טייפסקריפט?" הוא ישאל, "המוח שלי עובד יותר מהר מכל מחשב".
במצבים כאלה אנחנו יכולים להזכיר לחבר שהוא לא עובד לבד, ושלמרות שהוא המתכנת הכי-טוב-בעולם שאף-פעם-לא-טועה-בטיפוסים לפעמים אנשים אחרים יכניסו למערכת קוד מבלבל, ובפרויקט גדול אי אפשר לקרוא ולהכיר כל שורת קוד שמישהו מכניס. כשצריך לתקן באג בקטע קוד שלרוב אתה לא עובד עליו, מאוד עוזר כשיש כלי שקורא אתך את הקוד ומוודא שלא העברת פרמטר מהטיפוס הלא נכון.
בנוסף, בשימוש בספריות חיצוניות חדשות יכול להיות שאתה עדיין לא מכיר בעל פה את כל הממשק שלהן. השלמה אוטומטית של סביבת הפיתוח יכולה לחסוך מעבר לחלון הדפדפן כדי לחפש בתיעוד ובסך הכל להגביר את מהירות הפיתוח.
ואפילו אם אתה מכיר כל שורת קוד במערכת ואת ה API של כל הספריות החיצוניות, היכולת של טייפסקריפט בלחיצת כפתור לשנות שם של משתנה בכל הפרויקט (במקום שתצטרך לעבור על כל המקומות בהם המשתנה הזה מופיע) מביאה לזה שיהיה יותר קל לשנות שמות ולבחור את השמות הנכונים לפונקציות ולמשתנים שלנו.
## טייפסקריפט רק מאט את הבניה
התנגדות מספר 2 תגיע מאנשים שדווקא היו שמחים להכניס את טייפסקריפט לפרויקט אבל יש להם כבר מספיק ניסיון עם וובפאק כדי לדעת שכל פלאגין חדש יכול לשבור את כל הבילד או להאט אותו משמעותית.
אני מאוד בעד להקשיב לניסיון מר מהעבר, אבל נדמה לי שהמסקנה כאן היא שגויה: הבעיה היא לא טייפסקריפט אלא וובפאק. כלי בניה טובים יותר יגיעו לתוצאות טובות בהרבה. במקרים קיצוניים אפשר לבחור כלי כמו esbuild שפשוט מוחק את כל הגדרות הטיפוסים בבנייה (בלי לבדוק שום דבר) ולהריץ את הבדיקה מתוך ה IDE בנפרד מהבניה.
## טייפסקריפט רק מאט את הפיתוח
אנשים שחדשים לטייפסקריפט צריכים לעבור עקומת למידה ועד שעוברים אותה לפעמים יש הרגשה שהכלים עובדים נגדך - לא ברור איך לשלב קוד מספריה חיצונית שאין לה הגדרות טיפוסים, הודעות השגיאה של טייפסקריפט יכולות להיות קריפטיות והרבה פעמים טייפסקריפט יכול להסתכל על קוד נכון לגמרי ובכל זאת להתלונן עליו ולדרוש הגדרות טיפוסים יותר מדויקות.
קיימות בעיות אמיתיות עם טייפסקריפט וכל מי שעבדה איתו מספיק נתקלה במקומות שבהם טייפסקריפט הכריח אותנו לכתוב קוד שביום רגיל לא הייתי כותב. ובכל זאת המקומות האלה הם המיעוט - רוב הזמן ככל שמכירים יותר את טייפסקריפט אנחנו מגלים שהטענות שלו כן מבוססות על בעיות אמיתיות בקוד ותיקון של הקוד משמח גם את טייפסקריפט וגם מעלה את הרמה של המערכת.
נכון טייפסקריפט מכריח אותנו לחשוב טוב על הגדרות הטיפוסים שלנו ועל הממשק של כל פונקציה ונכון שזה יכול להאט את הפיתוח בטווח הקצר, אבל במערכות מספיק גדולות התועלת עולה בהרבה על המחיר.
## טייפסקריפט לא רלוונטי לפרונט-אנד כי ה API שלנו גמיש מדי
מתכנתי פרונטאנד רבים רגילים "לשחק" עם הקוד, ו JavaScript תומך בגישה הזאת אפילו בדוגמאות פשוטות. הפונקציה add בדוגמה:
function add(x, y) {
return x + y;
}
עובדת מהקופסה גם על מספרים, גם על מחרוזות ועושה את הדבר הנכון. בשביל לכתוב אותה בטייפסקריפט אני כבר צריך להשתמש בכלים מתוחכמים כמו Generics בשביל לקבל בדיוק את אותו אפקט:
function add<T extends number|string>(x: T, y: T) {
return x + y;
}
זה מוזר לא? חשבתי שאני מוסיף הגדרות טיפוסים קטנות למערכת ופתאום אני צריך ללמוד המון על טייפסקריפט רק בשביל לייצג חתימות נפוצות ופשוטות. מה יקרה כשאגיע לחתימות המסובכות יותר?
ובאמת להוסיף הגדרות טיפוסים דורש היכרות טובה גם עם JavaScript וגם עם הכלים של TypeScript. ככל שהמערכת שלנו מעניינת יותר (ומערכות ווב הן תמיד כאלה), כך זה יהיה יותר קשה לשלב טייפסקריפט בלי להכיר אותה. אבל מצד שני כן צריך לזכור שבמימוש המקורי של add אפשר להפעיל את הפונקציה גם על דברים שהם לא מספרים או מחרוזות - למשל מה לדעתכם תקבלו מהפעלה כזו:
add([1, 2, 3], [4, 5, 6]);
אם אתם לא בטוחים אולי זה סימן ששווה להשקיע בלימוד טייפסקריפט.1 419
# תשתית בדיקות
בכל נקודה בפיתוח, יותר זול לי לתקן באג או להוסיף פיצ'ר תוך כדי בדיקה ידנית שהצלחתי, מאשר לבנות תשתית בדיקות.
ובכל נקודה אם היתה לי תשתית בדיקות טובה הייתי יכול לבנות את הפיצ'ר או לתקן את הבאג יותר מהר מאשר בלעדיה.
הבעיה שבדרך כלל אנחנו בונים תשתית בדיקות לא מספיק טובה, ואז משלמים פעמיים - גם השקענו עבודה בבניית ההתשתית, וגם בשוטף אנחנו משקיעים יותר זמן בפיתוח פיצ'רים ותיקון באגים (כי צריך גם להוסיף בדיקה שרק גוזלת זמן).
המפתח קדימה הוא לחזור למשפט השני בפוסט הזה, ולזכור ש"תשתית בדיקות טובה משפרת קצב". כל עוד תשתית הבדיקות שלכם מאטה אתכם, צריך להמשיך לשפר אותה (או לוותר ולזרוק).
1 419
# הפעלת גיטהאב אקשן כשנוצר תג חדש לפי תבנית
גיטהאב אקשן מספק מנגנון ממש נוח ל Deployment אוטומטי למערכת שלכם, אבל יש טוויסט: אנחנו לא רוצים לעשות deploy על כל PR חדש שממוזג ל main, אבל אנחנו גם לא רוצים לעשות את הקומיט ידנית בלחיצת כפתור כי כן מאוד נוח לעבוד רק דרך גיט. פיתרון אחד קל הוא להחליט על תבנית שם של tag שיגרום ל deploy, למשל נחליט שכל תג שמתחיל במילה deploy ואחריה מקף יגרום לגיטהאב להפעיל אקשן שיעשה deployment חדש.
הטריגר ב Github Action יראה כך:
on:
push:
tags:
- 'deploy-*'
ואז אפשר ליצור את התג עם תוספת של timestamp ולדחוף אותו לשרת עם הפקודות:
$ git tag deploy-$(date +%s)
$ git push --tags1 419
# לא לדאוג, אני מכיר את find
נתון אוסף של תיקיות בכל אחת יש פרויקט אחר. המשימה שלנו היום היא ליצור בתוך כל תיקיה תת-תיקיה בשם app אם אין כזאת, ואם הצלחנו ליצור אז גם להעביר את כל הקבצים והתיקיות שהיו בתוך אותה תיקיה לתוך app. אם היתה app קודם אפשר לדלג על התיקיה.
כל עוד מדובר ב 2-3 פרויקטים אין בעיה לעבור אחד אחד, אבל כשיש עשרות הרבה יותר כיף להשתמש ב find.
המשימה הראשונה היא למצוא את כל תיקיות הפרויקטים, כלומר התיקיות ברמה "הראשית". בשביל זה find מציע לנו את maxdepth, type ו mindepth. עבור דוגמה פשוטה שמכילה שלוש תיקיות פרויקטים בשמות a, b ו c אני מריץ:
$ find . -mindepth 1 -maxdepth 1 -type d
./a
./c
./b
בזכות מסנן ה type הפקודה מדפיסה רק את התיקיות גם אם היו קבצים בתיקיה הראשית. אפשר לסנן עוד יותר גם לפי שמות קבצים של אותן תיקיות פרויקטים עם תוספת מתג -name.
אחרי שיש לנו את תיקיות הפרויקטים צריך בכל תיקיה להריץ את הפקודות:
mkdir app && mv * app
שימו לב לסימן ה && בין שתי הפקודות: אני רוצה להריץ את ה mv רק אם הצלחתי ליצור את התיקיה. אם mkdir נכשל זה כנראה אומר ש app היתה שם קודם (למרות שיכול להיות שמדובר בבעיית הרשאות, אבל גם במקרה כזה אין טעם לנסות להעביר לשם קבצים).
בשביל זה ל find יש כפתור exec. אבל אני לא יכול להריץ ישירות את ה && בתוך ה exec ולכן אני מריץ עותק חדש של bash שיפעיל את שתי הפקודות:
find . -mindepth 1 -maxdepth 1 -type d -exec bash -c "mkdir {}/app && mv {}/* {}/app" \;
ופה בדיוק הכח והיופי של הכלים הקטנים של יוניקס - היכרות טובה איתם עוזרת לתקשר עם המחשב טוב יותר ולחסוך זמן במשימות שבאמת לא הגיוני לעשות אותן ידנית.
متاح الآن! بحث تيليغرام 2025 — أهم رؤى العام 
