תיקון של שורה (עם ובלי בדיקות)
טיפים קצרים וחדשות למתכנתים
גירסאות עדכניות של Node.JS כבר תומכות בצורה מובנית ב ES Modules, ואפילו מציעות כמה שיפורים על פני עבודה בדפדפן. בואו נראה כמה טכניקות מרכזיות של עבודה עם ES Modules ב Node.JS.
נתחיל במה שלא עובד (וזה קצת מפתיע). אפשר לדמיין שבשביל להיות מתכנתי פייתון טובים יותר עלינו ללמוד כמה שיותר APIs של פייתון. למשל אם נלמד גם לכתוב ממשקים גרפיים, גם לקבל מידע מהרשת, גם לנתח מידע וגם לבנות בינה מלאכותית אז כל API חדש יהפוך אותנו למתכנתי פייתון טובים יותר.
אבל זה לא ממש עובד.
הדבר היחיד שאנחנו מקבלים מללמוד כל חודש API חדש לגמרי הוא סחרחורת. אנחנו מקבלים את התחושה שהטכנולוגיה רצה מהר מדי, שאי אפשר אף פעם לדעת הכל, שלא משנה כמה אני אלמד תמיד אצטרך "להתחיל מחדש" ושהעולם הזה לא בשבילי. אנחנו כל פעם משקיעים בדברים שלא נשארים, ואחרי חודש או שנה מגלים שחזרנו לנקודת ההתחלה.
דרך טובה יותר להשתפר בתור מפתחי פייתון, או כל טכנולוגיה אחרת, היא להשקיע בדברים שנשארים. בפייתון זה יהיה:
להבין איך פייתון מבינה ומריצה את התוכנית שלי.
להבין איך להשתמש ב Type Hints בצורה שתייצר ערך ותהפוך את הקוד לקל יותר לקריאה.
להבין איך לעשות דברים במקביל, באמצעות Threads, Processes או async.
להבין מה זה תכנות מונחה עצמים ואיך למדל באמצעותו בעיות.
להבין איך לכתוב בדיקות בצורה יעילה ומהירה.
להבין מה משפיע על זמן הריצה של תוכנית ואיך למדוד ולשפר זמני ריצה.
להכיר את המבנים היותר בסיסיים של פייתון כמו Decorator ו Metaclass ואיזה תפקיד הם משחקים בספריות קוד מרכזיות.
להבין את הקשר בין Python ל C. אחרי זה איך לכתוב הרחבות ב C לפייתון, ואיזה חבילות פייתון מרכזיות משתמשות בהרחבות C כדי לשפר ביצועים.
כשיש ספק, השקיעו בדברים שנשארים.
נתבונן בקומפוננטה הבאה מתוך דף הפתיחה של swr:
import useSWR from 'swr'
function Profile () {
const { data, error, isLoading } = useSWR('/api/user/123', fetcher)
if (error) return <div>failed to load</div>
if (isLoading) return <div>loading...</div>
// render data
return <div>hello {data.name}!</div>
}
ונכתוב תוכנית בדיקה שמשנה את fetch כדי להחזיר אוביקט שלנו, בשביל שאפשר יהיה לבדוק את הקומפוננטה גם בלי לצאת לרשת:
import { render, screen } from '@testing-library/react';
import Profile from './Profile;
test('test one', async () => {
jest.spyOn(global, 'fetch').mockImplementation(url => Promise.resolve({
json: () => Promise.resolve({ name: 'bug'})
}));
render(<Profile />);
expect(await screen.findByText(/hello bug/));
});
קודם כל תשמחו לשמוע שהתוכנית עובדת. עכשיו קראו את הקוד שוב. רואים את הבעיה?
את הטיפ הבא מצאתי במאמר הזה של חברת Betterment ומיד התחברתי אז אני משתף גם פה.
נתחיל עם קוד ריילס הבא עבור controller:
class Documents::AttachmentsController < ApplicationController
def create
AttachmentLink.new(create_params.merge(document: document)).save!
end
private
def create_params
params.permit(:attachment_id, :caption)
end
def document
current_user.documents.find(params[:document_id])
end
end
הקוד מאפשר להצמיד Attachments למסמך דרך הפונקציה create. הפונקציה מקבלת מהדפדפן מזהה של "קובץ מצורף" ומזהה של "מסמך" ויוצרת AttachmentLink שזה אוביקט חיבור בין השניים.
קחו רגע לקרוא את הקוד ונסו לחשוב מה שבור בו.
זה לא פשוט לכתוב בדיקות, במיוחד בדיקות לקוד צד לקוח.
הרבה אנשים חושבים שבדיקות לוקחות להם זמן והם מעדיפים להשקיע את הזמן הזה בבניית פיצ׳רים חדשים. הם שוכחים שהדבר הכי מרגיז במערכות זה כשמעלים גירסה חדשה וכל הדברים הישנים מפסיקים לעבוד.
אנשים אחרים חושבים שבדיקות End To End הן חשובות, אבל על בדיקות יחידה אפשר לוותר. הם נכוו מספיק פעמים מבדיקות יחידה לא יעילות שלא מצאו את הבאגים האמיתיים במערכת.
ויש גם את מי שבטוחים שבדיקות זה רעיון ממש מצוין אבל ספציפית המערכת שלהם מסובכת מדי וכרגע יש יותר מדי באגים. יום אחד כשדברים קצת יתייצבו הם ישמחו לכתוב בדיקות.
אם גם אתם חלק מאחת הקבוצות ברשימה שלמעלה תרגישו חופשי להמשיך הלאה, הפוסט הזה לא בשבילכם.
מצד שני אם אתם היום מרגישים לא בטוחים לגבי הקוד שלכם. אם אתם מבינים שאי אפשר להמשיך כך כשכל ריפקטור קטן שובר אינסוף דברים. אם גם לכם נמאס לעבור בין הדפדפן ל VS Code כל הזמן בשביל לבדוק שהקוד שאתם כותבים עובד כמו שצריך, אז תשמחו לשמוע שהעליתי היום מיני קורס חדש במטרה לעזור לכם להתחיל לכתוב בדיקות יחידה או לשפר את רמת הבדיקות שאתם כותבים.
הקורס כולל 6 סרטי וידאו באורך כולל של קצת פחות משעה, ועוסק בנושאים:
היכרות עם react-testing-library, איך נראית תוכנית בדיקה ואיך לא לבזבז זמן בכתיבת תוכניות הבדיקה.
בדיקת טיפול באירועים עם user-event.
בדיקת קומפוננטות המושפעות מזמן, גם בצורה אסינכרונית וגם באמצעות שעונים מזויפים.
בדיקת תקשורת באמצעות mock לפונקציית fetch ו Best Practices סביב בדיקות כאלה.
בדיקת קומפוננטות-בתוך-קומפוננטות באמצעות Jest Spies.
בדיקת יישומים המשתמשים ב Redux.
השיעורים מעשיים, כל שיעור מודגם על קומפוננטות אמיתיות שכתובות ב React ו TypeScript וייתן לכם בסיס טוב לבניית בדיקות למערכות שלכם.
אם יש לכם מנוי לאתר יכולים כבר להיכנס ולצפות בקישור: https://www.tocode.co.il/boosters/7
ואם עדיין אין לכם מנוי היום הוא הזדמנות מצוינת להירשם. פשוט לחצו על הקישור לקורס כדי להגיע לדף ההרשמה.
אחד הפיצ'רים שעוררו התלהבות בריאקט 18 נקרא Suspense For Data Fetching. בפוסט זה נראה מהו Suspense For Data Fetching ומתי כדאי או לא כדאי להשתמש בו.
בעולם של היום הדבר הכי קל בפרויקט זה להוסיף תלות בעוד ספריית קוד פתוח. צריכה הצפנה? יש מודול ב pip שעושה את זה. צריך לפתוח קובץ זיפ? פשוט תריץ npm install. לפעמים נדמה לי שחצי מהעבודה שלנו היא למצוא את המודול המתאים בשביל לפתור את הבעיה.
הבעיה שכשהפרויקט מתבגר כך גם ספריית הקוד הפתוח ששילבתם, ולא בטוח שאהבת הנעורים מלפני שנתיים היא השותפה המושלמת גם לפרויקט של היום. הרבה (מאוד) ספריות קוד פתוח התחילו בתור רעיון או צורך של מתכנת פרטי, לא זכו למימון וננטשו אחרי שהפסיקו להיות "כיף" לאותם מתכנת או מתכנתת שכתבו אותם במקור. אפילו פרויקטי קוד פתוח מסחריים רבים ננטשים, כשהחברה שבנתה אותם רואה שזה לא מביא להם את יחסי הציבור הטובים אליהם הם קיוו, או כשהסטארט אפ שבנה אותם נסגר כי נגמר המימון. בקיצור זה לא מוזר בכלל לעבוד על פרויקט שחצי מהתלויות שלו כבר לא נתמכות.
ואם זה גם המקרה שלכם הנה כמה רעיונות פרקטיים שאפשר לנסות:
להתעלם - זוכרים את "אם זה עובד לא נוגעים"? אז הרבה פעמים אנחנו רואים פרויקטים שתלויים בספריות קוד פתוח שכבר שנים לא מתוחזקות, ולאף אחד לא אכפת. בדרך כלל בפרויקטים כאלה יהיו כל מיני כללים מוזרים כמו "אסור לשדרג את node כי אז כלום לא יעבוד", וכולם מתכננים יום אחד לשדרג את התלות הלא מתוחזקת אבל לא מגיעים לזה.
ליצור fork מתוחזק - כש kreeti שמו לב שספריית הריילס האהובה עליהם ננטשה, הם יצרו פורט מתוחזק. וכן יש אפילו כלי שעוזר למצוא פורקים קיימים לספריות שננטשו.
להיפרד מהתלות ולהמשיך הלאה - רוב הסיכויים שאם הבעיה שלכם מעניינת יש גם אנשים אחרים שנתקלו בה ויש לה פיתרונות אחרים, טובים יותר מהפיתרון הישן ההוא שכבר לא מתוחזק. בדוגמה שקישרתי אליה קודם של פייפרקליפ, יש כבר פיתרון מובנה בריילס שפותר בדיוק את אותה בעיה (זאת הסיבה שהספריה המקורית ננטשה). אם הפרויקט שלכם מספיק חשוב, שווה להשקיע את הזמן ולעבור לפיתרון החדש יותר.
האפשרות השלישית היא המועדפת עליי. למרות שאפשר להישאר עם פיתרונות ישנים ולגרום לכל דבר לעבוד, אין כמו הכיף בלעבוד על פרויקט שהכל בו חדש, ושאפשר בקלות למצוא תיעוד רלוונטי ולשלב יכולות חדשות או כלים חדשים בלי התנגשויות מוזרות.
אודי הרשקוביץ כתב בסיפור על הבראנץ הנדיב-
ומנהל הפיתוח גייס עוד טאלנטים והוסיף המון באזז-וורדס ל Branch, והקוד הלך והסתבך ונהיה כבד ומסורבל, ואף אחד כבר לא ידע בדיוק מה עושים ולמה, אבל הדברים איכשהו עבדו. והמשקיעים ראו רק את הצמיחה האדירה של ה Branch, והמשיכו להזרים כסף. ולמרות הבלאגן והספגטי התוכנה המשיכה לעבוד איכשהו, וה Branch היה מקומפל.
קוד עובד הוא משקולת. הוא יוצר אילוצים, הוא יוצר בעיות קומפילציה כשמנסים להזיז דברים ממקום למקום, הוא מונע Refactoring כי אי אפשר לדעת איך זה ישפיע על הדברים הקיימים. זה לא סתם שמתכנתים הכי אוהבים פרויקטי Green Fields. כשאין קוד אין מה שיישבר.
ולמחוק קוד? למחוק קוד זאת הדרך הכי קלה להאיץ את הפיתוח. זה להקטין את כדור הבוץ הענק שאנחנו קוראים לו מערכת. כדי שהבראנץ שלנו לא יגמור כמו הבראנץ הנדיב.
"שימו לב כולם היום נכתוב ממשק גרפי מבוסס ווב למחשבון שרק יודע לחבר מספרים. הממשק צריך לאפשר למשתמש להקליד מספרים וכשלוחצים על כפתור צריך להציג את סכום כל המספרים שהוקלדו."
"רגע בוס אין פה מספיק אינפורמציה" נשמע קול מתכנתי מקצה החדר, "מה גבולות הגיזרה? בכמה מספרים צריך לתמוך?"
"אני לא יודע תזכור שזו פעולת חיבור אז בטח לא יהיה פחות מ-1, וגם יותר מדי שורות לא נראה יפה על המסך אז בואו נגביל את זה ל-10 מספרים במקסימום".
וכך נולד אילוץ פיקטיבי. מכאן כל מיני מקומות בקוד יכולים להתחיל להתבסס על זה ש"אף פעם לא יהיו יותר מ 10 תיבות", ולכתוב פונקציות כמו זו למשל:
function update() {
var i;
for (i = 3; i <= 10; i++) {
labelID = "line_R" + i;
if (document.getElementById("num").value >= i) {
document.getElementById(labelID).style.display = "list-item";
} else {
document.getElementById(labelID).style.display = "none";
}
}
}
אילוצים הם אחלה כי הם נותנים לנו אפשרות להתקדם. זה שהממשק צריך להיות מבוסס ווב או לעבוד בצד-לקוח בלבד אלה דברים שאנחנו חייבים לדעת בשביל לכתוב את הקוד. אבל כמו שאילוצים עוזרים להתקדם כך הם גם קשים לשינוי. האתגר בבניית מערכת הוא לא לנסות לעבוד בלי אילוצים (כי אז לא תצליחו לבנות שום דבר) אלא למצוא את סט האילוצים המינימלי שאיתו אפשר לרוץ קדימה.