כאשר רוצים לכתוב תוכנה עוד לפני שאנחנו מתחילים לקודד, נצטרך קודם כל לתכנן את הפתרון ולעצב את התוכנה שלנו (Software Design).
תמיד כשאנו מפתחים תוכנה מסוימת, אנו נתקלים בדברים שחוזרים על עצמם ובד"כ כאשר אנו נתקלים בבעיות, ישנם כבר פתרונות מוכנים, את הפתרונות הללו אנו יכולים לארגן כ"תבניות" לפתרונות.
במילים אחרות: תבניות העיצוב (Design Pattern) הן בעצם פתרונות כלליות לבעיות שכיחות בבניית תוכנה.
חשוב לשים לב, תבניות אלו הן לא הקוד הסופי, לא המוצר המוגמר ולא איזה אלגוריתם שכותבים בפועל. הן בסה"כ רעיונות מובנים לפתרונות שעשויים להיות שימושים להרבה מצבים.
בואו נדבר על כמה סוגים של Design Patterns נפוצים תוך כדי שימוש בהגדרות ודוגמאות (ניקח את Chuck Norris האגדי בכדי שיעזור לנו להמחיש את הדוגמאות בעולם האמיתי אליו כל אחד ואחת יוכל להתחבר בקלות):
Factory Pattern
הגדרה: תבנית שמייצרים ממנה אובייקט מסוים בלי לחשוף את הלוגיקה ומה שמתרחש מאחורי הקלעים לגבי אותו אובייקט.
תמונה להמחשה:
דוגמא מהחיים: צ'ק נוריס רוצה לרכוש מכונית. הוא פונה לסוכן מכוניות שמציע לו דגמים שונים של רכבים ונותן לו איזה חוזה עם "אותיות קטנות" שהוא צריך לחתום עליו. הסוכן הוא זה שמטפל בכל מה שקשור לניירת, הוא זה שבעצם מטפל עם כל התהליכים מול משרד הרישוי והמכס כך שצ'ק לא צריך להתעסק עם הבירוקרטיה כלל, הוא לא יודע ולא אכפת לו מכל התהליכים האלה שמתבצעים מאחורי הקלעים. מה שמעניין אותו הוא בחירת הרכב.
דוגמא באוטומציה: באוטומציה יש לנו מקרה קלאסי אותו כולם מכירים בו אנו נרצה לכתוב מקרה בדיקה, וזה לא משנה באיזה framework הוא נכתב (TestNG/ Nunit / Mocha / Pytest), בבואנו לכתוב עם Selenium אנו נפנה לWebDriver שהוא, בין היתר, אחראי על החיבור התכנותי מול הדפדפנים השונים, איך החיבור הזה מתבצע? זה לא באמת משנה לנו העיקר שיש חיבור כזה.
Strategy Pattern
הגדרה: תבנית שמגדירה התנהגות או אלגוריתם כדי ל"כמס" (להסתיר) לוגיקה מסוימת מאחורי הקלעים.
תמונה להמחשה:
דוגמא מהחיים: צ'ק נוריס חיי באושר עם הרכב החדש שלו, עוברת שנה, עוברות שנתיים, עובר זמן רב עד שבשלב מסויים צ'ק רוצה להחליף את המנוע של הרכב, צ'ק מגיע למוסך ופונה למכונאי הרכב בבקשה שיחליף את המנוע הישן במנוע חדש. החלפה צריכה כמובן להתבצע ללא פגיעה בשאר חלקי הרכב. אבוי לאותו מכונאי במידה במסגרת עבודת ההחלפה הרדיו יפסיק לעבוד, המזגן לא יקרר או שמא מערכת הבלמים לא תתפקד...
דוגמא באוטומציה: אם יש לנו אובייקט שכבר יצרנו אותו ואנחנו רוצים לשנות חלק ממנו, השינוי אינו אמור להשפיע על שאר הלוגיקה של האובייקט.
כמו כן, במידה ויש לנו תשתית אוטומציה שהיא לא פחות ממדהימה, רק מה ? היא תומכת כעת רק על אפליקציות Desktop וכעת אנו מעוניינים שהיא תתמוך על אפצליקציות Web. במידה ונכתוב תשתית טובה עפ"י עקרונות ה-Strategy , נוכל לבצע את המעבר הזה ללא הרבה כאבי ראש (לא נחליף את מערכת הדוחות, לא נממש שוב קריאה מתוך קבצי אקסל וכו') למעשה נצטרך בסה"כ להחליף את ה-driver של האוטומציה.
Builder Pattern
הגדרה: ה-Builder Pattern (יש כאלו הקוראים לו Fluent Style) הינה תבנית לעיצוב ה-API של האובייקט שבנינו בצורה שהיא קריאה וברורה.
תמונה להמחשה:
דוגמא מהחיים: צ'ק נוריס רוצה הפעם לקנות ארון בגדים. הוא נוסע ל IKEA ובוחר לו ארון בגדים מהתצוגה, רק מה ? ב-IKEA כאמור הוא לא מקבל את הארון מורכב אלא קופסת קרטון סגורה אותה הוא צריך לפתוח בבית ולהרכיב בעצמו. הוא עושה זאת על ידי שימוש ב "הוראות הרכבה" שיכול להיות שלא מוסברים כמו שצריך. במצב כזה צ'ק יתעצבן ויחזיר את הארון לחנות, ואנחנו כמובן לא מעוניינים לעצבן את צ'ק נוריס, אז לשם כך IKEA צריכים להכין דף הוראות הרכבה שהוא מסודר ברור וקריא עבור כל אחד ואחת שיקנו את המוצרים שלהם.
דוגמא באוטומציה:
למעשה ישנה כבר דוגמא קיימת באוטומציה.
למי שמגיע מעולם ה-Selenium יש לנו מחלקה שנקראת Actions המאפשרת לנו "לבנות" רצף של פעולות אחת אחרי השנייה.
בקוד הבא מתוארת פעולה של ריחוף (Mouse Hover) מאלמנט אחד לשני, גם למי שלא מבין איך זה מתבצע על ידי הסתכלות על השם של הפעולה אפשר להבין מה מתרחש כאן.
אנו רואים כי אנו מרחפים מעל אלמנט 1 , אח"כ מעל אלמנט 2 ואח"כ לוחצים עליו.
Page Object Pattern
ה-Page Object Pattern הינה התבנית המוכרת ביותר בעולם האוטומציה, תבנית זו בעצם מאפשרת לנו לבצע הפרדה בין התרחישים העסקיים לתשתית שלנו באוטומציה כך שכאשר אנחנו בודקים אפליקציית קליינט מסוימת נרצה ל"מדל" (Model) אותה עםPage Objects, כלומר אם יש לנו אפליקציה עם הרבה מאוד דפים ואזורים אנו נרצה לייצר להם מחלקות שונות (Pages) ובפנים אנו נזהה את האלמנטים, בתוך המחלקה העסקית של Business שלנו אנחנו נקרא לאותם אלמנטים מהמחלקות השונות.
Singleton Pattern
הגדרה: תבנית שמוודאת שלמחלקה יהיה מופע אחד ויחיד ומספקת גישה גלובלית לאותו מופע.
תמונה להמחשה:
דוגמא מהחיים: צ'ק נוריס רוצה ללכת לשירותים ציבוריים. הוא נכנס לתא ושוכח לנעול את הדלת. סוכן הרכבים (מהדוגמא הקודמת) גם כן צריך ללכת ולהתפנות בשירותים, מכיוון שדלת תאו של צ'ק לא נעולה הוא יכול לפתוח את הדלת ולהיכנס פנימה לאותו תא של צ'ק נוריס, כאמור, אנחנו לא מעונינים לעצבן את צ'ק, על כן, נרצה להתקין מנעול על הדלת כך שברגע שיש מישהו שנמצא בתא, הוא יכול לנעול את הדלת ואף אחד אחר לא יוכל להיכנס.
דוגמא באוטומציה :בכתיבה לתוך Data Base או בכתיבה לתוך דוחות אנו נרצה שלאותו מקרה בדיקה תהיה גישה בלעדית וללא הפרעה, כך שאם למשל נריץ כמה מקרי בדיקה במקביל לא ייווצר מצב שבו כולם ירצו לכתוב לדוח באותו הזמן, במקרה הזה אנו נרצה "לנעול" את הגישה לאותו דוח כשאחד ממקרי הבדיקה כותב אליו, האחרים יכולים להמתין עד שהקודם יסיים את פעילותו.
Template Method Pattern
הגדרה: תבנית שמהווה שלד של אלגוריתם שמוגדרת בתור מחלקת אב או interface כך שהבנים של אותה מחלקה יכולים לבצע את הלוגיקה בצורה מימוש שונה אך עדיין מבצעים את אותו תהליך.
תמונה להמחשה:
דוגמא מהחיים: צ'ק נוריס מעוניין לרכוש כובע חדש. הוא בודק מחירים באתרים שונים למשל Amazon Ebay, Walmart, או אפילו רמי לוי. למעשה זה לא באמת משנה באיזה אתר קניות צ'ק נוריס יבחר, כי בכולם הוא יצטרך לבצע בדיוק את אותן הפעולות לרכישה: כניסה לאתר, חיפוש מוצר, הוספה לעגלה, בחירת אמצעי תשלום, תשלום, אישור תשלום ועוד.
יש לנו כאן פרוצדורה שחוזרת על עצמה בכל אתר קניות אז למה שלא פשוט נבנה איזה שלד כללי לכולם והמימוש ישתנה בהתאם לאתר?
דוגמא באוטומציה: למעשה בדוגמא שראינו מקודם, היא גם תופסת לכתיבה נכונה באוטומציה, ישנן חברות עם מוצרי template כאלו כמו אתרי קניות, הלקוחות קונים את ה-template ועליהם מלבישים את האתר, בין אם זה מכירה של מוצרי חשמל, רכבים, בגדים, משקאות וכו'. אנחנו באוטומציה כאמור ניצור מחלקה אבסטרקטית לפי תבנית העיצוב, נגדיר את ההתנהגות ונממש אותה לכל אתר בנפרד.
Proxy Pattern
הגדרה: תבנית שמספקת לנו סוג של Placeholder - מקום שבו אנחנו יכולים ליצור אובייקט מסוים ועם אפשרות להגביל את היכולות של אותו אובייקט.
תמונה להמחשה:
דוגמא מהחיים: צ'ק נוריס נמצא במשרד במקום עבודתו. הוא כעת רוצה לגלוש באינטרנט לאתר המשחקים האהוב עליו, רק שהוא לא מצליח לעשות את זה מכיוון שהאינטרנט בעבודה חוסם לו את הגישה לכך. זאת אומרת שמחלקת ה-IT מימשו איזושהי תבנית שיודעת לחסום אתרים מסויימים ואתרים אחרים – לא.
דוגמא באוטומציה: בנינו תשתית אוטומציה אותה אנו יכולים להריץ על יותר מסביבה אחת, למשל יש לנו סביבת ה-Production וסביבת הבדיקות, כאשר אנו נריץ את מקרה הבדיקה שלנו על סביבת ה Production , אנו נרצה לשלול גישה לכל מיני פיצ'רים בסביבה. את זה נוכל למשל לממש ע"י תבנית העיצוב: Proxy Pattern.
Execute Around Pattern
הגדרה: תבנית שבעצם מכילה בלוק של קוד אותו נרצה להריץ לפני ואחרי פעולה או פעולות מסוימות.
תמונה להמחשה:
דוגמא מהחיים: צ'ק נוריס מעוניין להיכנס לסניף ה-AM-PM הקרוב לביתו לקנות חלב וביצים. הדלתות של המכולת השכונתית יודעות להיפתח בכל פעם שצ'ק מתקרב אליהם ויודעות להיסגר אחרי שהוא עובר אותן וכמו כן רמקול בקרבת מקום מברך אותו לשלום ושואל לשלומו (לא באמת, אבל הבנתם את הרעיון.). צ'ק לא עושה דבר מלבד להיכנס לחנות. הפעולות הללו של פתיח וסגירת הדלתות מתבצעות באופן אוטומטי לפני ואחרי מעבר של בן אדם בחנות.
דוגמא באוטומציה: צ'ק רוצה לכתוב מקרי בדיקה ולא משנה באיזה Testing Framework הוא יבחר בכולם הוא יוכל להשתמש ב-Annotations / Fixtures של Before ו-After (השמות משתנים בין Framework אחד לשני) שמאפשרים להריץ דברים לפני ואחרי הרצה של כל מקרה בדיקה. בעצם יש לנו פעולות שמתבצעות מסביב באופן אוטומטי. דוגמא נוספת: כאשר אנחנו רוצים לעבור בין חלונות או iFrames, אנו נרצה לממש פקודה או פעולה שמבצעת את את המעבר הזה באופן אוטומטי.
Decorator Pattern
הגדרה: תבנית שמאפשרת ללקוחות או המשתמשים להוסיף עוד פונקציונליות או תכונות על אובייקטים שייצרנו מראש אבל בלי שאותו אובייקט ישנה את המבניות שלו.
תמונה להמחשה:
דוגמא מהחיים: צ'ק נוריס רוצה לאכול גלידה. הוא הלך לגלידריה הקרובה למקום מגוריו ורוכש כמה כדורים של גלידה, המוכר מביא לו את המנה ורק אחרי ליקוק אחד או שניים צ'ק נזכר כי הוא מעוניין גם בתוספות לכדורים (Topping): קצפת, שוקולד ועוד כמה דובדבנים. המוכר מעמיס לו על הגלידה מכל טוב המתיקות וזה כמובן מבלי לפגוע בכדורי הגלידה.
דוגמא באוטומציה: ב-Jenkins למשל (כמו בשרתים אחרים) אפשר לבצע השמה של תפקידים כך שאפשר להוסיף יכולות ואפשרויות למשתמשים שונים, למשל בצילום מהסך הבא אנו רואים כי אנו יכולים להוסיף הרשאות לJohn למשל לפרוייקט ה-Java וזה מבלי לפגוע בשאר המשתמשים וכן מבלי לשנות הרשאות אחרות לשאר הפרוייקטים אליהם הוא מחובר \ לא מחובר.
לסיכום
עבודה עם תבניות עיצוב מומלצת בכל פרויקט תוכנה וכמובן פרויקט הבדיקות האוטומטיות אינו שונה בכך.
ע"י כתיבה לפי תבניות אלו, הפרויקט שלנו יהיה הרבה יותר מובן, הרבה יותר נקי, עם פחות שורות קוד ובסופו של דבר ניתן יהיה יותר לסמוך עליו כשנריץ את מסות הבדיקות שלנו.
אני מקווה שנהניתם לקרוא את המאמר הזה, לשאלות נוספות אתם מוזמנים לפנות אליי ואענה לכם בשמחה.