מדריך ארכיטקטורת תוכנה - שיעור 3 קריאת שמות
-
בחירת שמות "נכונים" לאובייקטים היא אבן יסוד לשליטה על קוד.
הקישורים שיש כאן שלח לי רבי קשורים לרעיון הזה.http://web.macam.ac.il/~tamil/psychology/4language.htm
http://www.calcalist.co.il/local/articles/0,7340,L-3415756,00.html
http://www.ovzap.net/whorf/index3b.html
אם יש לנו שיטתיות עקבית וקשוחה בקריאת שמות, זה נותן לנו יתרונות רבים, סביר להניח שלא נחזור בטעות לכתוב פונקציה שכבר כתבנו בעבר, כי כאשר נבקש לכתוב אותה, נבחר לה שם שכבר בחרנו, ונכתוב אותה בקלאס הנכון, ואז מייד יוודע לנו שבעצם כבר יש בידינו פונקציה שעושה את העבודה (לי אישית זה קרה הרבה פעמים). דבר שני, נדע למצוא מייד את הפונקציה גם כאשר אנו זוכרים שכתבנו אי פעם פונקציה שעושה את העבודה הזאת, אבל לך תמצא אותה בתוך הערימה של הפונקציות. דבר שלישי, זה עצמו מרגיל אותנו לכתוב קוד מסודר, ברור וקריא, כי בשיעורים הבאים נלמד על פיזור סמכויות בין פונקציות וזה נגזר ממודעות ברורה בנושא קריאת השמות, כך שהקריאות של הקוד בעצם מאפשרת לנו לחסוך המון עבודה מיותרת, וככל שנתקדם יותר, כך עקומת הזמן שבה לוקח לנו ליישם בקשה של לקוח, תלך ותרד עם הזמן.
אעיר כי הנושא הזה של קריאת שמות לדברים, הוא קודש קודשים, ושייך לגמרי לבית המדרש וליסודות הדת.
הבה ונתחיל מהעקרונות.
לפני שניגש למתודולוגיה שתנחה אותנו ב"איך לקרוא שם" ו"מה השם אמור לייצג", נבהיר את העקרונות בגדול.
שמות של אובייקטים, לא משנה אילו אובייקטים, טבלאות, שדות, מחלקות, פונקציות, מאפיינים. צריכים לעמוד ב 3 קריטריונים:
1. שיטתיות ועקביותיש לקרוא בשמות באופן שיטתי ולא לפי "מצב הרוח"
להקפיד מאוד על לשון יחיד ורבים לפי ההקשר (כל אוסף או מערך למשל תמיד ייקרא בלשון רבים!!!)
להקפיד מאוד על תחביר נקי, אותיות חיבור, שמות נושאים ונשואים לפי סדר קבוע, ועוד דברים כפי שנראה בהמשך.
להקפיד על עקביות בנושא בחירת ייצוג השם, כפי שנדבר על כך להלן, ישנם כמה דרכים לשמות בעלי משמעות, איך לבחור שם לאובייקט.2. ענייניות ומשמעותיות
על השם להיות ענייני ובעל משמעות ולא מקושקש!
וכאן אטיל פצצה קטנה ויש יאמרו שאני קיצוני:
אם אין לכם שם לפונקציה תעצרו את העבודה, עד שתמצאו לה שם, כי אם אין לכם שם, יש חשש גדול להניח שהפונקציה שלכם "מלוכלכת". והדברים אמורים גם אם הלקוח שלכם מתפתל מכאבים ודוחק בכם לסיים!! עוד נדבר על היחסים עם הלקוח בנושא הזה בשיעורים הבאים.
אסביר מדוע: אדם הראשון מיד כשנברא קרא בשמות לכל הסביבה שלו, גם לעצמו הוא קרא בשם. דבר שהוא נטול שם, הוא חסר עצמיות מוגדרת, וככזה הוא חסר יכולת להתפס בהכרתנו. וכאשר אתה לא מוצא שם למשהו (על כך נדבר להלן, את מה השם אמור לייצג), אז עבורך זה לא משהו מוגדר ומובחן, וזו בעצם בעיה יסודית הכרתית, ולא בעיה טכנית!!! , וככל שהשם מובחן יותר, כך היחס שלך לעצם, הוא עמוק יותר. אז בארכיטקטורה אנחנו זקוקים לשמות בעלי תוכן מובחן, לא בשביל "להסתדר" אלא גם בשביל לוודא שהקוד שלנו נכתב בצורה נכונה.
מורי ורבי גם לימד אותי שהדבר החשוב ביותר שאפשר להקנות לילד, זאת שפה תקינה!!! את ההסבר לכך סיפקנו כרגע.3. בהירות
על השם להיות נהיר לקורא ולהכיל מבחינתו את כל מה שצריך לו לדעת בעת הקריאה הראשונית!!! לא להשתמש בקיצורים וראשי תיבות (אלא אם כן בדברים מקובלים שכבר הפכו להיות שפה ברורה, כגון קידומת או סיומת str שכולם יודעים שזה string. אבל מי שכותב פונקציה וקורא לה GetCustIDByProName הוא מבחינתי מאבד עצמו לדעת, למרות שמשמעות הפונקציה היא, לקבל את מזהה הלקוח לפי שם של פרודוקט, יש כאן חיסכון משונה באותיות, שזה תחביב מגונה של הרבה מתכנתים, "לדבר בלשון קצרה". אז בואו ונעדיף את הבהירות מאשר את הקיצור בעניינים אלו.
כעת ניגש לשאלת השאלות, "מה השם של הפונקציה אמור לייצג", האם את התוצאה שהיא מחזירה? את העבודה שהיא עושה? ומה יהיה כשהיא בעיקר עושה עבודה, והתוצאה היא רק "מידע" על העבודה שנעשתה. וכן הלאה וכן הלאה. הנושא הזה הוא כל כך טעון, עד שהוא בכלל לא מתאים לפורום הזה. הייתי כותב ספר שלם רק על הנושא הזה, מבחינת שפה. יש לא מעט מחקרים בתחום, אבל בהקשר של שפת הדיבור. וכולם אין בהם משום "בנין" שפה אלא "ביקורתה וסתירתה". ולכן הנטייה היא להשתמש יותר באינטואיציות. אבל לפי דעתי יש אפשרות לגבש מדיניות מסויימת, גם אם לא עלתה בידינו לחקור את הנושא התורני הזה לעומקו ולרוחבו. לפחות נחזיק בידינו את היתרון שאנחנו עובדים עם מדיניות כלשהי, ולא בפיזור וחוסר סדר. אז מה שנכתוב כרגע איננו מתיימרים להקיף את הנושא, אלא לתת כלים להגיע לקירוב כלשהו עד כמה שאפשר לכללים ברורים.
יש קצת הבדל בהתייחסות לפונקציה בין השפות, למשל ב JS פונקציה היא עצמה אובייקט, ולא משנה מה היא עושה, בדוט נט, יש הבדל בין קלאס, מאפיין ושדה, לבין פונקציה, שהפונקציה נעלמת מייד אחרי שמסיימת את העבודה, ומותירה אחריה רק את הערך שהיא מחזירה, אך אין הדרך לקרוא לה "אובייקט" וכן שגרה לא כל שכן שאיננה אובייקט.
הבה נתחיל מאובייקטים, שם יותר קל לתאר את השיטה. אובייקט, בשפה מונחית עצמים, אמור להיות נקרא בשם כפי שאנו רגילים לקרוא לעצם.
שמו של עצם יכול לייצג אותו בכמה דרכים הנה דוגמאות נפוצות:
שם ראשוני: כגון "שור" "חמור" "ברזל" וכדומה. אי אפשר להסביר למה קוראים לברזל ברזל. (וגם אם אפשר זה לא משנה כי לעולם רובנו משתמשים בשמות אלו כראשוניים ואנחנו מדברים עכשיו מבחינת הכרה רגילה איך הדברים מתנהלים)
שימושיות מובהקת: כגון "מכסה" על שם שמכסים בו, "מראה" על שם שרואים בה, "מרכב" על שם שרוכבים עליו, וכן "מנעול" "מפתח" "עמוד" "מזבח" "מחתה" וכדומה. כל אלו נקראים על שם הפעולות המובהקות שנעשות בהם.סימליות: היינו שמות המכילים סמל כלשהו, אך אינם מצביעים על שימושו המובהק של הדבר. כגון "מעקה" על שם שמעיקים עליו (מפי רבי) "חולצה" על שם שחולצים אותה (מפי רבי) "חבית" על שם שהנוזל חבוי בה, או "כף" על שם שנראית כמו כף יד אדם (כף היד היא מן הסתם שם ראשוני), ובשפה מודרנית יש כיוצא בזה ממש על ידי, "עכבר" "מסך" "אוזניות" וכדומה.
שמות של פעולות, אף הן יכולות לייצג מגוון היבטים:
הפעולה עצמה (בדרך כלל כשם ראשוני): כגון שלוף, הגדר וכדומה.
וכאן יש הבדל בין פונקציה לשגרה לבין אובייקט, ככלל, כל דבר שמחזיק ערך בתוכו, כגון משתנה, מאפיין או מחלקה (במידה ותפקידה להחזיק ערכים) וכדומה, שמו אמור לייצג את עצם הערך שהוא מחזיק. ואילו פונקציה שמחזירה ערך, שמה אמור לייצג "פעולת ההחזרה". אם תבדקו במייקרוסופט הם די מקפידים על זה, על ידי קידומת "Get" לפני פונקציות שמחזירות משהו. ואילו בשמות של מאפיינים אין את הקידומת get.
הסיבה לכך היא פשוטה, פונקציה היא "כוח עבודה" היא איננה אובייקט, ואילו מאפיין או משתנה, הוא אובייקט. אז כשיש לנו מאפיין או משתנה שמכיל רשימת אנשי קשר נקרא לזה "Contacts" ואילו כשיש לנו פונקציה שמחזירה רשימה כלשהי של אנשי קשר נקרא לה "GetContacts" מפני שהפונקציה במהותה היא כוח עבודה שמחזיר ערך, היא בעצמה לעולם איננה מחזיקה ערך, אחרי שהיא מסיימת את העבודה שלה היא נעלמת מהמחסנית. לכן לפונקציה נקרא על שם הפעולה, ולמשתנה נקרא על שם הערך שהוא מחזיק.
הבה נעבור לדוגמאות:
נניח שיש לנו תלמידים שצריך להצמיד להם חונכים, אם למשל יש שגרה שתפקידה לצרף תלמיד לחונך, הייתי קורא לה: AttachStudentToTeacher למה? כי השגרה תפקידה רק לבצע פקודה, ולכן הכי נכון לקרוא לה כשם הפקודה שאותה היא מבצעת.
אולם אם יש אובייקט שמכיל את המידע אודות התלמיד והחונך, הייתי קורא לו כך: StudentByTeacher האובייקט הזה זהו שמו האמיתי והראוי לו, הואיל והוא מייצג את המידע הזה, השם הזה מתאים למיכל של מידע, שמכיל את המידע הרצוי.
ואם יש לי פונקציה שאמורה להחזיר לי ערך של תלמיד לפי מורה הייתי קורא לה: GetStudentByTeacher המילה Get (תמצאו את זה בלי סוף בפונקציות של מייקרוסופט) אומרת שאתה רק "מקבל" את הערך, אולם האובייקט הזה לא "מכיל" את הערך. וזה חשוב מאוד להבדיל בין אובייקטים לפונקציות.
מצד שלישי, לפעמים יש לנו פונקציה שעושה עבודה של שגרה, אולם היא מחזירה לנו True או False בסוף רק כדי שנדע אם הפעולה הצליחה או נכשלה מסיבות כלשהן כגון כללי אימות. במקרה כזה הייתי קורא לפונקציה בשם של שגרה AttachStudentToTeacher ולא בשם של פונקציה, וכל כך למה? הואיל והערך שהיא מחזירה איננו מכיל את המידע שהשם שלה מייצג, אלא את המידע לגבי הצלחת הפעולה שלה. ראוי להתייחס אליה כשגרה לכל דבר.לפעמים ראוי לקרוא לשם שייצג את התוצאה של הפעולה ולא את הפעולה עצמה, למשל, נניח ויש לנו פונקציה שעושה בדיקה, האם עובד מסויים פנוי וזמין בשעה נתונה, הפונקציה מקבלת את ערכיה, עושה את עבודתה ומחזירה בסופו של דבר אמת או שקר, איך נקרא לפונקציה כזאת? CheckAvailabilityWorks ??? לא נראה לי, אני הייתי קורא לפונקציה WorksAvailable(שלא לדבר על כך שפונקציה זו אמורה להיות מאושכלת בירושה או שלא בירושה בתוך מחלקת עובדים אבל נניח לזה כרגע) למה? מפני שכאן הפונקציה מחזירה לנו ערך שמעניין אותנו, ומבחינתנו ראוי להתייחס אליה כאובייקט, כלומר פחות מעניין אותי כרגע מה היא עושה, ויותר מעניין אותי הערך שלה, האם העובד כרגע זמין. נמצאנו למדים, שפונקציה יש לקרוא לה על שם הערך שהיא מחזירה כאשר הערך הוא עיקר, ואילו על שם הפעולה שלה כאשר הפעולה היא עיקר מבחינתנו. (בשפות כמו C# המאפיין הוא סוג של הכלאה בין פונקציה למשתנה, ולכן זהו הכלי הכי טוב לעבודות מהסוג הזה)
ישנם שמות של מצבים הצמודים בדרך כלל למספרים או נוסחאות יחסיות: כגון מהירות, עוצמה, יעילות, וכדומה. כשנכתוב מדד כזה, בדרך כלל תהיה זאת פונקציה שתיקרא על שם הערך שהיא מחזירה, אולם פעמים שהיא מפעילה עוד צבא שלם של פונקציות סביבותיה, ועל כך נדבר בשיעורים הבאים שידונו בפיזור סמכויות.
נשתדל תמיד לקרוא לאובייקטים בשמות שאינם סמליים, אלא בשמות שהם בעלי משמעות שימושית מובהקת, אם אנו מדברים על עצמים, כגון מחלקות מאפיינים או משתנים, לא נבחר בשום אופן בשמות סמליים שבחרנו, "מחוסר ברירה" אלא נעשה מאמץ ונקרא להם בשמות שמשמעותם נובעת מתוך עצמם, גם אם זה יגרום לנו לאריכות יתר.
יותר קל לקרוא לאובייקט בשם, מאשר לפונקציה או שגרה ריקה שאינה מחזירה דבר, כי אובייקט, בסופו של יום ייקרא על שם המידע שהוא מכיל, ואילו פונקציה שעושה פעולה כלשהי, קשה לנו להגדיר מהי הפעולה שהיא עושה בדיוק, בפרט כשהיא חוליה בתוך שרשרת של פעולות. לכן ההמלצה שלי האישית, ככל שהשם יותר מעורפל, כך כדאי יותר לפצל את הפונקציה לפעולות בודדות נפרדות, על מנת להשיג בהירות בהפעלתן. זה גם יעזור לנו להבין טוב יותר את תפקידיהן השונים של הפונקציות שנכתוב.
מסקנא: שפה = בהירות מחשבתית. ולכן הארכיטקטורה האמיתית מבחינת איכות קוד, גלומה בשפה נכונה וברורה שאתם משתמשים בה.
בהצלחה לכולם ושנה טובה.
פורסם במקור בפורום CODE613 ב02/09/2013 17:10 (+03:00)
-
איזה שיעור כללי!!
בהלכות יסודי ה...תודה!
פורסם במקור בפורום CODE613 ב30/09/2013 20:25 (+03:00)