אם הגעת לפוסט הזה מבלי לקרוא את הפוסט הקודם אנא עצור כאן ולך לפוסט הקודם, אחרת אתה מפספס את כל הכף.
אל תתעצל, לך לפוסט הקודם.
טוב, שלא תגיד שלא הזהרתי אותך.
אז להלן רמז נוסף לשאלה למה ה Reflector פישל.
לך בבקשה ל Explorer ופתח אותו באיזה תיקיה שאתה רוצה, לאחר מכן לחץ על עכבר ימין ובקש New Folder. תן בבקשה לפולדר הזה את השם aux, האם הצלחת ? לא, לא הצלחת.
נסה prn ? יש כאן איזה שהוא Pattern ? מצלצל פעמון באיזה שהוא מקום ?
נסה lpt1, מעניין ? מה עם Com1 ? אני מניח שכבר תפסתם את הפרנציף.
אי אפשר לייצר קובץ או תיקיה שהשם שלהן הוא אחד מהשמות שמופיעים ב Global Namespace כשם של Dos Device. למה ? ככה !. מאחר והרפלקטור פותח תיקיה לכל חלק ב NameSpace, אז אם כללת ב Namespace חלק ששמו כאחד מהשמות השמורים ב NameSpace (למשל aux בדוגמא שנתתי), אי אפשר לייצר את התיקיה הזו. מה שאומר שלא תצליח לעשות Export ל NameSpace הזה מה Reflector.
מה שמוליך לשתי שאלות שלא קשורות אחת לשניה. שאלה ראשונה היא למה לעזזל מיקרוסופט עושה את זה ? והשאלה היותר מעניינת, היא למה החברים ב Red-Gate לא בודקים את ה Return code של Create folder ולא מדוחים על הבעיה כמו שצריך, אלא פשוט מדווחים שהכל הצליח בשעה שזה לא הצליח. ואני חותם לכם שהם קיבלו Return Code רע על הבעיה הזו. כי לאחר שהבנתי מה הבעיה, סתם מתוך סקרנות, הרצתי Process Monitor על ה Reflector בזמן הביצוע של ה Export, והוא דיווח לי שהיישום קיבל Failour בנקודה הזו. ואם הוא דיווח את זה לי, הוא דיווח את זה גם להם.
למי שסקרן לדעת מה עשיתי כדי לפתור את הבעיה, אז אני מתבייש להודות שהשתמשתי ב Brute force. שעשיתי Roun trip ל DLL תוך שימוש ב ILDasm ו ILAsm, כאשר בדרך עשיתי Edit ידני על הקבצים, ושיניתי כל הופעה של aux ל aux1 (עשיתי את זה עם Replace all אחד). כן זה לא אלגנטי במיוחד, ואפילו מגעיל, אבל מדובר היה רק ב DLL אחד, ולא היה לי כוח להתקשקש עם זה באלגנטיות.
אני די בטוח שכשהתחלתי את הסיפור הבלשי, לא ציפיתם שהוא יסתיים בשרידים הארכיאולוגיים של עולם ה DOS. אבל אין מה לעשות, Real Programmers use DOS, ושלא יספרו לכם ש DOS מת, הוא איתנו לנצח.
אני תמיד מסביר למי שמוכן להקשיב לי, שמציאה של Bug בסביבת הייצור אינה החלק החשוב בתהליך. מי שעוצר ב Bug, יגלה שיש לו בפרויקט עוד המון Bug – ים שכולם יופיעו בשלב זה או אחר בסביבת הייצור או אצל הלקוח. השאלה החשובה באמת היא איך ה Bug הגיע בכלל למערכת. הרי ה Bug לא היה בספציפיקציות של המוצר, אז מאיפה הוא הגיע למוצר הסופי ?
הטעות הכי גדולה שיכולה לעשות מערכת פיתוח/ייצור, היא לעצור במציאת ה Bug, לתקן אותו, ולסמן V. הדבר הנכון הוא לא לעצור ב Bug, אלא לנתח לעומק, את כל השרשרת של הטעויות, שהביאו לכך שה Bug נמצא במוצר הסופי, ולהגיע לשורש הבעיה (The Root Cause of failour). התוצר של התהליך הזה, הוא שלא "רק" פותרים את ה Bug, אלא מגלים בדרך הרבה אחים ואחיות חורגים של אותו Bug, וכתוצאה מזה מקבלים שתי ציפורים ביריה אחת. גם מתקנים את כל משפחת ה Bug – ים, וגם מונעים את החזרה של כל ה Bug – ים מאותה משפחה למוצר.
הבעיה שאני מספר עליה כאן, התחילה משאלה נורא פשוטה, שנתקלתי בה אצל לקוח. איך אני משווה שני DLL – ים כתובים ב NET. ומוודא שהם זהים. השאלה הראשונה שהתעוררה אצלי בנקודה הזו, היא למה לעזזל שמישהו יצטרך לעשות דבר כזה ? שיוציא מה Source Control את הגירסה הישנה, וישווה אותה אל מול החדשה, ויגמור עניין. לאחר חקירה בכיוון הזה, שבה נתקבלו כמה תשובות נבוכות, נסתברו העובדות הבאות: א. יש Source Control, ב. קוראים לו Source Safe, ג. לא היה ניתן להוציא ממנו את הגירסה הקודמת, כי לא שמרו אליו גירסאות תוך שימוש נכון ב Labels (או כל אמצעי סימון אחר). ד. ה Source safe שימש יותר כמערכת Backup ופחות כ Source control. כל זה הוליך לבעיה, שלאחר שה Source שוחזר ידנית, למצב שבו חשבו, שמצב הקוד הוא בדיוק כמו הגירסה שנמסרה ללקוח. נוצר הצורך החשוב, לבדוק שההנחה הזו באמת נכונה. לכן היה צורך להשוות בין ה DLL – ים שמוציא הקומפילר, לאלה שנמצאים בפועל אצל הלקוח בסביבת הייצור.
שימוש ב Source safe כיום הוא אנכרוניסטי, למה להשתמש במערכת כל כך ישנה ומוגבלת כאשר יש TFS. ולא שהיתה כאן בעיה של רשיון או כסף. ללקוח היה כבר MSDN, כך שהמעבר מ Source Safe ל TFS לא היה יותר מאשר החלטה טכנית מנהלתית, וכמה דקות של Convert. ולהזכירכם, ל TFS יש Brance ו Shelf וקישור אוטומטי ל Work Item בזמן ה Check In, שאלה כלי עבודה שימושיים מאד, שאין ל Source safe.
דרך אגב, לא סתם אני אומר שהמעבר יקח כמה דקוות. כי אם אתה מעביר את הפרויקט כמו שהוא, זה כמה דקות. אבל אם אתה מנצל את ההזדמנות "לעשות סדר" בפרויקט, ואם אתה מחליט באותה הזדמנות גם להמיר אחורה את כל ההיסטוריה (כדי שניתן יהיה לדעת איזה שינוי נעשה בקוד בשנת 1954), ועוד כמה שטויות כאלה, זה בהחלט יכול להפוך לפרויקט רב שנתי.
אני בעד הגישה של, או להשתמש ב Converter המובנה של TFS, או פשוט לשאוב גירסה אחרונה מה Source Safe, ולהכניס אותה כפי שהיא ל TFS, ולהמשיך משם. אין לי בעיה ששתי המערכות יחיו Side By Side, עד אשר ה Source Safe ימות לבד מבדידות וחוסר שימוש. אבל כמובן, אני אשמח לשמוע דעות אחרות בנקודה הזו (ולכסח אותן באלימות).
אבל זה לא נעצר כאן. השאלה היותר מעניינת היא למה לא ניתן היה להוציא ב Soure Safe את הגירסא הנכונה ? כאן אנחנו נכנסים לתחום ה Process Plumber שלי דהינו בעיה בתהליך. כמה ש Source Safe נחשב לתוכנה דפוקה בימינו, הוא עדיין מערכת, שאם משתמשים בה נכון, יודעת לעשות את העבודה. הבעיה נוצרה מזה שפשוט לא השתמשו נכון במוצר. וכאן מקור הבעיה הוא פער ידע. הצוותים, ומה שיותר חשוב ראשי הצוותים, פשוט לא ידעו איך עובדים עם Labels, ומתי פותחים פרויקט חדש בעץ (שזה שווה הערך המאד לא טוב ולא דומה ל Brance), אלא השתמשו ב Source Safe כמעין מערכת Backup, מבלי להבין שללא תיוג מתאים של פעולות השמירה, המערכת מאבדת את רוב (אם לא את כל) יכולות ניהול הקוד שלה. ומכאן בעצם התחילה הבעיה.
אם המערכת תעבור ל TFS, מבלי שראשי הצוותים יקבלו הדרכה מלאה על מערכת ה Source Control של ה TFS, הדרכה שכוללת רקע תיאורטי על איך צריך לנהל Source ב TFS ולא רק את התפריטים. המפתחים כבר ימצאו דרך לעשות Abuse גם ל Source control של ה TFS, והבעיה תחזור באיזה שהוא שלב בצורה זו או אחרת. לא משנה לצורך העניין, כמה ה TFS טוב יותר מ Source Safe. כי המערכת הכי חכמה, לא תעמוד בפני המתכנת חסר הידע. השאלות התיאורטיות של מתי נכון לפתוח Brance, איך נכון לארגן את הפרויקט ב TFS, השימוש הנכון ב Shelf, או לחילופין, מהם שדות החובה שעל מפתח למלא בטופס בזמן ה Check In, הם שאלות שצריכות להיות ברורות, לא רק לראשי הצוותים, אלא גם לכל אחד מהמפתחים שמשתמשים בכלי. אז תוסיפו בבקשה לכמה דקות של ההמרה, גם כמה שעות של הדרכה לכל הצוות. ואני מקווה שברור לכם שאם היתה מתבצעת הדרכה דומה, למפתחים וראשי הצוותים, על ה Source Safe, הבעיה שנתבקשתי לפתור לא היתה נוצרת בכלל וההגעה למצב נתון של הקוד לא היתה דורשת התערבות ידנית.
אני נוהג כל פעם שאני נוגע בקוד, להוסיף בקוד שורה אחת של הערה, עם השם שלי, התאריך, מה שיניתי ובעיקר למה. אחרי 10 שנים, אתה לא זוכר בדיוק מה עשיתה ולמה, וכאשר אתה צריך לרדת מרזולוציה של Check In לרזולוציה של שורות בקוד, ההערות האלה חוסכות לך זמן יקר. כן, זה מנפח את הקבצים, אבל מצד שני, שטח דיסק זול יותר משעות עבודה, וזה בטח מקטין את רמות הסיכון של שינויים בהמשך. אם הנוהל הפשוט הזה היה מתבצע בפרויקט הנ"ל, העבודה הידנית של "החזרה לאחור" היתה קלה יותר.
טוב אז בואו ונמשיך הלאב בסיפור הבלשי. הרעיון הראשון שלי היה להשתמש ב IlDasm כדי לפרק את שני ה DLL – ים לגורמים ואז פשוט לעשות Diff בין הקבצים. רעיון מבריק אבל זה לא עבד, כי IlDasem באמת מפרק את הכל, אבל לא באותו סדר, ואז ה Diff מאבד באיזה שהוא שלב את הצפון.
השלב הבא היה לעבור ל Reflector או למשהו דומה, אבל מאחר וה Reflector עולה כסף חיפשתי בשלב הראשון פתרון חינמי אחר, וניסיתי את Just Compile של Telerik. זה לא עבד, יותר מדי Errors של הכלי. לא היה לי כוח לחפש עוד כלים (ואני אשמח לקבל משוב בנקודה הזו מכל מי שמכיר מנסיון כלי שיכול לעזור בסיטואציה הזו). אז התקנתי את גירסת הנסיון של ה Reflector על אחד ממחשבי הפיתוח במעבדה שלנו, והתחלתי לעבוד.
התהליך היה להכניס את זוג ה DLL – ים שדורש השוואה ל Reflector (אחד אחד בנפרד). ולשמור את ה Source של ה DLL באמצעות Export Assembly Source Code, ולהשוות בין התוצאות עם Diff.
כמובן שה Diff יצעק על ה Guid שמתחלף בין קומפילציות, אבל זה רק שתי שורות ב Diff, שקל לראות שאין להן קשר לקוד. ומאחר ודובר על כמות סופית וקטנה של Dll – ים להשוואה, לא חיפשתי פתרונות נוספים, אלא עברתי על ה DLL – ים ידנית.
הכל הלך כשורה עד שהגעתי ל DLL אחד שסירב בכל תוקף לבצע Export. לא היתה הודעת שגיאה ! פשוט לא קיבלתי קובץ Source.
חשוב לציין שהבעיה לא היתה ביכולת לעבור על הפונקציות ברפלקטור דרך ה UI, אלא רק ביכולת לעשות ל DLL הזה Export. ומאחר ובשאר ה DLL – ים לא נתקלתי בבעיה הזו, היה ברור שיש משהו ב DLL הזה שדופק את הרפלקטור.
אז להלן גירסת הקוד של ה DLL המינימלי שמשחזר את הבעיה, ונראה אם מישהו מכם מצליח לאתר את מקור הבעיה.
לא יכול להיות קוד פשוט יותר. רק שכדי שתידלק לך מנורה אדומה (כמו שנדלקה לי), בשלב הזה, אתה צריך להיות מספיק זקן (וזה רמז).
אז אני עוצר כאן את הפוסט, ומבטיח לכם, שבפוסט הבא אני אגלה לכם את התשובה (שבטח תפתיע את כל הצעירים). אל תציצו בתשובה, תנסו להבין למה בצורה שבה עובד הרפלקטור, קוד כזה איננו ניתן ל Export. ולא צריך בשביל התשובה לזה כלי Debug מיוחדים.
ilspy שווה חינימי ועושה את רוב העבודה……….