הקדמה
אין עיצוב ארכיטקטורי או עיצוב קוד הפותר כל בעיה.
כל פתרון תקף לבעיה ספציפית.
אבל, מתכנתים הם בדרך כלל אנשים חכמים והם גילו שפתרון יכול להוות פתרון, עם שינוי, לבעיה אחרת.
אז כעת פתרון אחד פותר 2 בעיות, ועל מנת שהוא ייעבוד הפתרון הזה צריך להיות כללי יותר.
איך לעצב קוד כללי - קוד גנרי
- כתבו קוד שמקבל 2 מספרים ומחבר בינהם ומחזיר את התוצאה.
- כתבו קוד שיודע לבצע חיסור
לפני שאתם ממשיכים הלאה אני מזמין אתכם לנסות בעצמכם את התרגיל.
הסעיף הראשון הוא פשוט:
1 | int Sum(int a, int b) |
בסעיף השני עלינו “להרחיב” את האופקים של הקוד ולתת מענה גם לפעולות אחרות.
אבל…
כעת נחשוב “רגע, אם אנחנו צריכים פעולת חיסור מה הלאה? כפל? חילוק?
בשלב הזה נתחיל לחשוב במושגים “כלליים” ולהתאים פתרון שיכול לעזור לנו גם בהמשך:
1 |
|
ואם נצטרך פעולה נוספת בקלי קלות נוסיף:
1 | template<class NumType> |
ואם נצטרך פרמטרים רבים ולא רק 2, ניתן אפילו להרחיב את זה יותר.
זה קוד C++
אז לא חייב להבין בדיוק מה עשיתי כאן,
בסופו של דבר זה נותן לנו יכולת להעביר יותר מפרמטר בודד לפנוקציה:
1 |
|
עכשיו נוכל לשבת בשקט כי כתבנו קוד שמעוצב היטב!
לא!
הקוד הזה בעצם “כללי מדי”.
Over-design - עיצוב יתר
נכיר כמה עקרונות בסיסיים איך נוכל לפשט את חיי הקוד שלנו:
KISS
- Keep it simple stupidYAGNI
- You ain’t gonna need it- אבסטרקצית יתר
- שימוש בתבניות עיצוב
- מסדי נתונים ושמירת נתונים
Keep it simple stupid - עקרון הפשטות
הפשטות היא תכונה המאפשרת לנו ליצור אינטרקציות בסיסיות מבלי להכליל את הפתרון.
בדוגמא הקודמת, כדי ליצור פשטות נוכל להמיר את הפתרון הכללי למשפט תנאי רגיל:
1 |
|
Ya aint gonna need it - עקרון מגדת העתידות
1 |
|
מהן 2 הבעיות הטמונות לנו בקוד הזה?
- הפונקציה
Multiply
לא בשימוש. - הפונקציה
Divide
בהערה עם הערות נוספות לתיקון.
בקיצור - אפשר למחוק את 2 הפונקציות האלו…
אבסטרקציית יתר
אבסטרקציה עוזרת להוריד תלותיות בין 2 רכיבים ובכך ליצור אינטרקציה עקיפה.
המטרה של אבסטרקציה היא לאפשר לשנות את הקוד מבלי לשנות את האינטרקציה בין 2 רכיבים:
1 |
|
ElectricalProduct
מבצע את החישוב.
אך העיצוב נבחר כדי למסך את השימוש ב-ElectricalProduct
.
שימוש כזה נעשה באופן עקבי ב-Domain driven design
הוא בעיצובים שבוחרים למסך כמה שיותר אובייקטים.
במידה ו-ElctricalProduct
היה פרטי ולא היה ניתן להשתמש בו מחוץ לקוד שלנו, אז היינו צריכים לבצע אבסטרקציה נוספת כדי לאפשר גישה.
לעיתים אין צורך באסטרקציה זו,
תנסו לוותר על ה-Adapter
, Factory
, Manager
וכדו’…
תבניות עיצוב
תבניות עיצוב אלו פתרונות כלליים שיצאו מתוך הפשטה של פתרונות ספציפיים יותר.
למשל ה-Strategy
הוא פתרון יעיל להחלפת לוגיקה בזמן ריצה:
1 | interface IStrategy |
לעיתים נוכל להחליף אבסטרקציה כזו בקונפיגורציה עם מימוש כללי יותר.
ואת העקרון הזה ניתן לפשט לעקרון שונה -
הכלה עדיפה מהורשה
לעיתים הורשה יכולה להוביל לקוד מסורבל יותר.
ומכיוון שהרבה תבניות עיצוב משתמשות בהורשה כפתרון - זה מוביל אותנו לקוד מסובך יותר ככל שאנחנו מכניסים עוד תבניות עיצוב לפתרון שלנו.
ולפי העקרון שהזכרתי איך ניתן לפתור את זה?
- לא להכניס תבניות עיצוב לא מתואמות.
כל תבנית עיצוב צריכה להיות מותאמת לפתרון הספציפי.
בלי להתאים אותו התבנית עיצוב תהיה “מגושמת”. - הכלה במקום הורשה.
דוגמא קלאסית תהיה הכלה של רשימות:
1 | class MyObjectList |
מעיין מחלקה שמממשת רשימה, במקום זה ניתן להחזיק אובייקט רשימה קיים ועליו לבנות את הקוד:
1 | class Calculator |
שימוש בתבנית עיצוב בודדת, והעדפת הכלה במקום הורשה תפשט לכם את הקוד.
מסדי נתונים
כמעט כל ארכיטקטורה מכילה מסדי נתונים.
מסד נתונים מבטיח לנו גישה מהירה ובטוחה לנתונים האמורים להישמר לטווח ארוך,
רוב מסדי הנתונים נותנים גם יכולות מעבר לשמירת מידע:
- טרנזקציוניות
- שמירה ארוכת טווח וקצרת טווח
- תשאול המסד עבור נתון מסוים - או אף שפה לשאילתות
- גיבויים
כל מנהל יגיד לכם “מה ברור שמסד, איפה עוד נשמור את הנתונים?”.
הוא חלקית צודק - עדיף להשתמש במסד נתונים קיים מאשר להמציא את הגלגל מחדש.
הבעיתיות מתחילה כאשר המסד נתונים הוא הראשון שנבחר,
כי אז כל העיצוב הוא סביב המסד נתונים.
זה במיוחד לא טוב כאשר המסד נתונים בנוי מטבלאות:
ניתן לראות תבניות רבות בקוד המרוכז במסד נתונים:
- קוד שקשור לשאילתות נדחף לתוך קוד הלוגיקה
1 | MyRow GetData(string nameOfEmployee) |
תחושה שגויה של “חלוקה” אבל ה-dbLayer
לא מהווה פה אבסטרקציה מספיק חזקה.
- אף מידע לא נשמר - כולו נלקח משכבת המסד
1 | void DoCalculation(IEnumerable<string> employees) |
- קשה לכתוב טסטים כי יש תלות גדולה מדי במסד נתונים
1 | void UntestableMethod() |
דיאגרמה נכונה לשכבות בלתי תלויות
ארכיטקטורת שכבות עובדת בתור עוגה יותר טוב מאשר בתור פיצה.
כי אם תבנו את זה כמו פיצה - לא ניתן להסיר את שכבת הרוטב והגבינה מבלי לגרוע מהפיצה.
במקום לדבר בשפת מסדי נתונים אנחנו לוקחים מהם את הכוח בעיצוב ומשאירים אותו אצלינו.
ובכך מעלים את האפשרות ל:
- כתיבת טסטים יעילה
- חוסר תלותיות במוצר ספציפי
- שימוש מחדש של קוד לוגיקה
- הורדת תלויות רחבה יותר בין שכבת ה-
UI
לשכבת הנתונים.
5 עקרונות אלו יסייעו לכם לשמור על עיצוב נקי יותר:
1.
Keep it simple stupid
2.
Ya aint gonna need it
3.
שמרו על מספר נמוך של אבסטרקציות
4.
שימוש בתבנית עיצוב בודדת, והעדפת הכלה במקום הורשה תפשט לכם את הקוד.
5.
קודם עצבו את הקוד ואחר כך בחרו את מסד הנתונים - עקרון העוגה.
תודה על הקריאה!