• #C,  Design Patterns

    Observer – גרסת הבמאי

    טרחתם, עשיתם חזרות, שיננתם את הטקסט ואחרי משהו כמו חמש שניות הבמאי קוטע את הדרמה בדיוק לפני הקטע הטוב ואומר (באנגלית זה נשמע יותר טוב): Don’t call us we’ll call you. אמנם יש בזה משהו מעצבן, אבל מצד שני זה גם הגיוני ויעיל – אתם עצמכם לא רוצים להתקשר שלוש פעמים ביום כדי לבדוק אם יש תשובה, וגם הבמאי לא רוצה להיות עסוק במענה לכל הטלפונים של המועמדים כפול שלוש פעמים ביום. עדיף שהוא יגבש החלטה, וכאשר יש שינוי כלשהו – הוא יעדכן את כל מי שצריך לעדכן. ה- Design pattern שמטפל בבעיה הזו נקרא – Observer. כלומר – צופה. זוהי למעשה מערכת שמבטאת קשר של יחיד לרבים. היחיד הוא…

  • #C,  Design Patterns,  ארכיטקטורת תוכנה | Software Architecture

    הכסף ירד מחשבון אחד. מה עם החשבון השני? להכיר את Unit of Work

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

  • #C,  ארכיטקטורת תוכנה | Software Architecture

    להכיר את ABP דרך פעולה אחת: ביטול הזמנה

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

  • ארכיטקטורת תוכנה | Software Architecture,  מיקרוסרוויסים | Microservices

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

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

  • #C

    למה string בשפת #C הוא Immutable?

    לא מזמן שאלתי בקבוצת המפתחים שלנו חידה קטנה: מה יודפס? התשובה היא True. אבל למה? הרי לא כתבנו b = a. יצרנו שני משתנים נפרדים, ושניהם קיבלו את אותו הטקסט. אחת התשובות שעלו בקבוצה היתה ש־string אינו ממש אובייקט רגיל, וש־#C מתייחסת אליו קצת כמו אל int. זו השערה מובנת, כי הרבה פעמים אנחנו משתמשים במחרוזות כאילו הן ערכים פשוטים. אבל string הוא Reference Type. אם רוצים לבדוק מה קורה עם int, אפשר לנסות: כאן התוצאה היא False. ‏ReferenceEquals מקבלת אובייקטים, ולכן כל אחד מהמספרים עובר boxing לאובייקט נפרד לצורך הקריאה. העובדה שהערכים שווים לא הופכת אותם לאותו אובייקט. התיעוד של Microsoft מסביר את ההבדל הזה. אז מה מיוחד בשתי…

  • #C,  Design Patterns

    תבנית Strategy בשפת #C: האם באמת צריך מחלקה לכל דבר?

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

  • #C,  Design Patterns,  SOLID

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

    רוברט מרטין (המוכר גם כ- Uncle Bob), האיש שהביא לנו את Clean Code, הגדיר במאמריו ובספריו חמישה עקרונות שנועדו לשפר את התכנון של מערכות תוכנה מונחות עצמים – OOP. חמשת העקרונות האלו עוזרים ליצור תוכנה קלה להבנה, לתחזוקה ולהרחבה. עקרונות אלו נודעו בראשי התיבות: SOLID והם: ________________________________________________________________________________________________________________ Single Responsibility Principle (SRP) יש אומרים שגברים לא יכולים לטפל ביותר מדבר אחד בכל פעם. לא יודע עד כמה זה נכון, אבל בכתיבת קוד, אכן מומלץ שלכל מחלקה תהיה אחריות אחת בלבד. כלומר, כל מחלקה צריכה לטפל בהיבט אחד בלבד של התוכנה ולא יותר מכך. לדוגמא: במקרה זה, מחלקת `Invoice` מטפלת רק בחישוב הסכום הכולל, בעוד ש-`InvoicePrinter` מטפלת בהדפסת החשבונית. טיפ: אם המילה…

  • #C,  SOLID

    איך עובד Linq ב- #C

    Linq היא טכנולוגיה המאפשרת לנו לתשאל נתונים בעזרת קוד #C. הכוונה במילה ‘לתשאל’ היא לכך שיש יותר מחמישים אופרטורים המאפשרים למיין, לסנן, לאחד וכו’ נתונים. למשל אם נרצה לקבל מתוך רשימת עובדים את העובדים שהם מנהלי מחלקות, נעשה זאת מן הסתם בעזרת Linq. אז איך Linq עובד? כידוע #C היא שפה סטטית, והטיפוסים (types) צריכים להיות קבועים ומוגדרים. ולכן, אם נרצה למשל ליצור מתודה בשם Where, שתחזיר לנו אובייקט מטיפוס Employee, נצטרך לדאוג לך שמתודת Where מכירה את הטיפוס שלנו. באופן מפתיע אנחנו רואים שLinq תומכת בכל סוגי המשתנים, אפילו אם הרגע הגדרנו אותם. נניח שמיקרוסופט היו יוצרים לנו Interface לצורך הסינונים האלה, ושהInterface הזה מחזיק את כל המתודות הנחוצות,…

  • Design Patterns,  SOLID

    Memento

    ממנטו היא תבנית עיצוב למימוש מנגנון שיחזור – כלומר לעשות undo או ctrl +z לפעולה שעשינו.  לפעמים התבנית הזו נקראת snapshot בגלל שהיא שומרת ‘תמונת-מצב’ קודמת ומאפשרת לחזור אליה.  הדרך הנוחה והמקובלת להסביר תבנית זו היא על ידי דוגמא של עורך טקסט.    נניח שיש לי עורך טקסט הממומש בקלאס בשם Editor או כפי שהוא נקרא במקור – Originator . אכניס לתוכו ערכים באופן הבא:  ואני מצפה שתהיה לי אפשרות לבטל את הפעולה / פעולות האחרונות. למשל שתהיה לי מתודה כזו:  איך הייתם מממשים מנגנון כזה?  אם למשל הייתי מוסיף לעורך שלי שדה נוסף מסוג STRING בשם prevContent ובכל פעם שאני רוצה לשנות את הערך של CONTENT הייתי שומר לפני…

  • Design Patterns

    Inversion of Control ו Dependency Injection

    Inversion of Control (להלן Ioc), היא תבנית עיצוב אשר ניתן להגדירה באופן כללי, כהעברת השליטה על תהליך כלשהו, כגון יצירת אובייקטים, הרצת קטע קוד וכו’, מהדרך הנקראת ‘רגילה’, על ידי תהליך מרכזי כלשהו, אל רכיב קוד אחר אשר יעשה הוא את העבודה. על ידי היפוך שליטה זה נרוויח לעיתים כמה דברים, כפי שתיכף ניראה. את IoC אפשר לממש בכל מיני דרכים בהתאם לתהליך עליו אנחנו עובדים, אך הכלי שבעזרתו מממשים IoC הוא תבנית עיצוב נוספת בשם Dependency Injection. לפעמים נרצה להשתמש ב IoC על ידי אינטרפייסים, כאשר הרעיון באופן כללי אומר שבמקום שתהליך כלשהו יצטרך להכיר את המחלקות המשתמשות בשירותיו, הוא פשוט צריך להגדיר Interface אשר רק אותו הוא מכיר,…