ארכיון

Posts Tagged ‘תכנות’

אין כאן לולאה

07/10/2011 38 תגובות

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

אתם מכירים את חוקי המשחק. צריך לחלץ את לולאת החוט מן המסגרת. למי שהתייאש, הדוד הנחמד שהכין את הצעצוע החביא צ'יט – אם חובטים אותו מספיק חזק בקיר, הלולאות נשברות והחוט יוצא בלי מאמץ בכלל. מוי קל!

אין כאן לולאה

אבל זה צעצוע מחשבה, אז נתון לנו שהבעיה פתירה גם בלי צ'יטים. ולמה היא פתירה? זה פשוט – אינטואיטיבית, אפשר להגיד שהחוט והמסגרת לא מהווים שתי לולאות סגורות ששלובות זו בזו. כיוון שברור לנו שהחוט הוא לולאה סגורה, הרי שמסגרת העץ היא צורה "פתוחה" שמאפשרת לחלץ ממנה את החוט[1]. מה הכוונה? אם נדמיין שהמסגרת לא היתה עשוייה מעץ, אלא מחומר רך כמו חוט או בד, היינו יכולים לנתק את הלולאות זו מזו ולקבל את המבנה הבאה:

טוב, בערך.

עם כזו חידה אני חושבת שאני יכולה להסתדר.

אז למה יש כאן אתגר?

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

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

היינו מעבירים את חלק החוט המסומן בחץ אדום קטן לאורך הקו המקווקו ומחלצים את החוט. עכשיו יש לנו ביד אלגוריתם[2] קטן שיודע להעביר חוט מצד אחד של לולאה שתקוע לה צ'ופצ'יק באמצע, לצד השני שלה:

  • העבר חוט מצד אחד לצד שני של הלולאה (A -> E)
    • העבר חוט מצד אחד לצד השני של הצ'ופצ'יק מתחת ללולאה (B -> C)
    • העבר חוט מצד אחד לצד השני של הצ'ופצ'יק מעל הלולאה (D -> E)

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

בעיה בתוך בעיה בתוך בעיה בתוך…

ההגדרה הוויקיפדית לרקורסיה היא:

רֵקוּרְסִיָּה (בעברית: נסיגה) היא תופעה שכל מופע שלה מכיל מופע נוסף שלה, כך שהיא מתרחשת ומשתקפת בשלמותה בתוך עצמה שוב ושוב.

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

גם אלגוריתמים יכולים להיות רקורסיביים. אלגוריתם רקורסיבי, הוא אלגוריתם שעושה שימוש במופע של עצמו. אלגוריתם אריה במדבר הוא דוגמת בית-ספר קלאסית (אם כי דבילית במקצת), והוא הולך ככה:

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

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

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

אז איך הרעיון של רקורסיה עוזר לנו?

אם נחזור לבעיה שעל הפרק נשים לב שהיא בנויה בצורה רקורסיבית גם כן – בתוך הלולאה הראשונה תקועה לולאה נוספת, שבתוכה תקועה לולאה נוספת שבתוכה… עד לסף העצירה – בלולאה האחרונה תקוע צ'ופצ'יק ולא לולאה. אנחנו גם יודעים איך לפתור את החידה כשהיא "קטנה מספיק", כלומר – בנויה רק מלולאה וצ'ופצ'יק[3].

עכשיו נעיף מבט קרוב יותר בצעצוע (קליק לתמונה בגודל סביר).

אנחנו כבר יודעים שכדי לחלץ את החוט, אנחנו צריכים להעביר אותו מ A.2 לA.1, וכבר הבנו שבשביל זה צריך קודם כל להעביר אותו מ B.1 ל B.2. אבל בעצם, אם נדמיין שהלולאה הראשונה הוסרה באורח פלא ממקומה (נגיד, באמצעות הקסם "הכאה בפטיש" דרגה 8), נראה שהבעיה של העברת החוט מ B.1 ל B.2 זהה במהות שלה להעברת החוט מ A.2 ל A.1, רק שהפעם הצעצוע בנוי משלוש לולאות ולא ארבע, ואנחנו צריכים להעביר את החוט בכיוון ההפוך לזה המקורי.

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

