4 באפריל 2023
Edit on GitHub
— Post available in English

יחידות מידה ומערכות תכנה

צורת עבודה נכונה עם יחידות מידה במערכות תכנה

Blog picture

ב-23 בספטמבר 1999 ניתק הקשר עם הגשושית Mars Climate Orbiter. פרוייקט בשווי 327 מיליון דולר ירד לטמיון.

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

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

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

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

כן, אבל.

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

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

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

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

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

ובהרחבה ניתן דוגמאות קוד להמחשת הבעיתיות

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




ובדוגמה זו ניתן להבחין בסירבול שמות המשתנים.




בדוגמה זו מומחשת בעיית ההמרות מיותרות שלא ניתן להתחמק מהן.




נו, מי רוצה להמיר דצימטר לנאוטיקל-מיילס?




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





הפתרון

תגידו שלום לספרייה UnitsNET.

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

דוגמה? יאללה דוגמה בקוד.


var distanceFromUser = Length.FromMeters(1000)

void PrintDistance(Length distance)
{
  console.Writeline("The distance is " + distance.Kilometers + " km") // 1
}

PrintDistance(distanceFromUser);

רואים כמה זה פשוט וטוב?

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

אממה, הפרוייקט הנפלא הזה מחולל לקוד בשפת #C שכבודה (ויש כבוד!) במקומה מונח, אבל אנחנו (ועוד כמה מליוני מפתחים) מכירים עוד שפה שאנחנו מאוד אוהבים ומוקירים הלוא היא JS/TS.

וכאן עבדכם הנאמן נכנס לסיפור ובנה מקבצי הגדרת היחידות של UnitsNET חבילת NPM שנקראת unitsnet-js לרווחת משתמשי JS/TS.

והופ, הנה איך נפתרים כל הבעיות שהוצגו בדוגמאות מלעיל (ב-TypeScript)




ומרוב ההצלחה המסחררת (והצורך של הכותב גם בספרייה לפייתון)

הספרייה זמינה עכשיו גם בפייתון!

קוד המקור של הספרייה unitsnet-py

והספרייה זמינה לשימוש ב-https://pypi.org/project/unitsnet-py


תהנו!