254. Convention over configuration

אחת הפרדיגמות העיצוב החשובות היא פרדיגמה בשם Convention over configuration.

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

למה הכוונה?

לדוגמה, נניח שיש לנו איזשהו Framework המאפשר לנו לשלוף מהDatabase אובייקטים משלנו. (שם קוד: DAL)

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

לכן בד”כ Framework כזה ידרוש מאיתנו מיפוי בין המחלקות והProperties שלנו לטבלאות או העמודות בDatabase:

המיפוי בדרך כלל יהיה באמצעות קובץ XML מעצבן, או בתוך הקוד באמצעות Metadata:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
[DbTable(Name = "PEOPLE")]
public class Person
{
[DbColumn(Name = "FIRST_NAME")]
public string Name
{
get;
set;
}
[DbColumn(Name ="LAST_NAME")]
public string LastName
{
get;
set;
}
[DbColumn(Name = "AGING")]
public int Age
{
get;
set;
}
}

במקרה זה המיפויים של השמות של המחלקות הProperties לא תואם לשמות בDatabase. אבל אם הוא היה תואם, הקוד שלנו היה צריך להראות כך:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
[DbTable(Name = "Person")]
public class Person
{
[DbColumn(Name = "Name")]
public string Name
{
get;
set;
}
[DbColumn(Name ="LastName")]
public string LastName
{
get;
set;
}
[DbColumn(Name = "Age")]
public int Age
{
get;
set;
}
}

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

מה שConvention over configuration אומר, זה את הדבר הבא:

הFramework שלנו יאפשר למפות את המחלקות/Properties לטבלאות/עמודות, אבל יאפשר גם הגדרה אוטומטית המבוססת קונבנציה:

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

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

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
[DbTable]
public class Person
{
[DbColumn]
public string Name
{
get;
set;
}
[DbColumn]
public string LastName
{
get;
set;
}
[DbColumn]
public int Age
{
get;
set;
}
}

אופציה נוספת יכולה להיות לא להכריח לשים כלום:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
public class Person
{
public string Name
{
get;
set;
}
public string LastName
{
get;
set;
}
public int Age
{
get;
set;
}
}

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

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

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
[DbTable(Name = "PEOPLE")]
public class Person
{
public string Name
{
get;
set;
}
[DbColumn(Name = "LAST_NAME")]
public string LastName
{
get;
set;
}
public int Age
{
get;
set;
}
}

אבל אין חובה לעשות זאת אם השמות זהים!

למה זה טוב?

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

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

המשך יום טוב עם קונבנציה טובה!

שתף