אם אתם רוצים לתרגל קצת "ריצה יבשה" (או שאתם סתם מזוכיסטים), אתם יכולים לנסות להריץ את האלגוריתם שלנו על דף ניר, כפי שעשינו עבור לולאה וצ'ופצ'יק. בכל שלב כתבו מאיזו נקודה לאיזו נקודה אתם מעוניינים להעביר את החוט. בשלב הבא, כתבו את צמד הנקודות הבא שצריך לעבור דרכן בהיסט של רמה אחת פנימה וחוזר חלילה – עד שתגיעו לשתי נקודות שהמעבר בינהן הוא טריוויאלי (E.1 ו E.2). כשהשלמתם מעבר בין שתי נקודות, בדקו מה צמד הנקודות הבא שצריך להעביר דרכו את החוט כדי להשלים את הרמה הקודמת.

הערה – יש עוד דרך לחשוב על זה, שיכולה להיות יותר אינטואיטיבית: אפשר להפוך את החוט כך שיקיף את המקל שמחזיק את לולאה B, ובכל שלב לנסות להעביר אותו מקל אחד שמאלה. כעקרון, שיטת הפתרון זהה (מהיכן להיכן רוצים לעבור, מה מפריע בדרך וחוזר חלילה באמצעות רקורסיה), אבל יכול להיות שהרציונל מאחורי התהליך יהיה ברור יותר לחלקכם כך.

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

-=-

[1] וכאן שאלה מעניינת – איך מפרמלים את הרעיון האינטואיטיבי ששתי צורות מורכבות הן לולאות שלובות ובונים אלגוריתם לגילוי צורות כאלה?
[2] סדרת צעדים
[3] הערה קטנה לקפדנים – למעשה, לולאה שתקוע בתוכה צ'ופצ'יק מייצגת שני שלבים ברקורסיה והבעיה הפשוטה ביותר היא צ'ופצ'יק בודד, אבל עזבו אתכם – אם לא שמתם לב, זה לא פוסט פורמלי במיוחד.

קטגוריות: מקצועי תגים: , ,

כנגד 4 תכניתנים

11/09/2010 6 תגובות

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

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

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

כשירות לצרכן, אני פורשת לפניכם את קטלוג התכנתים הגרועים הלוקה-בחסר* שלי, חינם אין כסף, ללא אותיות קטנות וללא תוספות**.

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

האדיש
האדיש בחר בקריירה בתחום המחשוב כי זו עבודה לגיטימית כמו כל עבודה, והשמועה אומרת ש"יש בזה כסף טוב", אז עד היום הוא מקווה למעוד במקרה על סטארט אפ ש"יעשה את המכה" ויגאול אותו מהגורל שהוא בחר לעצמו. הוא מבלה 9 שעות ביום בעיסוק שהוא לא ממש אוהב ולא ממש טוב בו, והוא יודע את זה, וכל שאיפתו היא לסיים את העבודה מהר ולעשות את הדבר היחיד שהוא באמת משתוקק אליו – לשבת מול הטלויזיה ולחלום על חיים של אנשים אחרים שקמים בבוקר בשביל משהו שהם באמת שמים עליו קצוץ.
האנשים האלה בדרך כלל ישייטו בשקט מתחת לרדאר של ההנהלה בתקווה למשוך עוד יום בו אף אחד לא ישים לב לבינוניות שלהם. אפשר לזהות אותם לפי ה check inים ל source control system שבהם נוספים גידולי קוד חיזריים שמטפלים בקוד שרת מה JavaScript של ה UI בלי שום קשר לכל דבר שמזכיר עיצוב הגיוני של מערכת, מתודות שפותחות חיבורים ל DB בלולאה ושולפות שורה את כל פעם ואבסטרקציות לבדיקת הערך של משתנה בולאני . והם בין הגורמים שאחראים לריקבון האיטי והבלתי נמנע של כל מערכת שהם עובדים עליה.

