יום חמישי, 22 באוגוסט 2013

ארכיטקטורה: חלוקת המערכת למודולים

תזכורת קצרה:

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

תהליך הגדרת הארכיטקטורה מורכב מ 4 פעולות עיקריות:
  1. חלוקת המערכת ליחידות קטנות יותר ("מודולים")
  2. ניהול תלויות
  3. הגדרת הפשטות (abstractions) והגדרת API
  4. תיעוד הארכיטקטורה
כמובן שהתהליך לא חייב להיות מנוהל בנוסח "מפל המים" (קרי - כל הגדרת הארכיטקטורה לפני כתיבת הקוד), אלא זה יכול להיות תהליך איטרטיבי שמתרחש תוך כדי כתיבת קוד.

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

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



חלקים של מערכת. כיצד נקבעה החלוקה?


מדוע לחלק מערכת למודולים?

חלוקת המערכת למודולים מסייעת להתמודד עם מספר בעיות (מתוך הפוסט "מדוע אנו זקוקים ל Software Design"):
  • בעיית ההתמצאות (במידה רבה)
  • בעיית ההקשר / הגבולות הברורים (במידה רבה)
  • בעיית מקביליות הפיתוח
  • בעיות הדומינו (במידה מסוימת)
  • בעיית ה Deployment (במידה מסוימת)
  • שימוש חוזר בקוד (במידה מסוימת)
קריטריון מרכזי לחלוקת המערכת למודולים היא יצרת "יחידות עבודה" ("Units of Work") עליהם יוכלו לעבוד מפתחים שונים במקביל (מה שמתחבר באופן ישיר לבעיית מקביליות הפיתוח). חלוקה למודולים בצורה הגיונית תסייע מאוד לבעיית ההתמצאות ובעיית ההקשר.

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

דויד לורג' פרנס תיאר זאת כך: "מתכנת חדש לא צריך ללמוד את כל המערכת בכדי לשנות שורת קוד אחת"


אז איך מתחילים?

בשלב הבסיסי ביותר ננסה לטפל בבעיות ההתמצאות ובעיית ההקשר / הגבולות הברורים. אנו רוצים שמתכנת שצריך לבצע שינוי ייגש לתרשים המערכת וממנו יבין את האזור (מודול) בו השינוי צריך לקרות. לשם כך אנו נחלק אחריויות כך ש:
  • לכל מודול תהיה אחריות יחידה
  • כל אחריות תהיה שייכת למודול אחד בלבד.
כלל זה בעצם הוא כלל ה Single Responsibility Principle (בקיצור: SRP), הכלל הראשון במערכת חוקי ה SOLID.

SOLID היא מערכת חוקים שהוגדרה ע"י רוברט ס. מרטין ("דוד בוב") לעיצוב תוכנה מונחה-אובייקטים.
במערכת כמעט מקבילה, מערכת ה GRASP של קרייג לרמן (מקור), העיקרון המקביל הוא High Cohesion (אחידות גבוהה).

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

ביטוי אחר מפורסם של כלל ה SRP ידוע כעקרון ה Separation of Concerns, כלל שאומר ש:
"System elements should have exclusivity and singularity of purpose", קרי - אותו הדבר, במלים גבוהות. זהו התיאור האהוב על ארכיטקטים רבים.

כלל ה SRP הוגדר ע"י דוד בוב בצורה הבאה: "A class should have one, and only one, reason to change". זו לא הדרך הכי פשוטה לבטא את הכלל, בהמשך נסביר את ההיגיון מאחורי הגדרה זו.

בצורה גרפית ניתן לתאר את הכלל בתרשים הבא (מעגל היא אחריות, "איש" הוא מחלקה):


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



מהי אחריות (Responsibility)?

קרייג לרמן הטיב לתאר[א] את מהות האחריות: אחריות היא מומחיות, ידע שרק המחלקה / המודול הספציפי יודע:
  • היכרות אינטימית עם מבנה נתונים מורכב
  • ביצוע חישוב מסוים (למשל חישוב ריבית או זמן נסיעה)
  • היכרות עם פורמט (עבור Parser) או פרוטוקול (למשל HTTP או פרוטוקול אפליקטיבי)
  • היכרות עם Flow (סדר פעולות ב high level) במערכת
