ארבעה כללים של עיצוב תוכנה iOS פשוט יותר

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

לדברי קנט בק, עיצוב תוכנה טוב:

  • מבצע את כל הבדיקות
  • אינו מכיל שכפול
  • מביע את כוונת המתכנת
  • ממזער את מספר השיעורים והשיטות

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

מבצע את כל הבדיקות

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

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

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

עקרון אחריות יחידה (SRP)

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

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

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

הקוד ליישום זה נראה כרגע כך:

כיצד ניתן לבדוק קוד זה? מה עלינו לבדוק קודם? האם הנחת המחירים מחושבת נכון? כיצד ניתן ללעוג לאירועי התשלום כדי לבדוק את ההנחה?

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

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

אז ננסה פשוט לתרגם את אלה לקוד סוויפט.

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

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

בקר תצוגת התשלום שלנו יכול להיראות כך:

אנחנו יכולים לכתוב עכשיו בדיקות כמו

  • מבחן חישוב Fininal Price ללא קופון
  • מבחן חישוב FinalPriceWithCoupon
  • testCouponExists

ורבים אחרים! על ידי יצירת אובייקטים נפרדים כעת אנו נמנעים מכפילויות לא נחוצות ויצרנו גם קוד שקל לכתוב עבורו מבחנים.

הזרקת תלות

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

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

טכניקה טובה היא ליצור פרוטוקולים לאובייקטים שלנו ולספק יישום קונקרטי על ידי האובייקט האמיתי והעגום כמו הבאים:

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

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

הפיכת הקוד לבחינה יותר לא רק מבטלת את החשש שלנו לשבור אותו (מכיוון שנכתוב את המבחן שיגבה אותנו) אלא גם תורם לכתיבת קוד נקי יותר.

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

אינו מכיל שכפול

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

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

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

לצ'אט זה יהיו אותן צפיות כמו הצ'אט הנוכחי שלנו, אך יהיו לו כמה כללים שונים:

  1. בקשת הרשת לשליחת הודעות צ'אט תהיה שונה.

2. הודעות צ'אט צריכות להיות קצרות, לכל היותר 20 תווים להודעה.

3. אסור להתמיד בהודעות צ'אט במסד הנתונים המקומי שלנו.

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

יישום תמים יהיה כמו הבא:

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

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

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

כעת אנו יכולים לגרום לפרזנטור שלנו להתאים ל- IChatPresenter

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

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

אם אנו משתמשים בהזרקת תלות בבקר התצוגה שלנו, כעת נוכל להשתמש שוב באותו בקר תצוגה בשני מקרים שונים.

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

אקספרסיבי

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

אנו יכולים להציע קוד אקספרסיבי יותר על ידי שימוש בשמות טובים, שימוש ב- SRP ובבדיקת כתיבה.

שמות

דבר מספר אחד שהופך את הקוד לביטוי יותר - והוא שמות. חשוב לכתוב שמות ש:

  • חשוף כוונה
  • הימנע ממידע חסר
  • ניתנים לחיפוש בקלות

כשמדובר בשמות של שמות ותפקודים, הטריק הטוב הוא להשתמש בביטוי עצם או ביטוי עצם עבור שיעורים ופועלים משתמשים או שמות ביטוי פעלים לשיטות.

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

באמצעות SRP

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

מבחן כתיבה

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

צמצם את מספר השיעורים והשיטות

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

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

רעיון טוב ב- iOS הוא לקצץ את שיחות התצורה שאנו מבצעים בדרך כלל בפונקציות viewDidLoad או viewDidAppear.

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

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

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

ישנן דרכים רבות להפוך את בקרי ה- UIView לקטנים. העדפה שלי היא להשתמש בארכיטקטורה שיש בה הפרדה טובה יותר של חששות כמו VIPER או MVP, אבל זה לא אומר שאנחנו לא יכולים לשפר את זה טוב יותר גם ב- MVC תפוח.

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

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

  • במקום לכתוב ישירות קוד רשת צריך להיות NetworkManager כיתה שאחראית לשיחות רשת
  • במקום לתפעל נתונים בבקרי צפייה אנו יכולים פשוט ליצור DataManager כיתה שאחראית לכך.
  • במקום לשחק עם מחרוזות UserDefaults ב- UIViewController נוכל ליצור חזית מעל זה.

לסיכום

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

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

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

אם יש לך שאלות או הערות אל תהסס להשאיר פתק כאן או שלח לי דוא"ל לכתובת arlindaliu.dev@gmail.com.