הנלהב
הנלהב סיים זה עתה בהצטיינות תואר ראשון במדעי המחשב והוא ניגש במרץ לשנות את פני עולם התכנה למרות שהוא לא עבד על מערכת אמיתית מימיו. הוא מגיע לעבודה מלא כרימון ברעיונות חדשים ומבריקים שהוא שהוא שמע עליהם בשיעורי design patterns ומבני נתונים , וכעת הוא נחוש לממש linked list תחת כל מחלקה רעננה. בעיניו הבורקות כל מחלקת utilities קיקיונית לובשת צורה של היררכייה מורכבת עם שני ממשקים לפחות ו factory עשוי ניירוסטה, כרום וניקל נוצץ שמייצר את המופע הבודד שלה במערכת שהוא, כמובן, singleton. האנשים האלה אחראיים ל"סינדרום המערכת הראשונה": עיצוב יתר ברמת פירוט מיקרוסקופית של קטעי קוד שמוטב היה לו היו פשוטים וקוהרנטיים, תוך התעלמות מוחלטת מסוגיות עיצוביות רחבות במערכת והתעקשות קשת עורף לממש כלים קיימים וקטעי קוד שנכתבו בעבר שוב ושוב במו ידיהם.
הבנים הללו הם למעשה לא תכניתנים גרועים באופן חסר תקווה, ותחת יד מרסנת שתכווין את המרץ הבלתי נגמר שלהם לאפיקים מועילים, הם יכולים לפרוח.

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

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

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

** ללא דמי מנוי בכפוף לשימוש יומי בסכום של 99.99 שקלים לפחות ועד לתקרה של 100 שקלים ליום, ובעלות של 10 שקל לדקה עבור כל דקה נוספת לא כולל שימוש ביכולות חיפוש, ציטוט או קריאה בלילות ירח מלא.

פעלולי קוד

29/08/2010 5 תגובות

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

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


// Maximum of objects that it's REALLY RALLY IMPORTANT not to create too many of!!!1
private static final int HEAVY_OBJECTS_MAX = 100;

// Counter for my objects
private int reallyHeavyObjectsCount = 0;

...

// Make sure we are not creating too many objects
if (++reallyHeavyObjectsCount < HEAVY_OBJECT_MAX) {
	new ReallyHeavyObject();
}

לכאורה הדבר הזה אמור לעבוד.
אמור, אלא אם האפליקציה שלנו רצה מספיק זמן.
בכל פעם שהתנאי הזה רץ, הערך של המשתנה מתקדם. אחרי מספיק ריצות כאלה, הערך שלו יזלוג (נו, איך מתרגמים overflow?) והוא יתאתחל למספר קטן מאד, שכמובן יגרום לכך שבריצות הבאות ניצור כמות לא מבוטלת של האובייקטים הממש כבדים שממש, אבל ממש, בשום פנים ואופן אסור לנו ליצור יותר מידי מהם.
והבעיה עם תכנות כזה היא שמאד קשה להבין מה לא בסדר בקוד הזה ממבט ראשון. אלה באגים מגעילים, חמקמקים, באגים מהסוג שלא משתחזר ושלך תמצא מאיפה הם מגיעים במערכת.
אז ככה מפילים מערכת production שלמישהו נורא חשוב לשמור למעלה, עם 30K+ אובייקטים שלא אמורים להיות יותר ממספר זעום של מופעים שלהם במערכת. למעשה, ככה מפילים מערכת production שכל כך חשוב לשמור למעלה, עד שיש לה שרת גיבוי, אבל זה בסדר, ככה מפילים גם את שרת הגיבוי.

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

קטגוריות: מקצועי תגים: ,

לפעמים גם המראה החיצוני חשוב