שינוי יחיד בדרישות של המערכת מתמפה לעתים קרובות ל"מומחיות" יחידה של המערכת. אם המומחיות מוכמסת (encapsulated) במחלקה יחידה - אזי השינוי יהיה נקודתי.

לכל אחת מהאחריויות אנו רוצים שתהיה רק מחלקה אחת (או מודול אחד) במערכת בעל/ת הידע. ואז:
  • מפתח שירצה לבצע שינוי - יידע לאן ללכת ואיזה חלק מהמערכת ללמוד. "כשאנו מקבלים דרישה לשינוי במערכת - צריך להיות מקום יחיד בקוד בו עלינו לעשות את הקוד".
  • ישנה סבירות גבוהה יותר ששינוי במודול אחד לא ידרוש שינויים במקומות לא צפויים (בעיות הדומינו)
  • Deployment של מודול יחיד, ללא מודולים אחרים הוא סביר יותר
מומחיות זו צריכה להיות מוגנת ע"י הכמסה[ב] ו/או ממשקים מגבילים, כך שלאורך זמן המומחיות לא "תזלוג"[ג] למחלקות אחרות.


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

נחזור להגדרת ה SRP ע"י דוד בוב ("למודול / למחלקה צריכה להיות סיבה יחידה להשתנות"):
אם למודול יש סיבה יחידה להשתנות, כלומר יש לשנות אותו רק כאשר מגיעה דרישה ספציפית r, אזי הוא לא ישתנה הרבה. אם הוא הסיכוי שלו להשתנות נמוך - אז הסיכוי שלו להישבר / להיות צוואר בקבוק בין המפתחים - קטן גם כן.

יש לי 3 הערות על הגדרה זו:
  • זו לא הגדרה כ"כ ברורה (לדעתי)
  • הגישה של כתיבת מחלקות "שלא ייגעו בהן יותר" קצת השתנתה בשנים האחרונות. נדון בהרחבה בנקודה זו בסקירת "העיקרון הפתוח-סגור" (OCP).
  • נקודה שאני אוהב בהגדרה זו היא ההצמדה של האחריות - להבנה סובייקטיבית שלנו של המערכת ("מה צפויים להיות השינויים"). בכלל ב Design אין "מתמטיקה" שמובילה אותנו לפתרונות טובים. החלטות ה Design מבוססות על הבנת הבעיה / מערכת + הגיון בריא (בשאיפה).
    ישנם גם Guidelines (להלן העקרונות להנדסת תוכנה) המסייעים לנו להגיע להחלטות הנכונות.

שמירה על שני האלמנטים של עקרון ה SRP הוא תנאי מקדים למודולים שיוכלו לשמש במערכות אחרות (להלן Code Reusability).


חזרה לדוגמה לעיל:


אם נתבונן בחלוקה לתתי-המערכות של הדפדפן, נוכל לראות שיש כאן חלוקה ברורה למומחיות:
מודולים 1-3, 5 - התמחות בתחום מסוים ומוגדר היטב
מודול 4 הוא יותר אינטגרטיבי ומשתמש במודולים 1-3,5 לביצוע משימותיו.
מודול 6 מומחה בניהול Flows.
מודול 7 ומודול 4 מחלקים ביניהם את המסך: מודול 7 הוא המסגרת ומודול 4 הוא מה שבאמצע.

מה שמוביל אותנו ל...


עקרון ה Unit Of Work

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

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

שאלה נוספת: כיצד החליטו בוני הדפדפנים לחלק בין ה Shell ל Rendering Engine ל Graphics Module? הרי שלושתם "מומחים לציור על המסך"?

עקרון יחידות העבודה ("Units of Work" של פרנס, לא לבלבל עם תבנית העיצוב של פאוולר בשם זהה) מוסיף לפעולה של חלוקת המערכת למודולים הקשר חשוב: הצוות המבצע.
  • אם את פייסבוק היה כותב אדם אחד (צוקרברג?) - אזי מודול אחד הוא בסדר. אין התנגשויות.
  • אם את המערכת כותבים 2 צוותים של חמישה מתכנתים כל אחד - אזי מודול אחד הוא לא בסדר, מכיוון שתהיה התנגשות בעבודה.

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

