יום רביעי, 24 באפריל 2013

WCF Concurrency Mode

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

כאשר נשלחת בקשה מהקליינט לשרת, נוצר בשרת thread שמטפל בבקשה.
כאשר יש סכנה של מצב בו thraed-ים יכולים לגשת למשאב משותף, יש לנו בעיה. אנחנו יכולים לפתור אותה ע"י כתיבת קוד בשירות שיבצע נעילות על המשאב, או שאנחנו יכולים להמנע מכך באמצעות הגדרת התכונה  ConcurrencyMode

האופציות הקיימות לתכונה זו הם:


Multiple- ברירת המחדל. האובייקט של השירות שנוצר בשרת הוא multy-threaded. אנחנו צריכים לטפל בסנכרון בין ה thread-ים.
Single- האובייקט של השירות שנוצר בשרת הוא single threaded. כל הקריאות שיגיעו לשרת בזמן שהשירות עסוק- ימתינו עד סיום הטיפול בבקשה הראשונה, או עד timeout מסויים.
Reentrant- השירות הוא single אבל אם מתבצעת קריאה מהשירות לשירות חיצוני אז הוא מאפשר ל thread חדש להיכנס לשירות. זה נועד למנוע מצב של deadlock.

התכונה מוגדרת מעל הגדרת השרות. לדוגמא:

