לפני מספר ימים אליק לוין תפס אותי במסדרון והתחיל לשאול אותי כל מיני שאלות לגבי מה אני עושה בתקופה האחרונה, איך אני מנהל את האתגרים העומדים בפני, מה הערך המוסף שאני מביא ללקוחות שלי ועוד שאלות מציקות אחרות, בקיצור התחיל לחפור. די במהרה הגענו למסקנה שיהיה נחמד לשתף את הקהילה בדברים שעלו בשיחה. אז הנה השאלות והתשובות:
שאלה: מה תחום ההתמחות שלך ?
תשובה: בשנים האחרונות בניתי ארכיטקטורה לפרוייקטים גדולים כך שניתן להגיד שתחום ההתמחות שלי הינו בניית ארכיטקטורה למערכות גדולות בין היתר,מערכות שו"ב, מערכות מודיעין, מערכות בתחום הפיננסים ועוד. מלבד בניית ארכיטקטורה אני גם מחובר מאד לקוד כך שיוצא לי להתעסק לא מעט עם שיפורי ביצועים במערכות שונות.
שאלה: היכן אתה מבלה בימים אלו ומהם האתגרים העומדים בפניך ?
תשובה: בימים אלו אני מחלק את זמני בין שני לקוחות עיקריים:
את הלקוח הראשון אני מלווה בנושא שיפור ביצועים באפליקציה אינטרנטית המבוססת על MOSS . פעילות זו מאופיינת בשני אתגרים: האתגר הראשון הינו להביא את הפרויקט לעמידה ביעדי הביצועים אותם הלקוח הגדיר תוך קבועי זמן קצרים מאד ואילו האתגר השני הינו ללמוד את הארכיטקטורה וה design של הפרויקט כפי שהספק של הלקוח אפיין ויישם (אני לא הייתי מעורב בארכיטקטורה וב design של המערכת), למפות את הנקודות העיקריות בפרויקט המצריכות טיפול וכל זה תוך שמירה על כך שנצטרך לבצע מינימום שינויים בלב המערכת (במידת האפשר) על מנת לעמוד ביעדי הזמנים של הפרויקט.
ללקוח השני אני עוזר במיפוי פערים בנושאי ארכיטקטורה היכולים להשפיע מבחינה כספית על ההזמנה שהוא כרגע מנהל במשא ומתן מול הספק. לאחר החתימה על החוזה אנו נגבש צוות ארכיטקטורה המורכב מנציגים של הלקוח והספק ונבנה את הארכיטקטורה של הפרויקט.
שאלה: איך אתה מתמודד עם האתגרים בפעילויות אותם אתה מלווה ?
תשובה: הגישה שלי לניהול הפעילויות/אתגרים העומדים בפני מבוססת על היכרות מעמיקה עם מתודולוגיות ו best practices אך גם על היכרות מעמיקה עם הטכנולוגיות השונות. לדוגמא, בפעילות של שיפור הביצועים יש צורך ב:
- היכרות עם MOSS ו best practices לשיפור ביצועים כגון האופציה להפעיל סוגים שונים של cache , שימוש ב PortalSiteMapProvider ועוד.
- היכרות עם פלטפורמת ASP.Net 2.0 ו best practices לשיפור ביצועים עם פלטפורמה זו. חלק מהפיתרון שמימשנו היה להשמיש את מנגנון ה caching עבור user controls ושימוש ב SQL Server Caching כפי שמתואר ב webcast.
- היכרות עם כלים לניתוח ביצועים כגון Fiddler , Visual Round Trip Analyzer . בעזרת כלים אלו ואחרים זיהינו את חלוקת הזמן ב server side processing של הדפים השונים באתר ושיכתבנו מחדש את הwebparts הבעייתיים שלקחו את מרבית הזמן בטעינת הדף, כמו כן ניתחנו בעזרת אותם כלים את מספר ה requests לדפים השונים, האם הקבצים שקיבלנו היו מה cache או לא, האם הקבצים הגיעו מקומפרסים ועוד.
- היכרות עם מתודולוגיות ניהול ביצועים של מיקרוסופט כגון PDL כפי שמתואר בהרחבה בבלוג של אליק
- ניסיון בניהול תהליכי שיפור ביצועים במערכות אחרות.
שאלה: מה "סוד" ההצלחה שלך בתור יועץ ?
תשובה: אני חושב שצמד המילים Trusted Advisor משקף את ה DNA ממנו מורכבת הקבוצה שלנו. תחת Trusted Advisor מוכלים היבטים כגון:
- היכולת להבין את הצרכים העסקיים של הלקוח
- היכולת לבנות יחסי אמון וידידות עם הלקוח
- היכולת להגיד את האמת גם אם היא קשה, לא לנסות לטייח דברים או לייפות את המציאות
- ניסיון בבניית ארכיטקטורות בעיקר לפרוייקטים גדולים ומורכבים.
שאלה: איך הניסיון שלך חוסך כסף ללקוח ?
תשובה: הניסיון של הקבוצה שלנו חוסף כסף ללקוחות בכך שאנו עוזרים לו לקצר תהליכי עבודה. קיצור תהליכי העבודה מתבסס על ניסיון מקצועי, היכרות עם מתודולוגיות ו best practices, היכולת להביא מומחי תוכן שונים מתוך מיקרוסופט עבור סיוע בבעיות שאינן בתחום ידיעתנו, קשר עם צוותי הפיתוח ועוד.
שאלה: רוצה קפה ?
תשובה : ברור..
...היא התשובה לשאלה הבאה שנשאלתי השבוע:
"מהי הדרך המומלצת ביותר לטפל ב- Exceptions ביישום שלי?"
זה אולי נשמע לא אינטואיטיבי ולא נכון, אבל האמת שלטעמי זו דרך הפעולה המועדפת. אלא אם כן יש סיבה טובה מאוד לעשות את זה - אל תטפלו ב- Exceptions. אל תמלאו את הקוד שלכם ב- Try...Catch לא נחוצים אל תתפסו כל סוג שגיאה שאתם חושבים שעלול להתעורר ביישום.
הסיבה לכך פשוטה מאוד - בהרבה מאוד מקרים, אין לנו מה לעשות עם ה- Exception חוץ מאשר לרשום אותו ללוג, ואת זה אפשר לעשות במקום מרכזי אחד. לא צריך לבצע את זה בכל פונקציה או Property.
בכלל, נראה לי שלעתים הטיפול ב- Exception נמצא בידיים הלא נכונות, והחשיבה הטיפוסית היא שזה משהו שתוכניתנים בלבד אחראים לו. אני טוען שטיפול בשגיאות ביישום הוא משהו שצריך לעבור גם דרך האחראים על האפיון, שצריכים לתת את הדעת לגבי אופן הפעולה הנדרש כאשר היישום נכשל. לדוגמה - מה אמור לקרות כאשר לא ניתן לגשת למקורות מידע מסויימים לשם שליפת מידע, אבל מקורות אחרים פועלים כראוי? האם היישום צריך "לעוף"? האם המשתמש צריך לקבל הודעה אבל להמשיך לעבוד כרגיל? אלו לא החלטות שתוכניתן צריך, ורשאי, להחליט. זו החלטה אפיונית טהורה.
הנושא הזה הוא רחב מאוד, ולא ניתן לסכם אותו בפוסט קצר אחד, אבל יש להבין שטיפול ב- Exception הוא לא משהו שעושים כלאחר יד, ולא משהו שמשאירים לרגע האחרון. יש לגבש תפיסה מקיפה ואחידה לגבי הטיפול בנושא זה כמה שיותר מוקדם.
מקור מצויין לתפיסה שכזו נמצא בקישור הבא:
http://msdn.microsoft.com/en-us/library/ms229014(VS.80).aspx
מומלץ לקרוא!
Unity and AOP: InterfaceInterceptor Example.
One of the solution architecture design key decisions is the cross-cutting concerns handling.
When we look at many of these cross-cutting concerns, we can recognize a pattern. Many of them happen only at either the start or the end of a method:
This leads to a different approach to implementing cross-cutting concerns. We can put some special handling before or after method calls , get the code out of the methods and enhance its maintainability.
The Unity 1.2 Interception extension lets us do just that.
Interception is a design pattern that is designed for cross-cutting concerns. Unity 1.2 provides support for interception through the Interception container.
The Unity Interception extension ships with two instance interceptors and one type interceptor:
Selection of a specific interceptor depends on your specific needs, because each one has various tradeoffs.
Below is an example of using the InterfaceInterceptor which works very similar to the VirtualMethodInterceptor,but, in current case the Logger Class implements an ILogger Interface which makes the use of the InterfaceInterceptor possible for AOP.
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Microsoft.Practices.Unity;
using Microsoft.Practices.Unity.InterceptionExtension;
namespace UnityAOPDemo
{
class Program
{
static void Main(string[] args)
{
IUnityContainer container = new UnityContainer();
container.AddNewExtension<
Interception>();container.RegisterType<ILogger, Logger>(); container.AddNewExtension<Interception>();
container.Configure<
Interception>().SetInterceptorFor<ILogger>(new InterfaceInterceptor()); var logger = container.Resolve<ILogger>();
logger.Write(
"Hello World...");Console.ReadKey();
}
}
public interface ILogger
{
[
Log] void Write(string message);
}
public class Logger : ILogger
{
public void Write(string message)
{
Console.WriteLine(message);
}
}
public class LogAttribute : HandlerAttribute
{
public override ICallHandler CreateHandler(IUnityContainer container)
{
return new LogHandler();
}
}
public class LogHandler : ICallHandler
{
public int Order { get; set; }public IMethodReturn Invoke(IMethodInvocation input, GetNextHandlerDelegate getNext)
{
Console.WriteLine("Log before..., ");IMethodReturn msg = getNext()(input, getNext);
Console.WriteLine("Log after... ");return msg;
}
}
}