כלומר: קודם יש לדאוג למקביליות הפיתוח ("Unit of Work") ורק לאחר מכן להתמצאות / קביעת גבולות ברורים. לרוב יש התאמה גבוהה (correlation) בין המשימות כך שלא תרגישו שאתם עובדים על דברים שונים.

נחזור לבעיית פייסבוק: מכיוון שיש לנו 2 צוותים וקשה להם לעבוד על מערכת כל-כך גדולה ללא חלוקה מסודרת - יש לחלק את המערכת למודולים. כאשר אנו מחלקים מערכת למודולים בחשיבה על צוות העבודה יש לקחת בחשבון גורמים כגון:
  • גודל ומורכבות המערכת - יותר גודל או מורכבות => יותר מודולים
  • רמת ואחידות הצוותים / המפתחים - ייתכן ונרצה לרכז מורכבויות או מומחיויות טכניות במודולים מסוימים
  • חלוקה לצוותים / מיקום גאוגרפי - כמה צוותים יש וכמה סביר שהתקשורת ביניהם תהיה טובה? כאשר התקשורת קשה (צוותים המופרדים ע"י מסדרון ארוך, אוקיינוס או סתם לא ביחסים טובים) כדאי לתכנן מודולים עצמיים שידרשו כמה שפחות תיאום בין הצוותים (קשור לנושא ניהול התלויות).
  • Legacy (שקשה לשנות) מול קוד חדש (שקל לשנות) - כדאי לקחת בחשבון ש Legacy Code [ד] קשה יותר לחלוקה, וכדאי להתגמש בנושא זה ולא לנסות לחלק אותו כמו שמחלקים קוד חדש.

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

זו מחשבה מקובלת, אבל בהחלט לא יעילה.

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

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

חזרה לדוגמת הדפדפנים:
סביר בהחלט שהדפדפנים חילצו את ה Shell ממנוע הרינדור בגלל תכונות ואיכויות שונות של המערכת: מנוע הרינדור הוא די hardcore (ביצועים, נכונות) בעוד ה Shell הוא יותר פשוט אבל מצריך שינויים תכופים. מודול ה Graphics דורש ידע ספציפי במערכת ההפעלה.
עצם כך שלא ניתן להתאים את קשת המשימות לפחות מ3 פרופילים שונים של מתכנתים, היא סיבה מצוינת לחלק את המערכת באזור המדובר לשלושה מודולים שונים - אחד לכל פרופיל מפתחים שזמין.



ארכיטקטורות אינטסנט

כדי להקל על המפתחים / ארכיטקטים, נוצרו מספר ״מתכונים מוכנים״ לחלוקת המערכת למודולים + ניהול התלויות.
חלוקה ע״פ שכבות - היא אולי המוכרת מכולן. ארכיטקטורות אינסטנט מוכרות אחרות הן MVC ו Pipes and Filters.



לחלוקה ע"פ שכבות יש מספר וריאציות:
  • n שכבות, כאשר כל שכבה יכולה לפנות רק לשכבה האחת שמתחתיה.
  • n שכבות, כאשר כל שכבה יכולה לפנות לכל שכבה שמתחתיה.
  • Shared Layers, בה יש שכבות "מאונכות" המשותפות לכמה שכבות.
  • 3 שכבות שנקבעו מראש: ממשק משתמש (UI), לוגיקה עסקית (Business Logic) ואחסון מידע (Persistence).
מכיוון שפוסט זה אינו עוסק בניהול תלויות, אדלג על ההבדלים בין 3 הווריאציות הראשונות ואתמקד רק בווריאציה האחרונה. מאחורי חלוקה זו ישנו רעיון דיי מתוחכם: חלוקת המערכת ע"פ טווח השרידות של חלקיה.

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

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

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

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


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

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

אנשים נוטים לייחס (בטעות) ל "מודל השכבות" או ל "MVC" (הפופולרית למדי - בימים אלו) סגולות לא-סבירות: "אם אין לנו במערכת MVC - כנראה שאנחנו לא בסדר".


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

כשהצטרפו מאוחר יותר עוד כמה צוותים לפרויקט הם היו מודאגים: "היכן ה MVC? אנחנו יודעים שחייבים MVC כדי לכתוב קוד ניתן-לתחזוקה!"

ניסינו להסביר שיש לנו חלוקה (ותלויות) מותאמים טוב יותר מ MVC [ה], שאנחנו מאוד בעד חלוקה מודולרית במערכת, ובעצם עשינו צעד אחד מעבר - אבל הדאגה בצד השני רק גברה. התוצאה הייתה מבלבלת: הצוותים ניסו להכניס MVC בצורות לא הגיוניות :"כל Service מחולק למודל ו Controller. ה View - ריק" או מיפוי לא נכון של הרכיבים ל MVC והסקת מסקנות לא נכונות לגבי השימוש בהם. במקרה קיצוני יצרו רכיב UI קטנטן שכלל MVC שלם ותקשר בהודעות עם עצמו.

עשו טובה: אל תגיעו למצב הזה.

הבינו ש MVC או כל "ארכיטקטורה מהקופסה" היא רק תבנית לתחילת עבודה: יש למלא אותה בתוכן ולהתאים אותה לבעיות הייחודיות של המערכת שלכם. אם המערכת שלכם לא עושה משהו ייחודי - פשוט רכשו את מוצר המדף המתאים ותנו אותו ללקוחות שלכם.
רצוי שתרשים-העל של הארכיטקטורה שלכם ירמז על דומיין הבעיה שאתם עוסקים בה ועל הפתרון שאתם מציעים. אם אתם מוצאים שם רק שמות של תבניות עיצוב (Plug-in, Factory, Facade וכו') - סיכוי טוב שהלכתם לאיבוד בארכיטקטורה. חשוב מאוד להבין את הבעיה העסקית, הייחוד שלה, את הבעיות שנגרמות מכך למפתחים של המערכת - וכיצד אתם מתמודדים איתן. זו המשמעות של ארכיטקטורה.


סיכום ביניים

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

בינתיים פורסם: פוסט על העיקרון הפתוח-סגור.

שיהיה בהצלחה!




---

[א] קרייג לרמן היטיב לתאר מדוד בוב כמה וכמה דברים, אולם בכל זאת SOLID היא המערכת הפופולרית בין השתיים.

[ב] עקרון זה, ה Information Hiding, הוא עיקרון שהוגדר ע"י פרנס במאמר פורץ הדרך שלו On the criteria to be used in decomposing systems into modules. העיקרון נשמע אולי טריוויאלי היום אבל בזמנו הייתה עליו לא מעט ביקורת ("למה להחביא, מה אנחנו - קומוניסטים?").

ספר מפורסם למדי, The Mythical Man Month, תקף את הרעיון בגרסתו הראשונה (1975) ובגרסה מעודכנת של הספר שיצאה לאחר 20 שנה, כתב פרדריק ברוקס פרק שמתחיל במשפט: "...Parnas was right, and I was wrong".

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

[ד] ישנה הגדרה שאומרת ש Legacy Code הוא כל קוד שאינו מכוסה היטב בבדיקות יחידה.

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



7 תגובות:

  1. היי

    רציתי להעיר באשר לנאמר לעליל שיש aubh מוחלט בין האכיטקטורת 3 tier לבין ה- MVC.


    אכיטקטורת ה - MVC זה ברמת השכבה של presentation ולא ברמת האפליקציה כולה

    השבמחק
  2. תגובה זו הוסרה על ידי המחבר.

    השבמחק
  3. שלום ליאור,

    למרות האיחור הרב מאז כתיבת שורות אלו (:

    הפוסט הזה חזק!

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

    הכלל החשוב יותר זה single responsibility הדו צדדי שהגדרת.
    סטיות מהכלל הזה נפוצות ויוצרות בעיות.

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

    תודה רבה!

    השבמחק
  4. היי ליאור,
    איפה הפוסט הבא בנושא? :)

    השבמחק
    תשובות
    1. תגובה זו הוסרה על ידי המחבר.

      מחק
    2. האא... הנה הוא פה: http://www.softwarearchiblog.com/2017/03/solid-ocp.html

      :)

      מחק