[(ServiceBehavior(ConcurrencyMode=Concurrency.Reentrant]
Public class SomeService: ISomeService

תהנו!

להשתמש ב int.Parse או Convert.ToInt32 ?

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

כן, יש הבדל:

Convert.ToInt32 קורא ל int.Parse, לאחר שהוא מבצע בדיקה אם הערך ששלחנו לו הוא null. אם הערך null אז הוא מחזיר 0. - מהבחינה הזאת קל לנו לראות יתרון קל בביצועים לטובת int.Parse . כמובן שזה נהיה משמעותי רק אם אנחנו קוראים לפונקציה המון פעמים.

אז למה לא תמיד להשתמש ב int.Parse?
  1. אם לא שלחנו לו string חוקי אז הוא זורק  ArgumentNullException ואז אנחנו צריכים לטפל ב exception שזה טיפול יקר (אולי בעצם נרצה שיזרוק- או שנשתמש ב TryParse?).
  2. int.Parse מקבל רק string,לעומת Convert שמקבל כל אובייקט שמממש IConvertible.
יש לשים לב ששתי הפונקציות יכולות להחזיר  FormatExeption לדוגמא אם שלחנו להם "123.45" , או שהם יכולות להחזיר OverflowExeption לדוגמא אם הstring  ששלחנו לו יותר גדול מ int.MaxValue

במקרה זה נשתמש ב int.TryParse שלא זורק אקספשיין אלא מחזיר במשתנה out אם הצליח או לא, אבל במידה ושלחנו string חוקי, ואין מצב שיזרק אקספשיין אז int.Parse יהיה יותר מהיר. אבל אם כבר אנחנו מעוניינים בביצועים יותר מהירים  - עשיית boxing ל int זוהי הדרך הכי מהירה להפוך string ל int.

אז בקצרה: מתי נשתמש בכל פונקציה-

אם x הוא boxed int אז הכי מהר להשתמש ב (int) 

אם x מספר וואלידי אז נשתמש ב int.Parse

אם לא בטוח ש x מספר וואלידי אז נשתמש ב int.TryParse כי אז לא נצטרך לטפל ב exceptions

אם אנחנו לא יודעים מה הוא x אז נשתמש ב Convert.ToInt32

תהנו!!!

יום שלישי, 23 באפריל 2013

מה זה Rest? או Restful Service

מי שבעצם הגדיר את Rest או Representational State Transfer הוא Roy T. Fielding (היה מבין מעצבי פרוטוקול HTTP). הגדיר זאת כסגנון ארכיטקטוני- שזהו בעצם דרך אבסטרקטית לבטא את הרעיון מאחורי הארכיטקטורה. סגנון ארכיטקטוני מגדיר את המאפיינים של הארכיטקטורה שתשתמש בסגנון הנ"ל... (Client-Server זה סגנון ארכיטקטוני).
הוא עוד הוסיף ואמר ש Rest מנסה להביא למינימום את ה latency ואת התקשורת ברשת, ובאותו הזמן למקסם את יכולת הסקלביליות והעצמאות  של הרכיבים עצמם.
הרעיון המרכזי של Rest זה במקום להשתמש בצורות מסובכות (כמו SOAP,RPC) כדי לתקשר עם מערכת אחרת, נשתמש בבקשת HTTP  פשוטה כדי לבצע את התקשורת שדרושה לנו. (מכיוון שלרוב Rest ממומש על Http, כך אתייחס בבלוג..)


 מאפייני Rest חשובים :
  1. מיושם באריטקטורות client-server
  2. למרות ש Rest פותח במקביל ל Http1.1, אפשר לממש את הסגנון הארכיטקטוני Rest  לא רק על גבי Http.
  3. הContext של הפנייה הוא Stateless
  4. הוא Cacheable- כלומר ניתן לעשות caching של תשובות השרת בזיכרון של מחשב הלקוח

העקרון המרכזי ב Rest הוא לתת לכל משאב ID. ב Web יש רעיון עבור IDs שנקרא URI- שזהו namespace גלובלי, והשימוש בו מבטיח לתת לכל משאב ID ייחודי גלובלי (קחו למשל דוגמא כתובת של אתר אינטרנט...).

Rest משתמש ב Http עבור כל פעולות ה CRUD שהם (Create/Read/Update/Delete), אך כמובן שהוא לא נצמד אליהם ויכול להשתמש בפעולות שהם Non-CRUD

Create- זוהי מתודת ה PUT - כלומר הוספת משאב חדש למערכת
Read- זוהי מתודת ה GET - קבלת משאב מהמערכת
Upadte- זוהי מתודת ה POST- עדכון המשאב במערכת
Delete - מחיקת המשאב מהמערכת

ב Rest אנחנו ניגשים למשאב ולא לשירות. המשאבים שלנו צריכים להיות מוגדרים היטב.

לדוגמא ניקח את הסנריו הבא:

יש לנו משב לקוחות ומשאב הזמנות (של לקוחות). השרות שלנו חושף רק את הפונקציות שמצוינות להלן:


בואו נראה איך המבנה יראה על פי Rest:

המשאבים שלנו יצטרכו לממש את ה Interface שנגדיר (בתרשים הבא אני אציג רק את המטודות שהמשאב משתמש (לצורך פשטות), למרות שבפועל הוא צריך להכיל את כל המטודות מה interface)




בואו נאמר שאנחנו רוצים לקבל פרטים של order מסויים. ( או בעצם להפעיל את הפונקציה GetOrder)

אם נשתמש ב Web Service וב SOAP הבקשה תראה כך:

<?xml version="1.0"?>
<soap:Envelope
xmlns:soap="http://www.w3.org/2001/12/soap-envelope"
soap:encodingStyle="http://www.w3.org/2001/12/soap-encoding">
 <soap:body pb="http://www.acme.com">
  <pb:GetOrder>
   <pb:OrderID>12345</pb:OrderID>
  </pb:GetOrder>
 </soap:Body>
</soap:Envelope>

וכנראה שגם יחזור לנו SOAP Response עם התשובה..

וע"י שימוש ב Rest הבקשה תיראה כך:

http://www.acme.com/Orders/12345

שתשלח לשרת ע"י בקשת HTTP GET,  ויחזור לי HTTP RESPONSE  עם התשובה.

למשל אם נרצה לקבל את כל הלקוחות:

http://www.acme.com/Customers

או למחוק לקוח מסויים (ע"י שליחת HTTP DELETE)

http://www.acme.com/Customers/1234

או לקבל את כל ההזמנות של לקוח מסויים:

http://www.acme.com/Customers/12345/Orders


אפשר גם לעשות שימוש בבקשות קצת יותר מורכבות:

http://www.acme.com/OrderDetails?ProductName=X&Year=2000

בד"כ בתשובה יחזור לי XML, אך בשונה מ SOAP, זה לא חייב להיות XML. זה יכול להיות גם JSOM,CSV

כלל חשוב שיש לשים לב זה שהגדרת ה URI מחייבת שתהיה אפשרות גישה לכל משאב בהיררכיות.
למשל: אם יש לי גישה ל
http://www.acme.com/Customers/12345/Orders

אז יהיה לי גישה גם ל:

http://www.acme.com/Customers/12345
http://www.acme.com/Customers

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

מתי נשתמש ב REST ומתי ב SOAP?
לזה נקדיש בהמשך פוסט נפרד..

תהנו!

יום ראשון, 21 באפריל 2013

Create session fake for unit test in ASP MVC

אני מפתח אתר אינטרנט עם דרישה שעבור חלק מהפעולות שהמשתמש מבצע על הפקדים המוצגים בדף יהיו רק לאחר בדיקת הרשאות המשתמש (למשל מחיקת הזמנה). לא משנה כרגע איך המימוש העיצובי (פקד ב disable או לא..)

את הרשאות המשתמש אני שומר במשתנה מסוג Session, כאשר בצד שרת (או בController) נבדק סוג ההרשאה, ועל פי סוג ההרשאה ממשיכים הלאה...

הכל הלך טוב ויפה, עד שהתחלתי לכתוב Unit tests. כשמריצים בדיקות, צריך לדמות את ה Context של ה HTTP.

אחד הדברים שהיה לי יותר קשה (לקח לי כמה שעות למצוא איך עושים זאת) זה לדמות את משתני ה Session ב Context (וכל זאת ללא שום שימוש בספריה חיצונית לבדיקות Unit Test).

אז הנה הפתרון:

נגיד שיש לנו Enum שמבטא את רמת ההרשאות:

    public enum Privilege
    {
        ADMIN,
        READ,
        WRITE,
        NOT_AUTHORIZED
    };

ובואו נאמר שיש לנו בController (נקרא לו SomeController) פונקציה עם הבדיקה הבאה:

    public JsonResult DeleteOrder(int orderId)
    {
        if ((Privilege)Session["Privilege"]==Privilege.ADMIN)
        {
           //TODO
        }
    }


עכשיו, כדי לכתוב Unit test שמדמה גם את אובייקט ה Session נצטרך ליצור את הקונטרולר באופן הבא:

נעשה using לבאים:

using System.Web.SessionItems
using MvcFakes

ונכתוב את הקוד הבא:

        private SomeController GetAdminSomeController()
        {
            SomeController controller = new SomeController();

            //create fake context
            var sessionItems["Privilege"]=Privilege.ADMIN;
            controller.ControllerContext=new FakeControllerContext(controller,sessionItems);

            return controller;
        }

unit test מוצלח!

יום שני, 15 באפריל 2013

למה צריך להבין מה זה Reference Type מול Value Type?

למה אנחנו צריכים להבין מה זה Reference Type ומה זה Value Type?
למה בכלל החברים במיקרוסופט עשו חלוקה ל 2 סוגי Type מרכזיים? יש לזה הצדקה?

אז קודם כל נתחיל בכך שנסביר את ההבדל המרכזי:
Value Type מחזיק את הנתון במקום משלו בזכרון. Reference Type מכיל פוינטר למקום בזכרון שמחזיק את הנתון.



עץ ה Type's

אני חושב שאחת הסיבות העיקריות שביצעו חלוקה כזאת היא מכיוון שלטיפוסי ה Reference הוסיפו שירותים נוספים על ידי הקומפיילר / סביבת זמן ריצה / ביצוע על חשבון ביצועים.
אילו שירותים הם מספקים?
בירושת אובייקטים אנו צריכים תמיכה בפולימורפיזם (שנעשה בהגדרת מטודות וירטואליות). המטודות הוירטואליות מסתמכות על "טבלת מטודות" שמכילות מצביע לאובייקט המכיל את המטודה. המצביע זוהי דוגמא לשירות הנוסף.
עוד שירות נוסף זה היכולת להשתמש ב Reference type בסינכרוניזצית Monitor   ( או C# lock)

חוץ מלקחת בחשבון את ה"שרותים" שהתווספו, אנחנו צריכים לחשוב גם על בעיות ביצועים. כאשר שולחים Value Type כפרמטר לפונקציה, אנחנו מעתיקים את ערכו. תחשבו על הבעיה שנוצרת אם אנחנו קוראים לפונקציה הרבה פעמים בתוכנית שלנו. כמה העתקות מיותרות בזיכרון נעשה.. צריך גם לקחת בחשבון אם אנחנו מעבירים לפונקציה struct מורכב..

לכן, צריך לקחת בחשבון את השירותים הנ"ל (ועוד בטבלה שבהמשך) שמסופקים כאשר אנו כותבים קוד. לא נרצה לקבל ביצועים יותר נמוכים (עקב הוספת התקורה של השירותים) כאשר נשמש ב TYPE שנרצה ליצור ממנו אלפי מופעים, לא נרצה לבזבז עבור כל מופע 4-16 ביט של תקורה..

טבלה מסכמת על ההבדלים בין Value Type ל Reference Type:


Value Types Reference Types
מחזיקים ישירות את הנתונים מחזיקים רפרנס לנתונים
שמורים על ה stack (אלא אם מוגדרים כמשתנים בתוך  Object Class) שמורים על ה heap
לא יכולים להיות null  אלא אם מגדירים אותם כ nullable יכולים להיות null
יש להם ערך דיפולטיבי אין להם ערך דיפולטיבי
אין צורך ב garbage collector, הכל מתבצע במהירות ב runtime ה garbage collector מנקה את הזיכרון 
בהעתקת תוכן של משתנה אחד לשני, שינוי של משתנה אחד לא משפיע על השני בהעתקת תוכן של משתנה אחד לשני, שינוי של משתנה אחד משנה את השני בהתאם
יורשים מ System.ValueType שיורש מ System.Object יורשים מ System.Object
כשמעבירים כפרמטר לפונקציה אז הערך מועתק כשמעבירים פרמטר לפונקציה אז מעבירים את הרפרנס
פונקציית Equal משווה את הערכים פונקציית Equal משווה את הרפרנסים
ממומש כ Struct ממומש כ Class
תהנו!

יום שישי, 12 באפריל 2013

My Builder Design Pattern

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

אני לא אפרט על תבנית העיצוב, אלא אני אתן דוגמא לשימוש מעט שונה בתבנית העיצוב Builder שמתבסס על המקור.
בכל מקרה יש הסבר מצוין על Builder ב CodeProject עם דוגמאות קוד.

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

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

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

נניח שבפתרון הנאיבי האובייקט שלנו יראה כך:

 public class BankClient
        {
            public string FirstName { get; set; }
            public string LastName { get; set; }
            public string City { get; set; }

            public BankClient(string firstName, string lastName, string city)
            {
                FirstName = firstName;
                LastName = lastName;
                City = city;
            }
        }

אתם אומרים לעצמכם- מה הבעיה?
תחשבו שזהו class תשתיתי. תחשבו על מקרה שבו מתכנת מצוות אחר, שאיתחל את האובייקט, ובטעות בלי לשים לב עשה "מיקס" בין הפרמטרים (כלומר שם פרטי במקום שם משפחה והפוך- כבר ראיתי באגים כאלו), הרי זה קל לטעות, שניהם string. תחשבו אם הוא מתבלבל בפרמטרים יותר מורכבים (מחיר מקסימלי ומחיר מינימלי). תחשבו אם לאובייקט היו יותר פרמטרים (לא 3 כמו בדוגמא, אלא 7-10- ראיתי כבר כאלה).

אז מה הפתרון?

נשתמש ב Builder pattern: (אשנה אותו מעט שיתאים לבעיה הנ"ל):

האובייקט לקוח יראה כך:


 public class BankClient
        {
            public string FirstName { get; set; }
            public string LastName { get; set; }
            public string City { get; set; }
        }


נצהיר על ה interface של ה Builder:
  interface IBankClientBuilder
        {
            BankClient newInstance();
            BankClientBuilder firstName(string firstName);
            BankClientBuilder lastName(string lastName);
            BankClientBuilder city(string city);
        }


וכך תראה מחלקת ה Builder:
  public class BankClientBuilder:IBankClientBuilder
         {
            private BankClient bankClient;

            public BankClientBuilder()
            {
                bankClient = new BankClient();
            }

            public BankClient newInstance()
            {
                return bankClient;
            }

            public BankClientBuilder firstName(string firstName)
            {
                bankClient.FirstName = firstName;
                return this;
            }

            public BankClientBuilder lastName(string lastName)
            {
                bankClient.LastName = lastName;
                return this;
            }

            public BankClientBuilder city(string city)
            {
                bankClient.City = city;
                return this;
            }

        }

מה יש לנו כאן? הבנאי של ה Builder מאתחל את האובייקט שלנו (במקרה זה אובייקט "לקוח"), ויש לנו פונקציה עבור כל פרמטר. כאן לדוגמא הפונקציות מקבלות string כלשהו, אבל כמובן אפשר לשנות אותם כך שיקבלו enum כלשהו, או אפילו שום פרמטר, ושאנחנו נקבע את הפרמטר. תראו גם איך פישטנו את העניין- אפשר להוסיף עוד פרמטרים בלי לשנות בעצם שום קוד בצד שמבקש לקבל את האובייקט.
איך יראה איתחול האובייקט (או במילים יותר יפות- קבלת האובייקט:)
 static void Main(string[] args)
        {
            BankClient client = new BankClientBuilder().firstName("Eyal").lastName("Cha").city("RL").newInstance();
        }


שימו לב איזה יופי, המתכנת שמבקש לקבל את האובייקט מגדיר בעצמו את האובייקט שהוא רוצה לקבל, בלי אפשרות לעשות מיקס בין הפרמטרים. אפשר כמובן לשפר את מחלקת ה Builder- למשל לבדוק אם הצד המבקש שכח להצהיר על פרמטר כלשהו (למשל שכחו להצהיר על שם פרטי) ואז לזרוק exception.. תהנו!