18/06/2010 4 תגובות
התקופות שבהן נדרש ממני לעבוד הרבה עם קוד שכתבו אנשים אחרים הביאו אותי למסקנה שבתכנה, כמו במערכות יחסים, הרבה פעמים המראה החיצוני חשוב. וכמו שבבליינד דייט הרבה פעמים אפשר לדעת שהאדם שלפניך ואת לא בדיוק הולכים לחולל יחדיו אל עבר השקיעה כבר אחרי מבט אחד, כך אפשר, גם בלי להתעמק במה התכנית עושה, בהצצה חטופה ובלי לקרוא את הקוד, לדעת שדברים טובים כנראה שלא יצאו ממנה.
כבר אמרו את זה לפני , יאמרו את זה אחרי, אני מגישה לפניכם את רשימת התופעות שגרמו לי למרוט את שיערות ראשי ביאוש ולרוץ בתבניות מורכבות במשרד תוך שאני מחפשת את הקיר הקשיח ביותר להטיח בו את ראשי, את המקרים שהותירו אותי המומה, נסערת וחסרת מילים, את הקוד שהתשובה היחידה שלי על השאלה "למה כתבו אותו ככה" היא "כנראה שהם היו מבולבלים".
Spaghetti Madness
כמות גדולה של תנאים בקוד היא בדרך כלל אינדיקציה טובה למדי לכך שמבנה האפליקציה לא משקף בצורה טובה את מה שהיא אמורה לעשות. כתוצאה מכך הרבה לוגיקה שאמורה להשתקף בעיצוב של המערכת מתורגמת לתנאים על גבי תנאים, שיוצרים גביש מופלא של בלוקים אשר בדרך כלל חוסם את ה Execution Paths הקריטיים ביותר, והם תמיד הקריטיים ביותר, באפליקציה:
public void playWithDick(Pet dick) {
	if (dick.getSpecie() == Pet.DOG) {
		throwBall(dick);
	} else if (dick.getSpecie() == Pet.CAT) {
		waveString(dick);
	} else if (dick.getSpecie() == Pet.IGUANA) {
		// Leave Dick alone, it hates you anyway...
	}
}
אולי היה עדיף לבנות את הקוד בצורה כללית, ולתת לפולימורפיזם לעשות את העבודה?
public void playWithDick(Pet dick) {

	// Let dick decide what it likes to do...
	dick.play();
}
במקרים קיצוניים, שורה ארוכה של תנאים עשוייה ליצור שרשרת סבוכה של תלויות שעם הזמן הופכת לבלתי אפשרית לתחזוק:
public void myUnmaintainablePieceOfCode() {

	// A flag that indicates whatever
	int myFlag = 1;

	if (someCondition) {

		myFlag = 2;

		if (someOtherCondition) {

			myFlag = 3;
		}
	}

	// Lots of complex code

	if (myFlag == 2) {
		myFlag = 4;
	}

	// Some more complex code

	// What flag value did we get?
	if ((myFlag == 1) || (myFlag == 4)){

		// Do something based on flag value
	} else {

		// Do something else
	}
}
בין התנאים שורר איזון עדין שאין לערערו משל היו מגדל קלפים נידף, וכל נסיון לשנות, להוסיף או לשפר את המצב הקיים כמוהו כרוח פרצים המרעידה את אושיות מבנה הבלוקים הרעוע ומסכנת את מצב האפליקציה. מה שהופך את התופעה לנפלאה עוד יותר היא העובדה שגביש התנאים המופלא בדרך כלל הוא-הוא ליבה של המערכת, וכל נגיעה בו מרטיטה את לבבותיהם הרגישים של בעלי המניות של החברה.
מדי פעם נשמע הטיעון שתנאים הכרחיים כדי לטפל במקרה קצה, תוך התעלמות בוטה מכך שבקוד שנכתב כמו שצריך לא אמורה להיות כמות גדולה של מקרה קצה לטפל בהם. כלומר, כל מקרה שדורש טיפול אמור להיות מטופל במסגרת ה flow הרגיל של האפליקציה. (יישום יפה לרעיון שעיצוב נכון יכול לחסוך תנאים מיותרים אפשר למצוא, למשל, ב Null Object Design Pattern).
התאומים הסיאמיים (copy&paste)
מדי פעם אפשר לראות בקוד של מערכות גדולות "חברים מוכרים" – קטעי קוד שאנחנו נדרשים אליהם, שבאופן חשוד מעוררים בנו תחושת "דה זה וו" מסויימת, עד שמתברר לנו שראינו אותם בהזדמנויות שונות. באופן משעשע למדי, הסימפטומים של אותם תאומי קוד הם טעויות קונסיסטנטיות (שחוזרות על עצמן חזור והטרד במקומות שונים באפליקציה, בכל מקום בו הקוד הועתק), או התנהגות לא קונסיסטנטית (כאשר צריך לשנות הרבה מקטעי קוד שאחראים לאותה התנהגות, ושוכחים כמה). למשל, יצא לי לראות פעם באג ב Excel שגרם לכך שהתנהגות שהיתה אמורה להיות סימטרית – תנועה של הסמן ימינה ושמאלה – פעלה תמיד לכיוון אחד. טעות copy&paste קלאסית.
העתקת קוד כזאת בתוך אותו ה Class מעידה בדרך כלל על חלוקה לא נכונה למתודות, והרבה פעמים היא מצוותת לבעיית ifים כזו או אחרת.
מתקפת המתודות המשובטות
מקרה פרטי של הבעיה הוא קוד שחוזר על עצמו בין Classים שונים, לפעמים בשינוי קטן, או בין מתודות שונות של אותו הclass:
public class myCoolClass {

	public void methodThatDoesSomethig() {

		// Bla bla...
	}

	public void methodThatDoesTheSameThingWithATinyDifference() {

		// Bla bla…
		// Yet another bla!
	}
}
בעיה כזאת מעידה הרבה פעמים על מקום בו היינו יכולים להשתמש בצורה הרבה יותר אלגנטית בהורשה.
Obese Class/Method
ובכל אפליקציה רעועה מגיע הרגע שאתם פותחים את הקוד ומתחילים לגלול ולגלול ולגלול, וכמה אלפי שורות מתחת לנקודה שהתחלתם בה, אתם מגיעים לסוף המתודה או ה class שאתם מסתכלים עליו. הדף מכיל שורות על גבי שורות של קוד קריפטי, וניווט והתמצאות בתוכו דורש כלים מתוחכמים שאתם רק יכולים להודות על כך שהIDE שלכם מספק לכם (או לא, אם המעסיק שלכם קמצן). כל דרישה לתחזק את המפלצת סומרת את שיערות עורפכם ואתם מתכסים זיעה קרה, ונראה כאילו כל הפונקציונליות של האפליקציה, זו שהיתה וזו שתהיה, מגולמת במפלי הASCII שזורמים מול עיניכם.
זו היא ה Obese Class.
כל הצעה לשנות את החיה האימתנית מובילה לצווחות אימה מצד חברי הצוות והמנהלים, ובלילות אתם חולמים על היום בו תאזרו אומץ לשלוח את הקובץ אל סל המחזור ולצעוד בslow motion אל עבר השקיעה.
קורבנות אופנה
ומדי פעם אני נתקלת גם בקטעי קוד שנראים דווקא כאילו מישהו כן חשב עליהם. חשב הרבה. חשב ועיצב וחשב ועיצב שוב, עד שמרוב עיצוב, עצי ירושה ו Design Patterns מתוחכמים, כבר אי אפשר להבין מה האפליקציה עושה. האנשים המקוריים שעיצבו את הקוד עזבו מזמן, ולחברי הצוות החדשים שעומדים חסרי אונים מול קונגלומרט התכנה המאיים לא נותר אלא להדביק את הפיתוחים החדשים עליהם הם עובדים אל תוך קטעי הקוד שהם כן מכירים, ובעשותם כך לשבור את העיצוב המקורי ולייצר חוליי תכנה חדשים.
היפה הוא שהרבה פעמים העיצוב המופרע מיותר לחלוטין – בעצי הירושה העצומים רק ענף אחד, ואותן המטרות היו יכולות להיות מושגות באמצעות עיצוב פשוט וברור בהרבה.
קטגוריות: מקצועי תגים: ,
Follow

Get every new post delivered to your Inbox.