├── 4_Comments(completed)
├── readme.md
├── img-4.1.png
├── img-4.2.png
├── README.md
└── 4_Comments.md
├── 1_Clean_Code(completed)
├── img-1-1.png
├── img-1-2.png
├── README.md
└── clean-code.md
├── 3_Functions(completed)
├── img_3.1.png
└── README.md
├── 5_Formatting(completed)
├── img-5.1.png
├── img-5.2.png
├── img-5.3.png
├── img-5.4.png
├── img-5.5.png
├── README.md
└── 5_Formatting.md
├── 0_introduction(completed)
├── img-0-1.png
├── README.md
└── introduction.md
├── 2_meaningful-names(completed)
├── img-2-1.png
├── README.md
└── meaningful-names.md
├── 8_Boundaries
└── 8_Boundaries.md
├── README.md
└── LICENSE
/4_Comments(completed)/readme.md:
--------------------------------------------------------------------------------
1 | # ...ترجمه این فصل در دست انجام است
2 |
--------------------------------------------------------------------------------
/4_Comments(completed)/img-4.1.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/milad-azami/clean-code-persian/HEAD/4_Comments(completed)/img-4.1.png
--------------------------------------------------------------------------------
/4_Comments(completed)/img-4.2.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/milad-azami/clean-code-persian/HEAD/4_Comments(completed)/img-4.2.png
--------------------------------------------------------------------------------
/1_Clean_Code(completed)/img-1-1.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/milad-azami/clean-code-persian/HEAD/1_Clean_Code(completed)/img-1-1.png
--------------------------------------------------------------------------------
/1_Clean_Code(completed)/img-1-2.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/milad-azami/clean-code-persian/HEAD/1_Clean_Code(completed)/img-1-2.png
--------------------------------------------------------------------------------
/3_Functions(completed)/img_3.1.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/milad-azami/clean-code-persian/HEAD/3_Functions(completed)/img_3.1.png
--------------------------------------------------------------------------------
/5_Formatting(completed)/img-5.1.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/milad-azami/clean-code-persian/HEAD/5_Formatting(completed)/img-5.1.png
--------------------------------------------------------------------------------
/5_Formatting(completed)/img-5.2.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/milad-azami/clean-code-persian/HEAD/5_Formatting(completed)/img-5.2.png
--------------------------------------------------------------------------------
/5_Formatting(completed)/img-5.3.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/milad-azami/clean-code-persian/HEAD/5_Formatting(completed)/img-5.3.png
--------------------------------------------------------------------------------
/5_Formatting(completed)/img-5.4.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/milad-azami/clean-code-persian/HEAD/5_Formatting(completed)/img-5.4.png
--------------------------------------------------------------------------------
/5_Formatting(completed)/img-5.5.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/milad-azami/clean-code-persian/HEAD/5_Formatting(completed)/img-5.5.png
--------------------------------------------------------------------------------
/0_introduction(completed)/img-0-1.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/milad-azami/clean-code-persian/HEAD/0_introduction(completed)/img-0-1.png
--------------------------------------------------------------------------------
/2_meaningful-names(completed)/img-2-1.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/milad-azami/clean-code-persian/HEAD/2_meaningful-names(completed)/img-2-1.png
--------------------------------------------------------------------------------
/1_Clean_Code(completed)/README.md:
--------------------------------------------------------------------------------
1 |
2 |
3 | # فصل اول: کد تمیز
4 | * [1_کد تمیز](clean-code.md#%D9%81%D8%B5%D9%84-%DB%8C%DA%A9---%DA%A9%D8%AF-%D8%AA%D9%85%DB%8C%D8%B2)
5 |
6 | * [کد همیشه وجود خواهد داشت](clean-code.md#%DA%A9%D8%AF-%D9%87%D9%85%DB%8C%D8%B4%D9%87-%D9%88%D8%AC%D9%88%D8%AF-%D8%AE%D9%88%D8%A7%D9%87%D8%AF-%D8%AF%D8%A7%D8%B4%D8%AA)
7 |
8 | * [کد بد](clean-code.md#%DA%A9%D8%AF-%D8%A8%D8%AF)
9 |
10 | * [هزینه کلی مالک یک شلختگی بودن](clean-code.md#%D9%87%D8%B2%DB%8C%D9%86%D9%87-%DA%A9%D9%84%DB%8C-%D9%85%D8%A7%D9%84%DA%A9-%DB%8C%DA%A9-%D8%B4%D9%84%D8%AE%D8%AA%DA%AF%DB%8C-%D8%A8%D9%88%D8%AF%D9%86)
11 |
12 | * [طراحی مجدد بزرگ در اسمان](clean-code.md#%D8%B7%D8%B1%D8%A7%D8%AD%DB%8C-%D9%85%D8%AC%D8%AF%D8%AF-%D8%A8%D8%B2%D8%B1%DA%AF-%D8%AF%D8%B1-%D8%A7%D8%B3%D9%85%D8%A7%D9%86)
13 |
14 | * [نگرش](clean-code.md#%D9%86%DA%AF%D8%B1%D8%B4)
15 |
16 | * [مسئله بغرنج اصلی](clean-code.md#%D9%85%D8%B3%D8%A6%D9%84%D9%87-%D8%A8%D8%BA%D8%B1%D9%86%D8%AC-%D8%A7%D8%B5%D9%84%DB%8C)
17 |
18 | * [هنر کد تمیز؟](clean-code.md#%D9%87%D9%86%D8%B1-%DA%A9%D8%AF-%D8%AA%D9%85%DB%8C%D8%B2)
19 |
20 | * [کد تمیز چیست؟](clean-code.md#%DA%A9%D8%AF-%D8%AA%D9%85%DB%8C%D8%B2-%DA%86%DB%8C%D8%B3%D8%AA)
21 |
22 | * [مکتب فکری!](clean-code.md#%D9%85%DA%A9%D8%AA%D8%A8-%D9%81%DA%A9%D8%B1%DB%8C)
23 |
24 |
25 |
--------------------------------------------------------------------------------
/5_Formatting(completed)/README.md:
--------------------------------------------------------------------------------
1 |
2 |
3 | # فرمت کردن
4 |
5 |
6 | * [۵ قالببندی](5_Formatting.md#%DB%B5-%D9%82%D8%A7%D9%84%D8%A8%D8%A8%D9%86%D8%AF%DB%8C)
7 | * [هدف قالببندی](5_Formatting.md#%D9%87%D8%AF%D9%81-%D9%82%D8%A7%D9%84%D8%A8%D8%A8%D9%86%D8%AF%DB%8C)
8 | * [قالب بندی عمودی](5_Formatting.md#%D9%82%D8%A7%D9%84%D8%A8-%D8%A8%D9%86%D8%AF%DB%8C-%D8%B9%D9%85%D9%88%D8%AF%DB%8C)
9 | * [استعاره روزنامه](5_Formatting.md#%D8%A7%D8%B3%D8%AA%D8%B9%D8%A7%D8%B1%D9%87-%D8%B1%D9%88%D8%B2%D9%86%D8%A7%D9%85%D9%87)
10 | * [گشودگی عمودی بین مفاهیم](5_Formatting.md#%DA%AF%D8%B4%D9%88%D8%AF%DA%AF%DB%8C-%D8%B9%D9%85%D9%88%D8%AF%DB%8C-%D8%A8%DB%8C%D9%86-%D9%85%D9%81%D8%A7%D9%87%DB%8C%D9%85)
11 | * [تراکم عمودی](5_Formatting.md#%D8%AA%D8%B1%D8%A7%DA%A9%D9%85-%D8%B9%D9%85%D9%88%D8%AF%DB%8C)
12 | * [فاصله عمودی](5_Formatting.md#%D9%81%D8%A7%D8%B5%D9%84%D9%87-%D8%B9%D9%85%D9%88%D8%AF%DB%8C)
13 | * [ترتیب عمودی](5_Formatting.md#%D8%AA%D8%B1%D8%AA%DB%8C%D8%A8-%D8%B9%D9%85%D9%88%D8%AF%DB%8C)
14 | * [قالببندی افقی](5_Formatting.md#%D9%82%D8%A7%D9%84%D8%A8%D8%A8%D9%86%D8%AF%DB%8C-%D8%A7%D9%81%D9%82%DB%8C)
15 | * [گشودگی و چگالی افقی](5_Formatting.md#%DA%AF%D8%B4%D9%88%D8%AF%DA%AF%DB%8C-%D9%88-%DA%86%DA%AF%D8%A7%D9%84%DB%8C-%D8%A7%D9%81%D9%82%DB%8C)
16 | * [ترازبندی افقی](5_Formatting.md#%D8%AA%D8%B1%D8%A7%D8%B2%D8%A8%D9%86%D8%AF%DB%8C-%D8%A7%D9%81%D9%82%DB%8C)
17 | * [تورفتگی](5_Formatting.md#%D8%AA%D9%88%D8%B1%D9%81%D8%AA%DA%AF%DB%8C)
18 | * [دامنه های ساختگی](5_Formatting.md#%D8%AF%D8%A7%D9%85%D9%86%D9%87-%D9%87%D8%A7%DB%8C-%D8%B3%D8%A7%D8%AE%D8%AA%DA%AF%DB%8C)
19 | * [قوانین تیم](5_Formatting.md#%D9%82%D9%88%D8%A7%D9%86%DB%8C%D9%86-%D8%AA%DB%8C%D9%85)
20 | * [قوانین قالب بندی عمو باب](5_Formatting.md#%D9%82%D9%88%D8%A7%D9%86%DB%8C%D9%86-%D9%82%D8%A7%D9%84%D8%A8-%D8%A8%D9%86%D8%AF%DB%8C-%D8%B9%D9%85%D9%88-%D8%A8%D8%A7%D8%A8)
21 |
22 |
23 |
--------------------------------------------------------------------------------
/4_Comments(completed)/README.md:
--------------------------------------------------------------------------------
1 |
2 |
3 | # کامنت ها ۴
4 |
5 |
6 | * [کامنت ها ۴](4_Comments.md#کامنتها-۴)
7 | * [کامنت ها برای کد بد نوشته نشده اند](4_Comments.md#کامنتها-برای-کد-بد-نوشته-نشده-اند)
8 | * [منظورتان را با کد برسانید](4_Comments.md#منظورتان-را-با-کد-برسانید)
9 | * [کامنت های خوب](4_Comments.md#کامنتهای-خوب)
10 | * [کامنت های قانونی](4_Comments.md#کامنتهای-قانونی)
11 | * [کامنت های آموزنده](4_Comments.md#کامنتهای-آموزنده)
12 | * [شرح نیت](4_Comments.md#شرح-نیت)
13 | * [شفاف سازی](4_Comments.md#شفاف-سازی)
14 | * [هشدار پیامدها](4_Comments.md#هشدار-پیامدها)
15 | * [TODO کامنت های](4_Comments.md#todo-کامنتهای)
16 | * [تقویت](4_Comments.md#تقویت)
17 | * [اسناد java در API های عمومی](4_Comments.md#%D8%A7%D8%B3%D9%86%D8%A7%D8%AF-java-%D8%AF%D8%B1-api-%D9%87%D8%A7%DB%8C-%D8%B9%D9%85%D9%88%D9%85%DB%8C)
18 | * [کامنت های بد](4_Comments.md#کامنتهای-بد)
19 | * [غرزدن](4_Comments.md#غرزدن)
20 | * [کامنت های اضافی](4_Comments.md#کامنتهای-اضافی)
21 | * [کامنتهای گمراه کننده](4_Comments.md#کامنتهای-گمراه-کننده)
22 | * [کامنت های مجاز](4_Comments.md#کامنتهای-مجاز)
23 | * [کامنت های گزارشی](4_Comments.md#کامنتهای-گزارشی)
24 | * [کامنت های شلوغ](4_Comments.md#کامنتهای-شلوغ)
25 | * [شلوغی هولناک](4_Comments.md#شلوغی-هولناک)
26 | * [زمانی که میتوانید از یک تابع یا متغییر استفاده کنید از کامنت ها استفاده نکنید](4_Comments.md#زمانی-که-میتوانید-از-یک-تابع-یا-متغییر-استفاده-کنید-از-کامنتها-استفاده-نکنید)
27 | * [نشانگرهای موقعیت](4_Comments.md#نشانگرهای-موقعیت)
28 | * [کامنت های بستن آکولاد](4_Comments.md#کامنتهای-بستن-آکولاد)
29 | * [خصیصهها و خطوط معرف نویسنده کد](4_Comments.md#خصیصهها-و-خطوط-معرف-نویسنده-کد)
30 | * [کامنت کردن کد](4_Comments.md#کامنت-کردن-کد)
31 | * [HTML کامنت های](4_Comments.md#html-کامنتهای)
32 | * [اطلاعات غیرمحلی](4_Comments.md#اطلاعات-غیرمحلی)
33 | * [اطلاعات بیش از اندازه](4_Comments.md#اطلاعات-بیش-از-اندازه)
34 | * [ارتباط نامشخص](4_Comments.md#ارتباط-نامشخص)
35 | * [عناوین تابع](4_Comments.md#عناوین-تابع)
36 | * [اسناد java در کد غیرعمومی](4_Comments.md#اسناد-java-در-کد-غیرعمومی)
37 | * [مثال](4_Comments.md#مثال)
38 |
39 |
--------------------------------------------------------------------------------
/2_meaningful-names(completed)/README.md:
--------------------------------------------------------------------------------
1 |
2 |
3 | # فصل دوم: اسامی با معنی
4 | * [مقدمه](meaningful-names.md#%D9%85%D9%82%D8%AF%D9%85%D9%87)
5 |
6 | * [استفاده از اسمهای بیان کننده منظور (Intention-Revealing Names)](meaningful-names.md#%D8%A7%D8%B3%D8%AA%D9%81%D8%A7%D8%AF%D9%87-%D8%A7%D8%B2-%D8%A7%D8%B3%D9%85%D9%87%D8%A7%DB%8C-%D8%A8%DB%8C%D8%A7%D9%86-%DA%A9%D9%86%D9%86%D8%AF%D9%87-%D9%85%D9%86%D8%B8%D9%88%D8%B1-intention-revealing-names)
7 |
8 | * [خودداری از دادن اطلاعات اشتباه](meaningful-names.md#%D8%AE%D9%88%D8%AF%D8%AF%D8%A7%D8%B1%DB%8C-%D8%A7%D8%B2-%D8%AF%D8%A7%D8%AF%D9%86-%D8%A7%D8%B7%D9%84%D8%A7%D8%B9%D8%A7%D8%AA-%D8%A7%D8%B4%D8%AA%D8%A8%D8%A7%D9%87)
9 |
10 | * [تفاوتهای با معنی ایجاد کنید](meaningful-names.md#%D8%AA%D9%81%D8%A7%D9%88%D8%AA%D9%87%D8%A7%DB%8C-%D8%A8%D8%A7-%D9%85%D8%B9%D9%86%DB%8C-%D8%A7%DB%8C%D8%AC%D8%A7%D8%AF-%DA%A9%D9%86%DB%8C%D8%AF)
11 |
12 | * [از اسمهای قابل تلفظ استفاده کنید](meaningful-names.md#%D8%A7%D8%B2-%D8%A7%D8%B3%D9%85%D9%87%D8%A7%DB%8C-%D9%82%D8%A7%D8%A8%D9%84-%D8%AA%D9%84%D9%81%D8%B8-%D8%A7%D8%B3%D8%AA%D9%81%D8%A7%D8%AF%D9%87-%DA%A9%D9%86%DB%8C%D8%AF)
13 |
14 | * [از اسامی قابل جستجو استفاده کنید](meaningful-names.md#%D8%A7%D8%B2-%D8%A7%D8%B3%D8%A7%D9%85%DB%8C-%D9%82%D8%A7%D8%A8%D9%84-%D8%AC%D8%B3%D8%AA%D8%AC%D9%88-%D8%A7%D8%B3%D8%AA%D9%81%D8%A7%D8%AF%D9%87-%DA%A9%D9%86%DB%8C%D8%AF)
15 |
16 | * [از رمزگذاری خودداری کنید](meaningful-names.md#%D8%A7%D8%B2-%D8%B1%D9%85%D8%B2%DA%AF%D8%B0%D8%A7%D8%B1%DB%8C-%D8%AE%D9%88%D8%AF%D8%AF%D8%A7%D8%B1%DB%8C-%DA%A9%D9%86%DB%8C%D8%AF)
17 |
18 | * [نمادگذاری مجارستانی](meaningful-names.md#%D9%86%D9%85%D8%A7%D8%AF%DA%AF%D8%B0%D8%A7%D8%B1%DB%8C-%D9%85%D8%AC%D8%A7%D8%B1%D8%B3%D8%AA%D8%A7%D9%86%DB%8C)
19 | * [پیشوندهای متغیر](meaningful-names.md#%D9%BE%DB%8C%D8%B4%D9%88%D9%86%D8%AF%D9%87%D8%A7%DB%8C-%D9%85%D8%AA%D8%BA%DB%8C%D8%B1)
20 |
21 | * [واسطها (interface) و پیادهسازیها](meaningful-names.md#%D9%88%D8%A7%D8%B3%D8%B7%D9%87%D8%A7-interface-%D9%88-%D9%BE%DB%8C%D8%A7%D8%AF%D9%87%D8%B3%D8%A7%D8%B2%DB%8C%D9%87%D8%A7)
22 |
23 | * [از نگاشت ذهنی خودداری کنید](meaningful-names.md#%D8%A7%D8%B2-%D9%86%DA%AF%D8%A7%D8%B4%D8%AA-%D8%B0%D9%87%D9%86%DB%8C-%D8%AE%D9%88%D8%AF%D8%AF%D8%A7%D8%B1%DB%8C-%DA%A9%D9%86%DB%8C%D8%AF)
24 |
25 | * [نام کلاسها](meaningful-names.md#%D9%86%D8%A7%D9%85-%DA%A9%D9%84%D8%A7%D8%B3%D9%87%D8%A7)
26 | * [نام متدها](meaningful-names.md#%D9%86%D8%A7%D9%85-%D9%85%D8%AA%D8%AF%D9%87%D8%A7)
27 |
28 | * [بانمک نباشید](meaningful-names.md#%D8%A8%D8%A7%D9%86%D9%85%DA%A9-%D9%86%D8%A8%D8%A7%D8%B4%DB%8C%D8%AF)
29 |
30 | * [برای هر مفهوم یک کلمه انتخاب کنید](meaningful-names.md#%D8%A8%D8%B1%D8%A7%DB%8C-%D9%87%D8%B1-%D9%85%D9%81%D9%87%D9%88%D9%85-%DB%8C%DA%A9-%DA%A9%D9%84%D9%85%D9%87-%D8%A7%D9%86%D8%AA%D8%AE%D8%A7%D8%A8-%DA%A9%D9%86%DB%8C%D8%AF)
31 |
32 | * [با ایهام ننویسید](meaningful-names.md#%D8%A8%D8%A7-%D8%A7%DB%8C%D9%87%D8%A7%D9%85-%D9%86%D9%86%D9%88%DB%8C%D8%B3%DB%8C%D8%AF)
33 |
34 | * [از دامنه واژگان مربوط به راه حل استفاده کنید](meaningful-names.md#%D8%A7%D8%B2-%D8%AF%D8%A7%D9%85%D9%86%D9%87-%D9%88%D8%A7%DA%98%DA%AF%D8%A7%D9%86-%D9%85%D8%B1%D8%A8%D9%88%D8%B7-%D8%A8%D9%87-%D8%B1%D8%A7%D9%87-%D8%AD%D9%84-%D8%A7%D8%B3%D8%AA%D9%81%D8%A7%D8%AF%D9%87-%DA%A9%D9%86%DB%8C%D8%AF)
35 |
36 | * [از دامنه واژگان صورت مسئله استفاده کنید](meaningful-names.md#%D8%A7%D8%B2-%D8%AF%D8%A7%D9%85%D9%86%D9%87-%D9%88%D8%A7%DA%98%DA%AF%D8%A7%D9%86-%D8%B5%D9%88%D8%B1%D8%AA-%D9%85%D8%B3%D8%A6%D9%84%D9%87-%D8%A7%D8%B3%D8%AA%D9%81%D8%A7%D8%AF%D9%87-%DA%A9%D9%86%DB%8C%D8%AF)
37 |
38 | * [ساختارهای با معنی اضافه کنید](meaningful-names.md#%D8%B3%D8%A7%D8%AE%D8%AA%D8%A7%D8%B1%D9%87%D8%A7%DB%8C-%D8%A8%D8%A7-%D9%85%D8%B9%D9%86%DB%8C-%D8%A7%D8%B6%D8%A7%D9%81%D9%87-%DA%A9%D9%86%DB%8C%D8%AF)
39 |
40 | * [سخن پایانی](meaningful-names.md#%D8%B3%D8%AE%D9%86-%D9%BE%D8%A7%DB%8C%D8%A7%D9%86%DB%8C)
41 |
42 |
43 |
44 |
--------------------------------------------------------------------------------
/3_Functions(completed)/README.md:
--------------------------------------------------------------------------------
1 |
2 |
3 | # فصل سوم: توابع
4 |
5 | * [توابع](3_Functions.md#%D8%AA%D9%88%D8%A7%D8%A8%D8%B9)
6 |
7 | * [کوچک بودن!](3_Functions.md#%DA%A9%D9%88%DA%86%DA%A9-%D8%A8%D9%88%D8%AF%D9%86)
8 | * [بلوک ها و تو رفتگی ها](3_Functions.md#%D8%A8%D9%84%D9%88%DA%A9-%D9%87%D8%A7-%D9%88-%D8%AA%D9%88-%D8%B1%D9%81%D8%AA%DA%AF%DB%8C-%D9%87%D8%A7)
9 | * [انجام دادن یک کار دیگر](3_Functions.md#%D8%A7%D9%86%D8%AC%D8%A7%D9%85-%D8%AF%D8%A7%D8%AF%D9%86-%DB%8C%DA%A9-%DA%A9%D8%A7%D8%B1-%D8%AF%DB%8C%DA%AF%D8%B1)
10 | * [بخشهای داخت توابع](3_Functions.md#%D8%A8%D8%AE%D8%B4%D9%87%D8%A7%DB%8C-%D8%AF%D8%A7%D8%AE%D8%AA-%D8%AA%D9%88%D8%A7%D8%A8%D8%B9)
11 | * [یک سطح انتزاع به ازای هر تابع](3_Functions.md#%DB%8C%DA%A9-%D8%B3%D8%B7%D8%AD-%D8%A7%D9%86%D8%AA%D8%B2%D8%A7%D8%B9-%D8%A8%D9%87-%D8%A7%D8%B2%D8%A7%DB%8C-%D9%87%D8%B1-%D8%AA%D8%A7%D8%A8%D8%B9)
12 | * [خواندن کد از بالا به پایین: قاعده گام به گام](3_Functions.md#%D8%AE%D9%88%D8%A7%D9%86%D8%AF%D9%86-%DA%A9%D8%AF-%D8%A7%D8%B2-%D8%A8%D8%A7%D9%84%D8%A7-%D8%A8%D9%87-%D9%BE%D8%A7%DB%8C%DB%8C%D9%86-%D9%82%D8%A7%D8%B9%D8%AF%D9%87-%DA%AF%D8%A7%D9%85-%D8%A8%D9%87-%DA%AF%D8%A7%D9%85)
13 | * [Switch Statements](3_Functions.md#switch-statements)
14 | * [استفاده از نام های توصیفی](3_Functions.md#%D8%A7%D8%B3%D8%AA%D9%81%D8%A7%D8%AF%D9%87-%D8%A7%D8%B2-%D9%86%D8%A7%D9%85%D9%87%D8%A7%DB%8C-%D8%AA%D9%88%D8%B5%DB%8C%D9%81%DB%8C)
15 | * [آرگومان های تابع](3_Functions.md#%D8%A2%D8%B1%DA%AF%D9%88%D9%85%D8%A7%D9%86-%D9%87%D8%A7%DB%8C-%D8%AA%D8%A7%D8%A8%D8%B9)
16 | * [فرم رایج Monadic](3_Functions.md#%D9%81%D8%B1%D9%85-%D8%B1%D8%A7%DB%8C%D8%AC-monadic)
17 | * [آرگومان های پرچم](3_Functions.md#%D8%A2%D8%B1%DA%AF%D9%88%D9%85%D8%A7%D9%86-%D9%87%D8%A7%DB%8C-%D9%BE%D8%B1%DA%86%D9%85)
18 | * [توابع Dyadic](3_Functions.md#%D8%AA%D9%88%D8%A7%D8%A8%D8%B9-dyadic)
19 | * [سه آرگومانی](3_Functions.md#%D8%B3%D9%87-%D8%A2%D8%B1%DA%AF%D9%88%D9%85%D8%A7%D9%86%DB%8C)
20 | * [آبجکت های آرگومان](3_Functions.md#%D8%A2%D8%A8%D8%AC%DA%A9%D8%AA-%D9%87%D8%A7%DB%8C-%D8%A2%D8%B1%DA%AF%D9%88%D9%85%D8%A7%D9%86)
21 | * [لیست های آرگومان](3_Functions.md#%D9%84%DB%8C%D8%B3%D8%AA-%D9%87%D8%A7%DB%8C-%D8%A2%D8%B1%DA%AF%D9%88%D9%85%D8%A7%D9%86)
22 | * [افعال و کیوردها](3_Functions.md#%D8%A7%D9%81%D8%B9%D8%A7%D9%84-%D9%88-%DA%A9%DB%8C%D9%88%D8%B1%D8%AF%D9%87%D8%A7)
23 | * [نداشتن هیچ عوارض جانبی](3_Functions.md#%D9%86%D8%AF%D8%A7%D8%B4%D8%AA%D9%86-%D9%87%DB%8C%DA%86-%D8%B9%D9%88%D8%A7%D8%B1%D8%B6-%D8%AC%D8%A7%D9%86%D8%A8%DB%8C)
24 | * [آرگومان های خروجی](3_Functions.md#%D8%A2%D8%B1%DA%AF%D9%88%D9%85%D8%A7%D9%86-%D9%87%D8%A7%DB%8C-%D8%AE%D8%B1%D9%88%D8%AC%DB%8C)
25 | * [جداسازی رایج Query](3_Functions.md#%D8%AC%D8%AF%D8%A7%D8%B3%D8%A7%D8%B2%DB%8C-%D8%B1%D8%A7%DB%8C%D8%AC-query)
26 | * [ترجیح Exception ها نسبت به برگرداندن کد خطا](3_Functions.md#%D8%AA%D8%B1%D8%AC%DB%8C%D8%AD-exception-%D9%87%D8%A7-%D9%86%D8%B3%D8%A8%D8%AA-%D8%A8%D9%87-%D8%A8%D8%B1%DA%AF%D8%B1%D8%AF%D8%A7%D9%86%D8%AF%D9%86-%DA%A9%D8%AF-%D8%AE%D8%B7%D8%A7)
27 | * [استخراج بلوک های Try/Catch](3_Functions.md#%D8%A7%D8%B3%D8%AA%D8%AE%D8%B1%D8%A7%D8%AC-%D8%A8%D9%84%D9%88%DA%A9-%D9%87%D8%A7%DB%8C-trycatch)
28 | * [مدیریت خطا یک چیز است](3_Functions.md#%D9%85%D8%AF%DB%8C%D8%B1%DB%8C%D8%AA-%D8%AE%D8%B7%D8%A7-%DB%8C%DA%A9-%DA%86%DB%8C%D8%B2-%D8%A7%D8%B3%D8%AA)
29 | * [آهنربای وابستگی Error.java](3_Functions.md#%D8%A2%D9%87%D9%86%D8%B1%D8%A8%D8%A7%DB%8C-%D9%88%D8%A7%D8%A8%D8%B3%D8%AA%DA%AF%DB%8C-errorjava)
30 | * [خود را تکرار نکنید](3_Functions.md#%D8%AE%D9%88%D8%AF-%D8%B1%D8%A7-%D8%AA%DA%A9%D8%B1%D8%A7%D8%B1-%D9%86%DA%A9%D9%86%DB%8C%D8%AF)
31 | * [برنامه نویسی ساخت یافته](3_Functions.md#%D8%A8%D8%B1%D9%86%D8%A7%D9%85%D9%87%D9%86%D9%88%DB%8C%D8%B3%DB%8C-%D8%B3%D8%A7%D8%AE%D8%AA-%DB%8C%D8%A7%D9%81%D8%AA%D9%87)
32 | * [چگونه می توانید توابعی مانند این را بنویسید؟](3_Functions.md#%DA%86%DA%AF%D9%88%D9%86%D9%87-%D9%85%DB%8C%D8%AA%D9%88%D8%A7%D9%86%DB%8C%D8%AF-%D8%AA%D9%88%D8%A7%D8%A8%D8%B9%DB%8C-%D9%85%D8%A7%D9%86%D9%86%D8%AF-%D8%A7%DB%8C%D9%86-%D8%B1%D8%A7-%D8%A8%D9%86%D9%88%DB%8C%D8%B3%DB%8C%D8%AF)
33 | * [نتیجه گیری](3_Functions.md#%D9%86%D8%AA%DB%8C%D8%AC%D9%87-%DA%AF%DB%8C%D8%B1%DB%8C)
34 |
35 |
36 |
--------------------------------------------------------------------------------
/0_introduction(completed)/README.md:
--------------------------------------------------------------------------------
1 |
2 |
3 | # مقدمه
4 |
5 |
6 |
7 |
8 | کدامیک از این تصاویر شما را در کدنویسی نشان میدهد؟ کدامیک شما را در تیم یا شرکت نشان میدهد؟ چرا ما در آن اتاق هستیم؟ ایا این فقط یک بررسی ساده کد است یا یک سری مشکلات را مدت کمی بعد از اجرا پیدا خواهیم کرد؟ ایا به خاطر وحشت از خراب شدن کدی که فکر میکردیم درست است ان را دیباگ میکنیم؟ایا مشتریها برنامه ما را ترک میکنند و مدیران ما را تنبیه میکنند؟ چطور مطمئن شویم در لحظات سخت، پشت درب درست قرار گرفته ایم؟ پاسخ این است: مهارت.
9 |
10 | یادگیری مهارت از دو بخش تشکیل شده است: دانش و کار. شما باید اصول، الگوها، تمرینها و شیوههای اکتشافی که یک هنرمند میداند را یاد بگیرید و آن دانش را با انگشتان، چشمها، دل و روده تان حس کنید و سخت کار کنید و تمرین کنید.
11 |
12 | من میتوانم به شما فیزیک راندن یک دوچرخه را یاد بدهم. در واقع، ریاضیات کلاسیک سر راست است. جاذبه، اصطکاک، تکانه زاویهای، مرکز جرم و غیره را میتوان در کمتر از یک صفحه پر از معادلات نشان داد. با توجه به فرمولها میتوانم به شما ثابت کنم که دوچرخه سواری عملی است و میتوانم همه دانشی که برای عملی کردن ان نیاز دارید را یاد بدهم. ولی هنوز در اولین دوچرخه سواری ات زمین خواهی خورد.
13 |
14 | کد نویسی تفاوتی ندارد.ما میتوانیم همه اصول کد تمیز را یادداشت کنیم و بعد به شما اطمینان دهیم که با انجام آنها موفق میشوید\(به عبارتی بگذاریم وقتی سوار دوچرخه شدید زمین بخورید\)، اما کدام معلم این کار را میکند؟
15 |
16 | نه،این راهی نیست که این کتاب میخواهد برود.
17 |
18 | یادگیری نوشتن کد تمیز، کار سختی است. به بیشتر از دانستن اصول و الگوها نیاز دارد.
19 |
20 | باید عرق بریزید. باید تمرین کنید و شکست هایتان را ببینید. باید کارهای دیگران و شکست هایشان را ببینید. باید ببینید چطور زمین میخورند و دوباره بلند میشوند.
21 |
22 | باید ببینید چطور از شکست هایشان عذاب میکشند و چه قیمتی برای تصمیمات بد شان پرداخته اند.
23 |
24 | آماده باشید که حین خواندن این کتاب سخت تمرین کنید. این یک کتاب تفریحی نیست که بتوانید انرا در هواپیما بخوانید و قبل از فرود انرا تمام کنید. این کتاب شما را به کار وادار میکند، پس سخت کار کنید. چه نوع کاری را انجام خواهید داد؟ باید کد بخوانید، مقدار زیادی کد؛ و شما را به چالش میکشد تا در مورد اینکه چه چیز آن کد خوب است و چه بدیهایی دارد فکر کنید. از ما خواسته میشود که بخشها \(modules\) را از هم جدا و دوباره به هم وصل کنیم. برای این کار زمان و تلاش صرف خواهد شد ولی ما فکر میکنیم که ارزش آنرا دارد. ما این کتاب را به سه بخش تقسیم کرده ایم.اولین فصل اصول، الگوها و تمرین نوشتن کد تمیز را در بر میگیرد. تعداد کمی کد در این فصل قرار دارد که خواندن آنها چالش برانگیز است. آنها شما را برای خواندن فصل دوم اماده خواهد کرد. اگر پس از خواندن فصل اول کتاب را کنار گذاشتید، موفق باشید!
25 |
26 | در بخش دوم کتاب کار سختتر است. این فصل از چند بخش با پیچیدگی افزایشی تشکیل شده است. هر بخش تمرین تمیزکردن کمی کد است؛تبدیل کردن کدی که مشکلاتی دارد به کدی که مشکلات کمتری دارد. جزئیات این فصل سخت است. باید دائم بین کتاب و یادداشت برداری جابه جا شوید. باید کدی که با ان کار میکنیم را آنالیز و درک کنید و برای هر تغییری که در کد ایجاد میکنیم استدلال کنید. کمی زمان بگذارید چون این کار باید چند روز زمان ببرد.
27 |
28 | بخش سوم کتاب نتیجه گیری نهایی است. این فصل شامل لیستی از اکتشافات و بوهایی \(منظور چیزهایی که کد را از حالت تمیز بودن خارج میکند که به بوی بد شهرت دارد\) است که هنگام یادگیری جمعآوری شده است. همینطور که پیش میرویم و کدها را تمیز میکنیم، برای هر کاری که انجام میدهیم تحت عنوان بو یا اکتشاف نکته برداری میکنیم. ما تلاش میکنیم واکنش خودمان را نسبت به کدی که خوانده ایم و تغییر داده ایم درک کنیم، و سخت تلاش کرده ایم که آنچه احساس کرده ایم، آنچه انجام داده ایم و دلیل ان را ضبط کنیم. نتیجه دانشی پایه است که به درک طرز تفکر ما هنگام نوشتن، خواندن و تمیز کردن کمک میکند.
29 |
30 | اگر شما بخشهای فصل دوم را به دقت نخوانید این دانش پایه ارزش محدودی خواهد داشت. در آن بخشهای آموزشی هر تغییری که ایجاد کرده ایم را به دقت و با ارجاع به اکتشافات به طور کامل تشریح کرده ایم. این ارجاعات در کروشه مثل این ظاهر میشوند:\[H22\]. این به شما اجازه میدهد متنی که در ان از اکتشافات استفاده شده را ببینید. این نه تنها خودش اکتشاف نیست بلکه بسیار ارزشمند است، این رابطه آن اکتشافات و تصمیمات پراکنده ای که حین تمیز کردن کد در بخشهای آموزشی گرفته ایم را مشخص میکند.
31 |
32 | برای کمک بیشتر در رابطه با این روابط ما مرجعی در پایان کتاب قرار داده ایم که شماره صفحه هر ارجاع را نمایش میدهد. میتوانید از آن برای دیدن مکانی که هر اکتشاف ظاهر شده استفاده کنید.
33 |
34 | اگر فصل اول و سوم را بخوانید و از بخشهای اموزشی صرف نظر کنید پس بهتر است یک کتاب تفریحی در باره نوشتن نرمافزار خوب بخوانید. اما اگر برای بخشهای اموزشی در فصل دوم وقت بگذارید، هر قدم کوچک را دنبال کنید، هر تصمیم لحظه ای، اگر خودتان را جای من قرار دهید، و خودتان را به همان مسیری که ما میرویم هدایت کنید، درک بیشتری از اصول و الگوها بدست خواهید اورد. آنها دیگر دانش تفریحی نخواهند بود. آنها به دل و روده، انگشتان و قلبتان راه پیدا کرده اند. آنها به بخشی از خودتان تبدیل خواهند شد همان طور که وقتی دوچرخه سواری یاد میگیرید به بخشی از وجودتان تبدیل میشود.
35 |
36 |
37 |
--------------------------------------------------------------------------------
/0_introduction(completed)/introduction.md:
--------------------------------------------------------------------------------
1 |
2 |
3 | # مقدمه
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 | کدامیک از این تصاویر شما را در کدنویسی نشان میدهد؟ کدامیک شما را در تیم یا شرکت نشان میدهد؟ چرا ما در آن اتاق هستیم؟ آیا این فقط یک بررسی ساده کد است یا یک سری مشکلات را مدت کمی بعد از اجرا پیدا خواهیم کرد؟ آیا به خاطر وحشت از خراب شدن کدی که فکر میکردیم درست است آن را دیباگ میکنیم؟ آیا مشتریها برنامه ما را ترک میکنند و مدیران، ما را تنبیه میکنند؟ چطور مطمئن شویم در لحظات سخت، پشت درب درست قرار گرفته ایم؟ پاسخ این است: مهارت.
14 |
15 | یادگیری مهارت از دو بخش تشکیل شده است: دانش و تمرین. شما باید اصول، الگوها، تمرینها و شیوههای اکتشافی که یک هنرمند میداند را یاد بگیرید و آن دانش را با انگشتان، چشمها، دل و رودهتان حس کنید و سخت کار کنید و تمرین کنید.
16 |
17 | من میتوانم به شما فیزیک راندن یک دوچرخه را یاد بدهم. در واقع، ریاضیات کلاسیک سر راست است. جاذبه، اصطکاک، تکانه زاویهای، مرکز جرم و غیره را میتوان در کمتر از یک صفحه پر از معادلات نشان داد. با توجه به فرمولها میتوانم به شما ثابت کنم که دوچرخه سواری عملی است و میتوانم همه دانشی که برای عملی کردن آن نیاز دارید را یاد بدهم. ولی هنوز در اولین دوچرخه سواریات زمین خواهی خورد. کد نویسی تفاوتی ندارد. ما میتوانیم همه اصول کد تمیز را یادداشت کنیم و بعد به شما اطمینان دهیم که با انجام آنها موفق میشوید\(به عبارتی بگذاریم وقتی سوار دوچرخه شدید زمین بخورید\)، اما کدام معلم این کار را میکند؟
18 |
19 | نه، این راهی نیست که این کتاب میخواهد برود. یادگیری نوشتن کد تمیز، کار سختی است. به بیشتر از دانستن اصول و الگوها نیاز دارد. باید عرق بریزید. باید تمرین کنید و شکستهایتان را ببینید. باید کارهای دیگران و شکست هایشان را ببینید. باید ببینید چطور زمین میخورند و دوباره بلند میشوند. باید ببینید چطور از شکستهایشان عذاب میکشند و چه قیمتی برای تصمیمات بدشان پرداختهاند. آماده باشید که حین خواندن این کتاب سخت تمرین کنید.
20 |
21 | این یک کتاب تفننی نیست که بتوانید آنرا در هواپیما بخوانید و قبل از فرود آنرا تمام کنید. این کتاب شما را به کار وادار میکند، پس سخت کار کنید. چه نوع کاری را انجام خواهید داد؟ باید کد بخوانید، مقدار زیادی کد؛ و شما را به چالش میکشد تا در مورد اینکه چه چیز آن کد خوب است و چه بدیهایی دارد فکر کنید. از ما خواسته میشود که بخشها (modules) را از هم جدا و دوباره به هم وصل کنیم. برای این کار زمان و تلاش صرف خواهد شد ولی ما فکر میکنیم که ارزش آنرا دارد.
22 |
23 | من این کتاب را به سه بخش تقسیم کردهام. اولین بخش اصول، الگوها و تمرین نوشتن کد تمیز را در بر میگیرد. تعداد کمی کد در این بخش قرار دارد که خواندن آنها چالش برانگیز است. آنها شما را برای خواندن بخش دوم آماده خواهد کرد. اگر پس از خواندن فصل اول کتاب را کنار گذاشتید، موفق باشید!
24 |
25 | در بخش دوم کتاب کار سختتر است. این فصل از چند بخش با پیچیدگی افزایشی تشکیل شده است. هر بخش، تمرین تمیز کردن کمی کد است؛ تبدیل کردن کدی که مشکلاتی دارد به کدی که مشکلات کمتری دارد. جزئیات این فصل سخت است. باید دائم بین کتاب و یادداشت برداری جابه جا شوید. باید کدی که با آن کار میکنیم را آنالیز و درک کنید و برای هر تغییری که در کد ایجاد میکنیم استدلال کنید. کمی زمان بگذارید چون این کار باید چند روز زمان ببرد.
26 |
27 | بخش سوم کتاب نتیجهگیری نهایی است. این بخش شامل لیستی از اکتشافات و بوهایی (منظور چیزهایی که کد را از حالت تمیز بودن خارج میکند که به بوی بد شهرت دارد) است که هنگام یادگیری جمعآوری شده است. همینطور که پیش میرویم و کدها را تمیز میکنیم، برای هر کاری که انجام میدهیم تحت عنوان بو یا اکتشاف، نکته برداری میکنیم. ما تلاش میکنیم واکنش خودمان را نسبت به کدی که خواندهایم و تغییر دادهایم درک کنیم، و سخت تلاش کردهایم که آنچه احساس کردهایم، آنچه انجام دادهایم و دلیل آن را ضبط کنیم. نتیجه دانشی پایه است که به درک طرز تفکر من هنگام نوشتن، خواندن و تمیز کردن کمک میکند. اگر شما بخشهای فصل دوم را به دقت نخوانید این دانش پایه ارزش محدودی خواهد داشت.
28 |
29 | در آن بخشهای آموزشی هر تغییری که ایجاد کردهایم را به دقت و با ارجاع به اکتشافات به طور کامل تشریح کرده ایم. این ارجاعات در کروشه مثل این ظاهر میشوند:[H22]. این به شما اجازه میدهد متنی که در آن از اکتشافات استفاده شده را ببینید. این نه تنها خودش اکتشاف نیست بلکه بسیار ارزشمند است، این رابطه آن اکتشافات و تصمیمات پراکندهای که حین تمیزکردن کد در بخشهای آموزشی گرفتهایم را مشخص میکند. برای کمک بیشتر در رابطه با این روابط، مرجعی در پایان کتاب قرار دادهایم که شماره صفحه هر ارجاع را نمایش میدهد. میتوانید از آن برای دیدن مکانی که هر اکتشاف ظاهر شده، استفاده کنید.
30 |
31 | اگر فصل اول و سوم را بخوانید و از فصل دوم صرف نظر کنید، بهتر است یک کتاب تفننی در باره نوشتن نرمافزار خوب بخوانید. اما اگر برای بخشهای آموزشی در فصل دوم وقت بگذارید، هر قدم کوچک را دنبال کنید، هر تصمیم لحظهای، اگر خودت را جای من قرار دهی، و خودت را به همان مسیری که ما میرویم هدایت کنی، درک بیشتری از اصول و الگوها بدست خواهی اورد. آنها دیگر دانش تفریحی نخواهند بود. آنها به دل و روده، انگشتان و قلبتان راه پیدا کردهاند. آنها به بخشی از خودتان تبدیل خواهند شد همان طور که وقتی دوچرخه سواری یاد میگیرید، به بخشی از وجودتان تبدیل میشود.
32 |
33 |
34 |
--------------------------------------------------------------------------------
/8_Boundaries/8_Boundaries.md:
--------------------------------------------------------------------------------
1 | 
2 |
3 | We seldom control all the software in our systems. Sometimes we buy third-party pack-
4 | ages or use open source. Other times we depend on teams in our own company to produce
5 | components or subsystems for us. Somehow we must cleanly integrate this foreign code with our own. In this chapter we look at practices and techniques to keep the boundaries of
6 | our software clean.
7 | # Using Third-Party Code
8 | There is a natural tension between the provider of an interface and the user of an interface.
9 | Providers of third-party packages and frameworks strive for broad applicability so they
10 | can work in many environments and appeal to a wide audience. Users, on the other hand,
11 | want an interface that is focused on their particular needs. This tension can cause problems
12 | at the boundaries of our systems.
13 | Let’s look at java.util.Map as an example. As you can see by examining Figure 8-1,
14 | Maps have a very broad interface with plenty of capabilities. Certainly this power and flexi-
15 | bility is useful, but it can also be a liability. For instance, our application might build up a
16 | Map and pass it around. Our intention might be that none of the recipients of our Map delete
17 | anything in the map. But right there at the top of the list is the clear() method. Any user of
18 | the Map has the power to clear it. Or maybe our design convention is that only particular
19 | types of objects can be stored in the Map, but Maps do not reliably constrain the types of
20 | objects placed within them. Any determined user can add items of any type to any Map.
21 |
22 |
23 | • clear() void – Map
24 | • containsKey(Object key) boolean – Map
25 | • containsValue(Object value) boolean – Map
26 | • entrySet() Set – Map
27 | • equals(Object o) boolean – Map
28 | • get(Object key) Object – Map
29 | • getClass() Class extends Object> – Object
30 | • hashCode() int – Map
31 | • isEmpty() boolean – Map
32 | • keySet() Set – Map
33 | • notify() void – Object
34 | • notifyAll() void – Object
35 | • put(Object key, Object value) Object – Map
36 | • putAll(Map t) void – Map
37 | • remove(Object key) Object – Map
38 | • size() int – Map
39 | • toString() String – Object
40 | • values() Collection – Map
41 | • wait() void – Object
42 | • wait(long timeout) void – Object
43 | • wait(long timeout, int nanos) void – Object
44 |
45 | If our application needs a Map of Sensors, you might find the sensors set up like this:
46 |
47 |
48 | ```java
49 | Map sensors = new HashMap();
50 | ```
51 |
52 | Then, when some other part of the code needs to access the sensor, you see this code:
53 |
54 | ```java
55 | Sensor s = (Sensor)sensors.get(sensorId );
56 | ```
57 |
58 | We don’t just see it once, but over and over again throughout the code. The client of this
59 | code carries the responsibility of getting an Object from the Map and casting it to the right
60 | type. This works, but it’s not clean code. Also, this code does not tell its story as well as it
61 | could. The readability of this code can be greatly improved by using generics, as shown
62 | below:
63 |
64 | ```java
65 | Map
sensors = new HashMap();
66 | ...
67 | Sensor s = sensors.get(sensorId );
68 | ```
69 |
70 | However, this doesn’t solve the problem that Map provides more capability than we
71 | need or want.
72 | Passing an instance of Map liberally around the system means that there will
73 | be a lot of places to fix if the interface to Map ever changes. You might think such a change
74 | to be unlikely, but remember that it changed when generics support was added in Java 5.
75 | Indeed, we’ve seen systems that are inhibited from using generics because of the sheer
76 | magnitude of changes needed to make up for the liberal use of Maps.
77 | A cleaner way to use Map might look like the following. No user of Sensors would care
78 | one bit if generics were used or not. That choice has become (and always should be) an
79 | implementation detail.
80 |
81 | ```java
82 | public class Sensors {
83 | private Map sensors = new HashMap();
84 | public Sensor getById(String id) {
85 | return (Sensor) sensors.get(id);
86 | }
87 | //snip
88 | }
89 | ```
90 |
91 | The interface at the boundary ( Map) is hidden. It is able to evolve with very little impact on
92 | the rest of the application. The use of generics is no longer a big issue because the casting
93 | and type management is handled inside the Sensors class.
94 | This interface is also tailored and constrained to meet the needs of the application. It
95 | results in code that is easier to understand and harder to misuse. The Sensors class can
96 | enforce design and business rules.
97 | We are not suggesting that every use of Map be encapsulated in this form. Rather, we
98 | are advising you not to pass Map s (or any other interface at a boundary) around your
99 | system. If you use a boundary interface like Map, keep it inside the class, or close family
100 | of classes, where it is used. Avoid returning it from, or accepting it as an argument to,
101 | public APIs.
102 |
103 | # Exploring and Learning Boundaries
104 | Third-party code helps us get more functionality delivered in less time. Where do we start
105 | when we want to utilize some third-party package? It’s not our job to test the third-party
106 | code, but it may be in our best interest to write tests for the third-party code we use.
107 | Suppose it is not clear how to use our third-party library. We might spend a day or two
108 | (or more) reading the documentation and deciding how we are going to use it. Then we
109 | might write our code to use the third-party code and see whether it does what we think. We
110 | would not be surprised to find ourselves bogged down in long debugging sessions trying to
111 | figure out whether the bugs we are experiencing are in our code or theirs.
112 | Learning the third-party code is hard. Integrating the third-party code is hard too.
113 | Doing both at the same time is doubly hard. What if we took a different approach? Instead
114 | of experimenting and trying out the new stuff in our production code, we could write some
115 | tests to explore our understanding of the third-party code. Jim Newkirk calls such tests
116 | learning tests.1
117 | In learning tests we call the third-party API, as we expect to use it in our application.
118 | We’re essentially doing controlled experiments that check our understanding of that API.
119 | The tests focus on what we want out of the API.
120 |
121 | # Learning log4j
122 | Let’s say we want to use the apache log4j package rather than our own custom-built log-
123 | ger. We download it and open the introductory documentation page. Without too much
124 | reading we write our first test case, expecting it to write “hello” to the console.
125 |
126 |
127 | ```java
128 | @Test
129 | public void testLogCreate() {
130 | Logger logger = Logger.getLogger("MyLogger");
131 | logger.info("hello");
132 | }
133 | ```
134 |
135 | When we run it, the logger produces an error that tells us we need something called an
136 | Appender. After a little more reading we find that there is a ConsoleAppender. So we create a
137 | ConsoleAppender and see whether we have unlocked the secrets of logging to the console.
138 |
139 | ```java
140 | @Test
141 | public void testLogAddAppender() {
142 | Logger logger = Logger.getLogger("MyLogger");
143 | ConsoleAppender appender = new ConsoleAppender();
144 | logger.addAppender(appender);
145 | logger.info("hello");
146 | }
147 | ```
148 |
149 | This time we find that the Appender has no output stream. Odd—it seems logical that it’d
150 | have one. After a little help from Google, we try the following:
151 |
152 | ```java
153 | @Test
154 | public void testLogAddAppender() {
155 | Logger logger = Logger.getLogger("MyLogger");
156 | logger.removeAllAppenders();
157 | logger.addAppender(new ConsoleAppender(
158 | new PatternLayout("%p %t %m%n"),
159 | ConsoleAppender.SYSTEM_OUT));
160 | logger.info("hello");
161 | }
162 | ```
163 |
164 | That worked; a log message that includes “hello” came out on the console! It seems odd
165 | that we have to tell the ConsoleAppender that it writes to the console.
166 | Interestingly enough, when we remove the ConsoleAppender.SystemOut argument, we
167 | see that “hello” is still printed. But when we take out the PatternLayout, it once again com-
168 | plains about the lack of an output stream. This is very strange behavior.
169 | Looking a little more carefully at the documentation, we see that the default
170 | ConsoleAppender constructor is “unconfigured,” which does not seem too obvious or useful.
171 | This feels like a bug, or at least an inconsistency, in log4j.
172 | A bit more googling, reading, and testing, and we eventually wind up with Listing 8-1.
173 | We’ve discovered a great deal about the way that log4j works, and we’ve encoded that
174 | knowledge into a set of simple unit tests.
175 |
176 |
177 | Listing 8-1
178 | LogTest.java
179 |
180 | ```java
181 | public class LogTest {
182 | private Logger logger;
183 | @Before
184 | public void initialize() {
185 | logger = Logger.getLogger("logger");
186 | logger.removeAllAppenders();
187 | Logger.getRootLogger().removeAllAppenders();
188 | }
189 | @Test
190 | public void basicLogger() {
191 | BasicConfigurator.configure();
192 | logger.info("basicLogger");
193 | }
194 | @Test
195 | public void addAppenderWithStream() {
196 | logger.addAppender(new ConsoleAppender(
197 | new PatternLayout("%p %t %m%n"),
198 | ConsoleAppender.SYSTEM_OUT));
199 | logger.info("addAppenderWithStream");
200 | }
201 | @Test
202 | public void addAppenderWithoutStream() {
203 | logger.addAppender(new ConsoleAppender(
204 | new PatternLayout("%p %t %m%n")));
205 | logger.info("addAppenderWithoutStream");
206 | }
207 | }
208 | ```
209 |
210 | Now we know how to get a simple console logger initialized, and we can encapsulate
211 | that knowledge into our own logger class so that the rest of our application is isolated from
212 | the log4j boundary interface.
213 |
214 | # Learning Tests Are Better Than Free
215 | The learning tests end up costing nothing. We had to learn the API anyway, and writing
216 | those tests was an easy and isolated way to get that knowledge. The learning tests were
217 | precise experiments that helped increase our understanding.
218 | Not only are learning tests free, they have a positive return on investment. When there
219 | are new releases of the third-party package, we run the learning tests to see whether there
220 | are behavioral differences.
221 | Learning tests verify that the third-party packages we are using work the way we
222 | expect them to. Once integrated, there are no guarantees that the third-party code will stay
223 | compatible with our needs. The original authors will have pressures to change their code to
224 | meet new needs of their own. They will fix bugs and add new capabilities. With each
225 | release comes new risk. If the third-party package changes in some way incompatible with
226 | our tests, we will find out right away.
227 | Whether you need the learning provided by the learning tests or not, a clean boundary
228 | should be supported by a set of outbound tests that exercise the interface the same way the
229 | production code does. Without these boundary tests to ease the migration, we might be
230 | tempted to stay with the old version longer than we should.
231 |
232 | # Using Code That Does Not Yet Exist
233 | There is another kind of boundary, one that separates the known from the unknown. There
234 | are often places in the code where our knowledge seems to drop off the edge. Sometimes
235 | what is on the other side of the boundary is unknowable (at least right now). Sometimes
236 | we choose to look no farther than the boundary.
237 | A number of years back I was part of a team developing software for a radio com-
238 | munications system. There was a subsystem, the “Transmitter,” that we knew little
239 | about, and the people responsible for the subsystem had not gotten to the point of defining
240 | their interface. We did not want to be blocked, so we started our work far away from the
241 | unknown part of the code.
242 | We had a pretty good idea of where our world ended and the new world began. As we
243 | worked, we sometimes bumped up against this boundary. Though mists and clouds of
244 | ignorance obscured our view beyond the boundary, our work made us aware of what we
245 | wanted the boundary interface to be. We wanted to tell the transmitter something like this:
246 | Key the transmitter on the provided frequency and emit an analog representation of the
247 | data coming from this stream.
248 | We had no idea how that would be done because the API had not been designed yet.
249 | So we decided to work out the details later.
250 | To keep from being blocked, we defined our own interface. We called it something
251 | catchy, like Transmitter. We gave it a method called transmit that took a frequency and a
252 | data stream. This was the interface we wished we had.
253 | One good thing about writing the interface we wish we had is that it’s under our
254 | control. This helps keep client code more readable and focused on what it is trying to
255 | accomplish.
256 | In Figure 8-2, you can see that we insulated the CommunicationsController classes
257 | from the transmitter API (which was out of our control and undefined). By using our own
258 | application specific interface, we kept our CommunicationsController code clean and
259 | expressive. Once the transmitter API was defined, we wrote the TransmitterAdapter to
260 | bridge the gap. The ADAPTER2 encapsulated the interaction with the API and provides a
261 | single place to change when the API evolves.
262 |
263 | 
264 |
265 | This design also gives us a very convenient seam3 in the code for testing. Using a
266 | suitable FakeTransmitter, we can test the CommunicationsController classes. We can also
267 | create boundary tests once we have the TransmitterAPI that make sure we are using the
268 | API correctly.
269 | Clean Boundaries
270 | Interesting things happen at boundaries. Change is one of those things. Good software
271 | designs accommodate change without huge investments and rework. When we use code
272 | that is out of our control, special care must be taken to protect our investment and make
273 | sure future change is not too costly.
274 | Code at the boundaries needs clear separation and tests that define expectations. We
275 | should avoid letting too much of our code know about the third-party particulars. It’s better
276 | to depend on something you control than on something you don’t control, lest it end up
277 | controlling you.
278 | We manage third-party boundaries by having very few places in the code that refer to
279 | them. We may wrap them as we did with Map, or we may use an ADAPTER to convert from
280 | our perfect interface to the provided interface. Either way our code speaks to us better,
281 | promotes internally consistent usage across the boundary, and has fewer maintenance
282 | points when the third-party code changes.
283 |
284 |
285 |
286 |
287 |
288 |
289 |
290 |
291 |
292 |
293 |
294 |
295 |
296 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 |
2 | ترجمه آزاد کتاب کد تمیز
3 |
4 |
5 |
6 |
7 |
8 | این پروژه یک کار گروهی برای ترجمه آزاد یکی از بهترین کتاب های برنامه نویسیه.
9 |
10 |
11 | درباره کتاب
12 |
13 |
14 |
15 | این کتاب سعی دارد توسعهی نرمافزار به روش چابک (Agile) را به شما آموزش دهد. داستان نوشتن کتاب از آنجا شروع شد که رابرت.سی.مارتین (Robert C. Martin معروف به عمو باب) نویسندهی این کتاب، مدتها قبل، سردمدارانِ تفکرِ اجایل را به یک دورهمی دوستانه دعوت کرد. هدف اصلی این دورهمی بررسی نقاط اشتراک متدهای توسعه نظیر اسکرام، کریستال، ایکس.پی، پراگماتیک و … بود. نهایتاً نتیجهی این گردهمایی به نامگذاری متدها و طبقهبندی روشهای مختلف زیر پرچمی تحت عنوان اجایل/چابک (یا Adaptive) منتهی شد. از دیگر ثمرات این جلسه، توافق بر سر ۴ ارزش (Value) کلیدی و ۱۲ اصل(Principle) دیگر مبتنی بر ارزشهای فوق بود که میتوانید در اجایلمانیفستو مطالعه کنید.
16 |
17 | بعدها عمو باب به کمک سایر همکارانش در موسسهی Object Mentor روشهای مختلف کدنویسی را بررسی کرده و بهترین موارد را استخراج کردند. این روشها به تدریج روی هم تلنبار شد و نهایتاً در قالب کتابِ Clean Code در اختیار عموم برنامهنویسان قرار گرفت. مفاهیم این کتاب تا آنجا مورد توجه توسعهدهندگان قرار گرفت که در مدت کوتاهی به یکی از پرفروشترین کتابهای آمازون تبدیل شد. رابرت.سی.مارتین با تکیه بر اصول اجایل، نکاتی را در کتابش مطرح کرد که باعث تمییزتر شدن کدها، نگهداری آسانتر، درک بهتر منطق برنامه و بهبود عملکرد آن میشود. در این کتاب روش نوشتن کدهای ماژولار، چگونگی اشکالزدایی برنامه، نحوهی استفاده از توسعهی آزمون محور (TDD: Test Driven Development) و … نیز آموزش داده میشود.
18 |
19 | بیشتر بخوانید
20 |
21 |
22 |
23 | ## راهنمای مشارکت
24 | بخش هایی از کتاب که به زبان انگلیسی هستند و ترجمه نشده. کافیه اون قسمت ها رو با ترجمه جایگزین کنید و یه ریکوئست بفرستید. منم سر وقت اون رو باز بینی میکنم و اگه خوب بود به ترجمه اضافه میشه.
25 |
26 | اگر میخوای یک بخش بزرگ یا یک فصل رو ترجمه کنی با ایمیل زیر بهم خبر بده تا از ترجمه دوباره توسط بقیه جلوگیری بشه.
27 |
28 |
noahopentranslate@gmail.com
29 |
30 | ## بخش های ترجمه شده
31 |
32 | * [0_مقدمه](0_introduction(completed)/introduction.md)
33 | * [0_مقدمه](0_introduction(completed)/introduction.md)
34 | * [1_کد تمیز](1_Clean_Code(completed)/clean-code.md)
35 |
36 | * [کد همیشه وجود خواهد داشت](1_Clean_Code(completed)/clean-code.md#%DA%A9%D8%AF-%D9%87%D9%85%DB%8C%D8%B4%D9%87-%D9%88%D8%AC%D9%88%D8%AF-%D8%AE%D9%88%D8%A7%D9%87%D8%AF-%D8%AF%D8%A7%D8%B4%D8%AA)
37 |
38 | * [کد بد](1_Clean_Code(completed)/clean-code.md#%DA%A9%D8%AF-%D8%A8%D8%AF)
39 |
40 | * [هزینه کلی مالک یک شلختگی بودن](1_Clean_Code(completed)/clean-code.md#%D9%87%D8%B2%DB%8C%D9%86%D9%87-%DA%A9%D9%84%DB%8C-%D9%85%D8%A7%D9%84%DA%A9-%DB%8C%DA%A9-%D8%B4%D9%84%D8%AE%D8%AA%DA%AF%DB%8C-%D8%A8%D9%88%D8%AF%D9%86)
41 |
42 | * [طراحی مجدد بزرگ در اسمان](1_Clean_Code(completed)/clean-code.md#%D8%B7%D8%B1%D8%A7%D8%AD%DB%8C-%D9%85%D8%AC%D8%AF%D8%AF-%D8%A8%D8%B2%D8%B1%DA%AF-%D8%AF%D8%B1-%D8%A7%D8%B3%D9%85%D8%A7%D9%86)
43 |
44 | * [نگرش](1_Clean_Code(completed)/clean-code.md#%D9%86%DA%AF%D8%B1%D8%B4)
45 |
46 | * [مسئله بغرنج اصلی](1_Clean_Code(completed)/clean-code.md#%D9%85%D8%B3%D8%A6%D9%84%D9%87-%D8%A8%D8%BA%D8%B1%D9%86%D8%AC-%D8%A7%D8%B5%D9%84%DB%8C)
47 |
48 | * [هنر کد تمیز؟](1_Clean_Code(completed)/clean-code.md#%D9%87%D9%86%D8%B1-%DA%A9%D8%AF-%D8%AA%D9%85%DB%8C%D8%B2)
49 |
50 | * [کد تمیز چیست؟](1_Clean_Code(completed)/clean-code.md#%DA%A9%D8%AF-%D8%AA%D9%85%DB%8C%D8%B2-%DA%86%DB%8C%D8%B3%D8%AA)
51 |
52 | * [مکتب فکری!](1_Clean_Code(completed)/clean-code.md#%D9%85%DA%A9%D8%AA%D8%A8-%D9%81%DA%A9%D8%B1%DB%8C)
53 | * [2\_اسامی با معنی](2_meaningful-names(completed)/meaningful-names.md)
54 |
55 | * [استفاده از اسمهای بیان کننده منظور (Intention-Revealing Names)](2_meaningful-names(completed)/meaningful-names.md#%D8%A7%D8%B3%D8%AA%D9%81%D8%A7%D8%AF%D9%87-%D8%A7%D8%B2-%D8%A7%D8%B3%D9%85%D9%87%D8%A7%DB%8C-%D8%A8%DB%8C%D8%A7%D9%86-%DA%A9%D9%86%D9%86%D8%AF%D9%87-%D9%85%D9%86%D8%B8%D9%88%D8%B1-intention-revealing-names)
56 |
57 | * [خودداری از دادن اطلاعات اشتباه](2_meaningful-names(completed)/meaningful-names.md#%D8%AE%D9%88%D8%AF%D8%AF%D8%A7%D8%B1%DB%8C-%D8%A7%D8%B2-%D8%AF%D8%A7%D8%AF%D9%86-%D8%A7%D8%B7%D9%84%D8%A7%D8%B9%D8%A7%D8%AA-%D8%A7%D8%B4%D8%AA%D8%A8%D8%A7%D9%87)
58 |
59 | * [تفاوتهای با معنی ایجاد کنید](2_meaningful-names(completed)/meaningful-names.md#%D8%AA%D9%81%D8%A7%D9%88%D8%AA%D9%87%D8%A7%DB%8C-%D8%A8%D8%A7-%D9%85%D8%B9%D9%86%DB%8C-%D8%A7%DB%8C%D8%AC%D8%A7%D8%AF-%DA%A9%D9%86%DB%8C%D8%AF)
60 |
61 | * [از اسمهای قابل تلفظ استفاده کنید](2_meaningful-names(completed)/meaningful-names.md#%D8%A7%D8%B2-%D8%A7%D8%B3%D9%85%D9%87%D8%A7%DB%8C-%D9%82%D8%A7%D8%A8%D9%84-%D8%AA%D9%84%D9%81%D8%B8-%D8%A7%D8%B3%D8%AA%D9%81%D8%A7%D8%AF%D9%87-%DA%A9%D9%86%DB%8C%D8%AF)
62 |
63 | * [از اسامی قابل جستجو استفاده کنید](2_meaningful-names(completed)/meaningful-names.md#%D8%A7%D8%B2-%D8%A7%D8%B3%D8%A7%D9%85%DB%8C-%D9%82%D8%A7%D8%A8%D9%84-%D8%AC%D8%B3%D8%AA%D8%AC%D9%88-%D8%A7%D8%B3%D8%AA%D9%81%D8%A7%D8%AF%D9%87-%DA%A9%D9%86%DB%8C%D8%AF)
64 |
65 | * [از رمزگذاری خودداری کنید](2_meaningful-names(completed)/meaningful-names.md#%D8%A7%D8%B2-%D8%B1%D9%85%D8%B2%DA%AF%D8%B0%D8%A7%D8%B1%DB%8C-%D8%AE%D9%88%D8%AF%D8%AF%D8%A7%D8%B1%DB%8C-%DA%A9%D9%86%DB%8C%D8%AF)
66 |
67 | * [نمادگذاری مجارستانی](2_meaningful-names(completed)/meaningful-names.md#%D9%86%D9%85%D8%A7%D8%AF%DA%AF%D8%B0%D8%A7%D8%B1%DB%8C-%D9%85%D8%AC%D8%A7%D8%B1%D8%B3%D8%AA%D8%A7%D9%86%DB%8C)
68 | * [پیشوندهای متغیر](2_meaningful-names(completed)/meaningful-names.md#%D9%BE%DB%8C%D8%B4%D9%88%D9%86%D8%AF%D9%87%D8%A7%DB%8C-%D9%85%D8%AA%D8%BA%DB%8C%D8%B1)
69 |
70 | * [واسطها (interface) و پیادهسازیها](2_meaningful-names(completed)/meaningful-names.md#%D9%88%D8%A7%D8%B3%D8%B7%D9%87%D8%A7-interface-%D9%88-%D9%BE%DB%8C%D8%A7%D8%AF%D9%87%D8%B3%D8%A7%D8%B2%DB%8C%D9%87%D8%A7)
71 |
72 | * [از نگاشت ذهنی خودداری کنید](2_meaningful-names(completed)/meaningful-names.md#%D8%A7%D8%B2-%D9%86%DA%AF%D8%A7%D8%B4%D8%AA-%D8%B0%D9%87%D9%86%DB%8C-%D8%AE%D9%88%D8%AF%D8%AF%D8%A7%D8%B1%DB%8C-%DA%A9%D9%86%DB%8C%D8%AF)
73 |
74 | * [نام کلاسها](2_meaningful-names(completed)/meaningful-names.md#%D9%86%D8%A7%D9%85-%DA%A9%D9%84%D8%A7%D8%B3%D9%87%D8%A7)
75 |
76 | * [نام متدها](2_meaningful-names(completed)/meaningful-names.md#%D9%86%D8%A7%D9%85-%D9%85%D8%AA%D8%AF%D9%87%D8%A7)
77 |
78 | * [بانمک نباشید](2_meaningful-names(completed)/meaningful-names.md#%D8%A8%D8%A7%D9%86%D9%85%DA%A9-%D9%86%D8%A8%D8%A7%D8%B4%DB%8C%D8%AF)
79 |
80 | * [برای هر مفهوم یک کلمه انتخاب کنید](2_meaningful-names(completed)/meaningful-names.md#%D8%A8%D8%B1%D8%A7%DB%8C-%D9%87%D8%B1-%D9%85%D9%81%D9%87%D9%88%D9%85-%DB%8C%DA%A9-%DA%A9%D9%84%D9%85%D9%87-%D8%A7%D9%86%D8%AA%D8%AE%D8%A7%D8%A8-%DA%A9%D9%86%DB%8C%D8%AF)
81 |
82 | * [با ایهام ننویسید](2_meaningful-names(completed)/meaningful-names.md#%D8%A8%D8%A7-%D8%A7%DB%8C%D9%87%D8%A7%D9%85-%D9%86%D9%86%D9%88%DB%8C%D8%B3%DB%8C%D8%AF)
83 |
84 | * [از دامنه واژگان مربوط به راه حل استفاده کنید](2_meaningful-names(completed)/meaningful-names.md#%D8%A7%D8%B2-%D8%AF%D8%A7%D9%85%D9%86%D9%87-%D9%88%D8%A7%DA%98%DA%AF%D8%A7%D9%86-%D9%85%D8%B1%D8%A8%D9%88%D8%B7-%D8%A8%D9%87-%D8%B1%D8%A7%D9%87-%D8%AD%D9%84-%D8%A7%D8%B3%D8%AA%D9%81%D8%A7%D8%AF%D9%87-%DA%A9%D9%86%DB%8C%D8%AF)
85 |
86 | * [از دامنه واژگان صورت مسئله استفاده کنید](2_meaningful-names(completed)/meaningful-names.md#%D8%A7%D8%B2-%D8%AF%D8%A7%D9%85%D9%86%D9%87-%D9%88%D8%A7%DA%98%DA%AF%D8%A7%D9%86-%D8%B5%D9%88%D8%B1%D8%AA-%D9%85%D8%B3%D8%A6%D9%84%D9%87-%D8%A7%D8%B3%D8%AA%D9%81%D8%A7%D8%AF%D9%87-%DA%A9%D9%86%DB%8C%D8%AF)
87 |
88 | * [ساختارهای با معنی اضافه کنید](2_meaningful-names(completed)/meaningful-names.md#%D8%B3%D8%A7%D8%AE%D8%AA%D8%A7%D8%B1%D9%87%D8%A7%DB%8C-%D8%A8%D8%A7-%D9%85%D8%B9%D9%86%DB%8C-%D8%A7%D8%B6%D8%A7%D9%81%D9%87-%DA%A9%D9%86%DB%8C%D8%AF)
89 |
90 | * [سخن پایانی](2_meaningful-names(completed)/meaningful-names.md#%D8%B3%D8%AE%D9%86-%D9%BE%D8%A7%DB%8C%D8%A7%D9%86%DB%8C)
91 |
92 | * [3_توابع](3_Functions(completed)/3_Functions.md#%D8%AA%D9%88%D8%A7%D8%A8%D8%B9)
93 |
94 | * [کوچک بودن!](3_Functions(completed)/3_Functions.md#%DA%A9%D9%88%DA%86%DA%A9-%D8%A8%D9%88%D8%AF%D9%86)
95 | * [بلوک ها و تو رفتگی ها](3_Functions.md#%D8%A8%D9%84%D9%88%DA%A9-%D9%87%D8%A7-%D9%88-%D8%AA%D9%88-%D8%B1%D9%81%D8%AA%DA%AF%DB%8C-%D9%87%D8%A7)
96 | * [انجام دادن یک کار دیگر](3_Functions.md#%D8%A7%D9%86%D8%AC%D8%A7%D9%85-%D8%AF%D8%A7%D8%AF%D9%86-%DB%8C%DA%A9-%DA%A9%D8%A7%D8%B1-%D8%AF%DB%8C%DA%AF%D8%B1)
97 | * [بخشهای داخت توابع](3_Functions.md#%D8%A8%D8%AE%D8%B4%D9%87%D8%A7%DB%8C-%D8%AF%D8%A7%D8%AE%D8%AA-%D8%AA%D9%88%D8%A7%D8%A8%D8%B9)
98 | * [یک سطح انتزاع به ازای هر تابع](3_Functions.md#%DB%8C%DA%A9-%D8%B3%D8%B7%D8%AD-%D8%A7%D9%86%D8%AA%D8%B2%D8%A7%D8%B9-%D8%A8%D9%87-%D8%A7%D8%B2%D8%A7%DB%8C-%D9%87%D8%B1-%D8%AA%D8%A7%D8%A8%D8%B9)
99 | * [خواندن کد از بالا به پایین: قاعده گام به گام](3_Functions.md#%D8%AE%D9%88%D8%A7%D9%86%D8%AF%D9%86-%DA%A9%D8%AF-%D8%A7%D8%B2-%D8%A8%D8%A7%D9%84%D8%A7-%D8%A8%D9%87-%D9%BE%D8%A7%DB%8C%DB%8C%D9%86-%D9%82%D8%A7%D8%B9%D8%AF%D9%87-%DA%AF%D8%A7%D9%85-%D8%A8%D9%87-%DA%AF%D8%A7%D9%85)
100 | * [Switch Statements](3_Functions.md#switch-statements)
101 | * [استفاده از نام های توصیفی](3_Functions.md#%D8%A7%D8%B3%D8%AA%D9%81%D8%A7%D8%AF%D9%87-%D8%A7%D8%B2-%D9%86%D8%A7%D9%85-%D9%87%D8%A7%DB%8C-%D8%AA%D9%88%D8%B5%DB%8C%D9%81%DB%8C)
102 | * [آرگومان های تابع](3_Functions.md#%D8%A2%D8%B1%DA%AF%D9%88%D9%85%D8%A7%D9%86-%D9%87%D8%A7%DB%8C-%D8%AA%D8%A7%D8%A8%D8%B9)
103 | * [فرم رایج Monadic](3_Functions.md#%D9%81%D8%B1%D9%85-%D8%B1%D8%A7%DB%8C%D8%AC-monadic)
104 | * [آرگومان های پرچم](3_Functions.md#%D8%A2%D8%B1%DA%AF%D9%88%D9%85%D8%A7%D9%86-%D9%87%D8%A7%DB%8C-%D9%BE%D8%B1%DA%86%D9%85)
105 | * [توابع Dyadic](3_Functions.md#%D8%AA%D9%88%D8%A7%D8%A8%D8%B9-dyadic)
106 | * [سه آرگومانی](3_Functions.md#%D8%B3%D9%87-%D8%A2%D8%B1%DA%AF%D9%88%D9%85%D8%A7%D9%86%DB%8C)
107 | * [آبجکت های آرگومان](3_Functions.md#%D8%A2%D8%A8%D8%AC%DA%A9%D8%AA-%D9%87%D8%A7%DB%8C-%D8%A2%D8%B1%DA%AF%D9%88%D9%85%D8%A7%D9%86)
108 | * [لیست های آرگومان](3_Functions.md#%D9%84%DB%8C%D8%B3%D8%AA-%D9%87%D8%A7%DB%8C-%D8%A2%D8%B1%DA%AF%D9%88%D9%85%D8%A7%D9%86)
109 | * [افعال و کیوردها](3_Functions.md#%D8%A7%D9%81%D8%B9%D8%A7%D9%84-%D9%88-%DA%A9%DB%8C%D9%88%D8%B1%D8%AF%D9%87%D8%A7)
110 | * [نداشتن هیچ عوارض جانبی](3_Functions.md#%D9%86%D8%AF%D8%A7%D8%B4%D8%AA%D9%86-%D9%87%DB%8C%DA%86-%D8%B9%D9%88%D8%A7%D8%B1%D8%B6-%D8%AC%D8%A7%D9%86%D8%A8%DB%8C)
111 | * [آرگومان های خروجی](3_Functions.md#%D8%A2%D8%B1%DA%AF%D9%88%D9%85%D8%A7%D9%86-%D9%87%D8%A7%DB%8C-%D8%AE%D8%B1%D9%88%D8%AC%DB%8C)
112 | * [جداسازی رایج Query](3_Functions.md#%D8%AC%D8%AF%D8%A7%D8%B3%D8%A7%D8%B2%DB%8C-%D8%B1%D8%A7%DB%8C%D8%AC-query)
113 | * [ترجیح Exception ها نسبت به برگرداندن کد خطا](3_Functions.md#%D8%AA%D8%B1%D8%AC%DB%8C%D8%AD-exception-%D9%87%D8%A7-%D9%86%D8%B3%D8%A8%D8%AA-%D8%A8%D9%87-%D8%A8%D8%B1%DA%AF%D8%B1%D8%AF%D8%A7%D9%86%D8%AF%D9%86-%DA%A9%D8%AF-%D8%AE%D8%B7%D8%A7)
114 | * [استخراج بلوک های Try/Catch](3_Functions.md#%D8%A7%D8%B3%D8%AA%D8%AE%D8%B1%D8%A7%D8%AC-%D8%A8%D9%84%D9%88%DA%A9-%D9%87%D8%A7%DB%8C-trycatch)
115 | * [مدیریت خطا یک چیز است](3_Functions.md#%D9%85%D8%AF%DB%8C%D8%B1%DB%8C%D8%AA-%D8%AE%D8%B7%D8%A7-%DB%8C%DA%A9-%DA%86%DB%8C%D8%B2-%D8%A7%D8%B3%D8%AA)
116 | * [آهنربای وابستگی Error.java](3_Functions.md#%D8%A2%D9%87%D9%86%D8%B1%D8%A8%D8%A7%DB%8C-%D9%88%D8%A7%D8%A8%D8%B3%D8%AA%DA%AF%DB%8C-errorjava)
117 | * [خود را تکرار نکنید](3_Functions.md#%D8%AE%D9%88%D8%AF-%D8%B1%D8%A7-%D8%AA%DA%A9%D8%B1%D8%A7%D8%B1-%D9%86%DA%A9%D9%86%DB%8C%D8%AF)
118 | * [برنامه نویسی ساخت یافته](3_Functions.md#%D8%A8%D8%B1%D9%86%D8%A7%D9%85%D9%87-%D9%86%D9%88%DB%8C%D8%B3%DB%8C-%D8%B3%D8%A7%D8%AE%D8%AA-%DB%8C%D8%A7%D9%81%D8%AA%D9%87)
119 | * [چگونه می توانید توابعی مانند این را بنویسید؟](3_Functions.md#%DA%86%DA%AF%D9%88%D9%86%D9%87-%D9%85%DB%8C-%D8%AA%D9%88%D8%A7%D9%86%DB%8C%D8%AF-%D8%AA%D9%88%D8%A7%D8%A8%D8%B9%DB%8C-%D9%85%D8%A7%D9%86%D9%86%D8%AF-%D8%A7%DB%8C%D9%86-%D8%B1%D8%A7-%D8%A8%D9%86%D9%88%DB%8C%D8%B3%DB%8C%D8%AF)
120 | * [نتیجه گیری](3_Functions.md#%D9%86%D8%AA%DB%8C%D8%AC%D9%87-%DA%AF%DB%8C%D8%B1%DB%8C)
121 |
122 | * [کامنت ها ۴](4_Comments.md#%DA%A9%D8%A7%D9%85%D9%86%D8%AA-%D9%87%D8%A7-%DB%B4)
123 | * [کامنت ها برای کد بد نوشته نشده اند](4_Comments.md#%DA%A9%D8%A7%D9%85%D9%86%D8%AA-%D9%87%D8%A7-%D8%A8%D8%B1%D8%A7%DB%8C-%DA%A9%D8%AF-%D8%A8%D8%AF-%D9%86%D9%88%D8%B4%D8%AA%D9%87-%D9%86%D8%B4%D8%AF%D9%87-%D8%A7%D9%86%D8%AF)
124 | * [منظورتان را با کد برسانید](4_Comments.md#%D9%85%D9%86%D8%B8%D9%88%D8%B1%D8%AA%D8%A7%D9%86-%D8%B1%D8%A7-%D8%A8%D8%A7-%DA%A9%D8%AF-%D8%A8%D8%B1%D8%B3%D8%A7%D9%86%DB%8C%D8%AF)
125 | * [کامنت های خوب](4_Comments.md#%DA%A9%D8%A7%D9%85%D9%86%D8%AA-%D9%87%D8%A7%DB%8C-%D8%AE%D9%88%D8%A8)
126 | * [کامنت های قانونی](4_Comments.md#%DA%A9%D8%A7%D9%85%D9%86%D8%AA-%D9%87%D8%A7%DB%8C-%D9%82%D8%A7%D9%86%D9%88%D9%86%DB%8C)
127 | * [کامنت های آموزنده](4_Comments.md#%DA%A9%D8%A7%D9%85%D9%86%D8%AA-%D9%87%D8%A7%DB%8C-%D8%A2%D9%85%D9%88%D8%B2%D9%86%D8%AF%D9%87)
128 | * [شرح نیت](4_Comments.md#%D8%B4%D8%B1%D8%AD-%D9%86%DB%8C%D8%AA)
129 | * [شفاف سازی](4_Comments.md#%D8%B4%D9%81%D8%A7%D9%81-%D8%B3%D8%A7%D8%B2%DB%8C)
130 | * [هشدار پیامدها](4_Comments.md#%D9%87%D8%B4%D8%AF%D8%A7%D8%B1-%D9%BE%DB%8C%D8%A7%D9%85%D8%AF%D9%87%D8%A7)
131 | * [TODO کامنت های](4_Comments.md#todo-%DA%A9%D8%A7%D9%85%D9%86%D8%AA-%D9%87%D8%A7%DB%8C)
132 | * [تقویت](4_Comments.md#%D8%AA%D9%82%D9%88%DB%8C%D8%AA)
133 | * [اسناد java در API های عمومی](4_Comments.md#%D8%A7%D8%B3%D9%86%D8%A7%D8%AF-java-%D8%AF%D8%B1-api-%D9%87%D8%A7%DB%8C-%D8%B9%D9%85%D9%88%D9%85%DB%8C)
134 | * [کامنت های بد](4_Comments.md#%DA%A9%D8%A7%D9%85%D9%86%D8%AA-%D9%87%D8%A7%DB%8C-%D8%A8%D8%AF)
135 | * [غرزدن](4_Comments.md#%D8%BA%D8%B1%D8%B2%D8%AF%D9%86)
136 | * [کامنت های اضافی](4_Comments.md#%DA%A9%D8%A7%D9%85%D9%86%D8%AA-%D9%87%D8%A7%DB%8C-%D8%A7%D8%B6%D8%A7%D9%81%DB%8C)
137 | * [کامنتهای گمراه کننده](4_Comments.md#%DA%A9%D8%A7%D9%85%D9%86%D8%AA%D9%87%D8%A7%DB%8C-%DA%AF%D9%85%D8%B1%D8%A7%D9%87-%DA%A9%D9%86%D9%86%D8%AF%D9%87)
138 | * [کامنت های مجاز](4_Comments.md#%DA%A9%D8%A7%D9%85%D9%86%D8%AA-%D9%87%D8%A7%DB%8C-%D9%85%D8%AC%D8%A7%D8%B2)
139 | * [کامنت های گزارشی](4_Comments.md#%DA%A9%D8%A7%D9%85%D9%86%D8%AA-%D9%87%D8%A7%DB%8C-%DA%AF%D8%B2%D8%A7%D8%B1%D8%B4%DB%8C)
140 | * [کامنت های شلوغ](4_Comments.md#%DA%A9%D8%A7%D9%85%D9%86%D8%AA-%D9%87%D8%A7%DB%8C-%D8%B4%D9%84%D9%88%D8%BA)
141 | * [شلوغی هولناک](4_Comments.md#%D8%B4%D9%84%D9%88%D8%BA%DB%8C-%D9%87%D9%88%D9%84%D9%86%D8%A7%DA%A9)
142 | * [زمانی که میتوانید از یک تابع یا متغییر استفاده کنید از کامنت ها استفاده نکنید](4_Comments.md#%D8%B2%D9%85%D8%A7%D9%86%DB%8C-%DA%A9%D9%87-%D9%85%DB%8C%D8%AA%D9%88%D8%A7%D9%86%DB%8C%D8%AF-%D8%A7%D8%B2-%DB%8C%DA%A9-%D8%AA%D8%A7%D8%A8%D8%B9-%DB%8C%D8%A7-%D9%85%D8%AA%D8%BA%DB%8C%DB%8C%D8%B1-%D8%A7%D8%B3%D8%AA%D9%81%D8%A7%D8%AF%D9%87-%DA%A9%D9%86%DB%8C%D8%AF-%D8%A7%D8%B2-%DA%A9%D8%A7%D9%85%D9%86%D8%AA-%D9%87%D8%A7-%D8%A7%D8%B3%D8%AA%D9%81%D8%A7%D8%AF%D9%87-%D9%86%DA%A9%D9%86%DB%8C%D8%AF)
143 | * [نشانگرهای موقعیت](4_Comments.md#%D9%86%D8%B4%D8%A7%D9%86%DA%AF%D8%B1%D9%87%D8%A7%DB%8C-%D9%85%D9%88%D9%82%D8%B9%DB%8C%D8%AA)
144 | * [کامنت های بستن آکولاد](4_Comments.md#%DA%A9%D8%A7%D9%85%D9%86%D8%AA-%D9%87%D8%A7%DB%8C-%D8%A8%D8%B3%D8%AA%D9%86-%D8%A2%DA%A9%D9%88%D9%84%D8%A7%D8%AF)
145 | * [خصیصهها و خطوط معرف نویسنده کد](4_Comments.md#%D8%AE%D8%B5%DB%8C%D8%B5%D9%87%D9%87%D8%A7-%D9%88-%D8%AE%D8%B7%D9%88%D8%B7-%D9%85%D8%B9%D8%B1%D9%81-%D9%86%D9%88%DB%8C%D8%B3%D9%86%D8%AF%D9%87-%DA%A9%D8%AF)
146 | * [کامنت کردن کد](4_Comments.md#%DA%A9%D8%A7%D9%85%D9%86%D8%AA-%DA%A9%D8%B1%D8%AF%D9%86-%DA%A9%D8%AF)
147 | * [HTML کامنت های](4_Comments.md#html-%DA%A9%D8%A7%D9%85%D9%86%D8%AA-%D9%87%D8%A7%DB%8C)
148 | * [اطلاعات غیرمحلی](4_Comments.md#%D8%A7%D8%B7%D9%84%D8%A7%D8%B9%D8%A7%D8%AA-%D8%BA%DB%8C%D8%B1%D9%85%D8%AD%D9%84%DB%8C)
149 | * [اطلاعات بیش از اندازه](4_Comments.md#%D8%A7%D8%B7%D9%84%D8%A7%D8%B9%D8%A7%D8%AA-%D8%A8%DB%8C%D8%B4-%D8%A7%D8%B2-%D8%A7%D9%86%D8%AF%D8%A7%D8%B2%D9%87)
150 | * [ارتباط نامشخص](4_Comments.md#%D8%A7%D8%B1%D8%AA%D8%A8%D8%A7%D8%B7-%D9%86%D8%A7%D9%85%D8%B4%D8%AE%D8%B5)
151 | * [عناوین تابع](4_Comments.md#%D8%B9%D9%86%D8%A7%D9%88%DB%8C%D9%86-%D8%AA%D8%A7%D8%A8%D8%B9)
152 | * [اسناد java در کد غیرعمومی](4_Comments.md#%D8%A7%D8%B3%D9%86%D8%A7%D8%AF-java-%D8%AF%D8%B1-%DA%A9%D8%AF-%D8%BA%DB%8C%D8%B1%D8%B9%D9%85%D9%88%D9%85%DB%8C)
153 | * [مثال](4_Comments.md#%D9%85%D8%AB%D8%A7%D9%84)
154 |
155 |
156 | * [۵ قالببندی](5_Formatting(completed)/5_Formatting.md#%DB%B5-%D9%82%D8%A7%D9%84%D8%A8%D8%A8%D9%86%D8%AF%DB%8C)
157 | * [هدف قالببندی](5_Formatting(completed)/5_Formatting.md#%D9%87%D8%AF%D9%81-%D9%82%D8%A7%D9%84%D8%A8%D8%A8%D9%86%D8%AF%DB%8C)
158 | * [قالب بندی عمودی](5_Formatting(completed)/5_Formatting.md#%D9%82%D8%A7%D9%84%D8%A8-%D8%A8%D9%86%D8%AF%DB%8C-%D8%B9%D9%85%D9%88%D8%AF%DB%8C)
159 | * [استعاره روزنامه](5_Formatting(completed)/5_Formatting.md#%D8%A7%D8%B3%D8%AA%D8%B9%D8%A7%D8%B1%D9%87-%D8%B1%D9%88%D8%B2%D9%86%D8%A7%D9%85%D9%87)
160 | * [گشودگی عمودی بین مفاهیم](5_Formatting(completed)/5_Formatting.md#%DA%AF%D8%B4%D9%88%D8%AF%DA%AF%DB%8C-%D8%B9%D9%85%D9%88%D8%AF%DB%8C-%D8%A8%DB%8C%D9%86-%D9%85%D9%81%D8%A7%D9%87%DB%8C%D9%85)
161 | * [تراکم عمودی](5_Formatting(completed)/5_Formatting.md#%D8%AA%D8%B1%D8%A7%DA%A9%D9%85-%D8%B9%D9%85%D9%88%D8%AF%DB%8C)
162 | * [فاصله عمودی](5_Formatting(completed)/5_Formatting.md#%D9%81%D8%A7%D8%B5%D9%84%D9%87-%D8%B9%D9%85%D9%88%D8%AF%DB%8C)
163 | * [ترتیب عمودی](5_Formatting(completed)/5_Formatting.md#%D8%AA%D8%B1%D8%AA%DB%8C%D8%A8-%D8%B9%D9%85%D9%88%D8%AF%DB%8C)
164 | * [قالببندی افقی](5_Formatting(completed)/5_Formatting.md#%D9%82%D8%A7%D9%84%D8%A8%D8%A8%D9%86%D8%AF%DB%8C-%D8%A7%D9%81%D9%82%DB%8C)
165 | * [گشودگی و چگالی افقی](5_Formatting(completed)/5_Formatting.md#%DA%AF%D8%B4%D9%88%D8%AF%DA%AF%DB%8C-%D9%88-%DA%86%DA%AF%D8%A7%D9%84%DB%8C-%D8%A7%D9%81%D9%82%DB%8C)
166 | * [ترازبندی افقی](5_Formatting(completed)/5_Formatting.md#%D8%AA%D8%B1%D8%A7%D8%B2%D8%A8%D9%86%D8%AF%DB%8C-%D8%A7%D9%81%D9%82%DB%8C)
167 | * [تورفتگی](5_Formatting(completed)/5_Formatting.md#%D8%AA%D9%88%D8%B1%D9%81%D8%AA%DA%AF%DB%8C)
168 | * [دامنه های ساختگی](5_Formatting(completed)/5_Formatting.md#%D8%AF%D8%A7%D9%85%D9%86%D9%87-%D9%87%D8%A7%DB%8C-%D8%B3%D8%A7%D8%AE%D8%AA%DA%AF%DB%8C)
169 | * [قوانین تیم](5_Formatting(completed)/5_Formatting.md#%D9%82%D9%88%D8%A7%D9%86%DB%8C%D9%86-%D8%AA%DB%8C%D9%85)
170 | * [قوانین قالب بندی عمو باب](5_Formatting(completed)/5_Formatting.md#%D9%82%D9%88%D8%A7%D9%86%DB%8C%D9%86-%D9%82%D8%A7%D9%84%D8%A8-%D8%A8%D9%86%D8%AF%DB%8C-%D8%B9%D9%85%D9%88-%D8%A8%D8%A7%D8%A8)
171 |
172 |
173 |
--------------------------------------------------------------------------------
/2_meaningful-names(completed)/meaningful-names.md:
--------------------------------------------------------------------------------
1 |
2 |
3 | # فصل دو - اسامی با معنی
4 |
5 | ## مقدمه
6 |
7 | 
8 |
9 | اسمها همه جای نرمافزار وجود دارند. ما متغیرها، تابعها، آرگومانها، کلاسها و پکیجهایمان را نامگذاری میکنیم. ما فایلهای سورس و دایرکتوری هایی که آنها را شامل میشوند را نام گذاری میکنیم. ما حتی فایلهای jar و war و ear را نامگذاری میکنیم. ما نامگذاری میکنیم، نامگذاری میکنیم و نامگذاری میکنیم. از آنجایی که این کار را خیلی زیاد انجام میدهیم، بهتر است که آن را با شیوه درست دهیم. آنچه که در ادامه میخوانید، قوانینی ساده برای خلق اسم های خوب هستند.
10 |
11 | ## استفاده از اسمهای بیان کننده منظور (Intention-Revealing Names)
12 |
13 | کاملا واضح است که اسمها باید منظور شما را بازتاب دهند. چیزی که ما میخواهیم به شما بگوییم این است که ما در این قضیه کاملا جدی هستیم. انتخابکردن اسمهای خوب زمانبر است ولی زمان بیشتری از آنچه میگیرد را ذخیره میکند. پس به اسم هایتان توجه کنید و هر وقت اسمهای بهتری یافتید، آنها را عوض کنید. هر کسی که کد شما را بخواند (شامل خودتان) از انجام این کار خوشحال میشود. اسم یک متغیر، تابع یا کلاس، باید به تمام سوالهای بزرگ پاسخ دهد. اسم باید بگوید که چرا وجود دارد، چه میکند و چگونه استفاده میشود.اگر اسمی به کامنت نیاز داشته باشد،پس منظور خود را نمیرساند.
14 |
15 |
16 | ```java
17 | int d; // elapsed time in days
18 | ```
19 |
20 |
21 | اسم d در کد بالا هیچ منظوری را نمیرساند. این اسم احساس گذشت روزها را ایجاد نمیکند. ما باید اسمی انتخاب کنیم که مشخص کند چه چیزی در حال اندازه گیری شدن است و واحد و مقیاس آن اندازه گیری چیست.
22 |
23 |
24 | ```java
25 | int elapsedTimeInDays;
26 | int daysSinceCreation;
27 | int daysSinceModification;
28 | int fileAgeInDays;
29 | ```
30 |
31 |
32 | انتخاب اسمهایی که منظور ما را القا میکند، فهمیدن و تغییر دادن کد را راحت تر میکند. میتوانید بگویید کد زیر چه میکند؟
33 |
34 |
35 | ```java
36 | public List getThem() {
37 | List list1 = new ArrayList;
38 | for (int[] x : theList)
39 | If (x[0] == 4)
40 | List1.add(x);
41 | Return list1;
42 | }
43 | ```
44 |
45 |
46 | چرا گفتن کاری که این کد انجام میدهد سخت است؟ اینجا هیچ کد پیچیده ای وجود ندارد. فاصله ها و تورفتگی ها کاملا معقول هستند. در کل سه متغیر و دو ثابت استفاده شده است. اینجا هیچ کلاس عجیب یا متد پیچیده ای وجود ندارد، فقط یک لیست از آرایه ها وجود دارد. مشکل سادگی کد نیست، صراحت کد است؛ میزان صریح بودن کد در بیان منظور خودش. صریح بودن کد نیازمند این است که ما بتوانیم به سوال های نظیر این ها پاسخ دهیم:
47 |
48 | 1. چه چیزهایی در theList وجود دارد؟
49 | 2. اهمیت عضو صفرم در theList چیست؟
50 | 3. اهمیت مقدار 4 چیست؟
51 | 4. چگونه از لیستی که برگشت داده میشود استفاده کنم؟
52 |
53 | جواب سوالها در مثال قبل قابل تشخیص نیستند، ولی باید مشخص شوند. فرض کنید ما داریم روی یک بازی مین روبی کار میکنیم. ما میدانیم که صفحه بازی یک لیست از سلول هاست که با عنوان theList نمایش داده میشود. بیایید نام آن را به gameBoard تغییر دهیم. هر سلول در صفحه توسط یک آرایه ساده نشان داده میشود. همچنین این را میدانیم که مقدار صفرم، وضعیت سلول است و اینکه وضعیت 4 یعنی "پرچم گذاری شده". بیایید با دادن اسمهای این کانسپتها کد را به شکل قابل توجهی بهبود دهیم:
54 |
55 |
56 |
57 | ```java
58 | public List getFlaggedCells() {
59 | List flaggedCells = new ArrayList();
60 | for (int[] cell : gameBoard)
61 | If (cell[STATUS_VALUE] == FLAGGED)
62 | flaggedCells.add(cell);
63 | return flaggedCells;
64 | }
65 | ```
66 |
67 |
68 | دقت کنید که سادگی کد تغییری نکرده است و هنوز هم همان تعداد مقادیر ثابت و متغیر وجود دارد، دقیقا با همان تعداد تورفتگی و بیرون زدگی. ما میتوانیم پا را فراتر بگذاریم و به جای یک آرایه از اعداد، یک کلاس ساده برای سلولها بنویسیم.این کلاس میتواند یک تابع را شامل شود (که منظور خود را به درستی به نمایش میگذارد و آن را isFlagged مینامیم) که باعث میشود اعداد عجیب از کد حذف شوند:
69 |
70 |
71 | ```java
72 | public List getFlaggedCells() {
73 | List flaggedCells = new ArrayList();
74 | for (Cell cell : gameBoard)
75 | if (cell.isFlagged())
76 | flaggedCells.add(cell);
77 | return flaggedCells;
78 | }
79 | ```
80 |
81 |
82 | با این تغییرات ساده، دیگر فهمیدن اینکه چه کاری در حال انجام است سخت نیست. این قدرت انتخاب کردن اسمهای خوب است.
83 |
84 | ## خودداری از دادن اطلاعات اشتباه
85 |
86 | برنامه نویسها باید از به جا گذاشتن اطلاعات اشتباه که معنی کد را خراب میکنند خودداری کنند. ما باید از کلماتی که مفهوم آنها با منظور ما فاصله زیادی دارد دوری کنیم. برای مثال، کلمات hp ،aix و sco نامهای ضعیفی برای متغیرها هستند زیرا از اسامی یونیکس پلتفرم هستند. حتی اگر شما در حال نوشتن یک Hypotenuse هستید و hp مخفف خوبی برای آن به نظر میرسد، ممکن است اطلاعات ناسازگار در کد به جا بگذارید. هرگز به یک لیست از اکانتها اسم accountList را ندهید زیرا آن واقعا یک لیست است ولی کلمه List به معنی چیزی است که به برنامه نویس ها اختصاص دارد. اگر یک کانتینر اکانت را نگهداری میکند، به این معنی نیست که یک List است، این ممکن است به اطلاعات غلط منجر شود. پس accountGroup یا bunchOfAccounts یا فقط accounts اسمهای بهتری هستند.
87 |
88 | از استفاده از اسمهایی که تفاوتهای کوچکی با هم دارند خودداری کنید. چه تضمینی وجود دارد که بعدا دو شی با نامهای XYZControllerforEfficientHandlingOfStringsin و XYZControllerforEfficientStorageOfStrings با هم اشتباه گرفته نشوند؟ هر دو اسم شکل یکسانی دارند. در انتخاب اسم به تلفظ آن دقت کنید. استفاده از اسم با تلفظ اشتباه نوعی اطلاعات غلط است. به کمک محیطهای مدرن جاوا ما میتوانیم از تکمیل شدن خودکار کدها لذت ببریم. ما چند حرف تایپ میکنیم و دکمه ای را فشار میدهیم که لیستی از اسامی قابل استفاده برای تکمیل کلمه را به ما نشان میدهد.بسیار مفید است که نامهای بسیار مشابه به ترتیب حروف الفبا مرتب شوند.تفاوتها را آشکار میکند.
89 |
90 | یک مثال از نامهایی که اطلاعات غلط میدهند، نامهایی هستند که از حروفی استفاده میکنند که شبیه حروف دیگر هستند. مثلا حرف I و L، اگر به صورت I و l نوشته شوند،مطمئنا اشتباه گرفته میشوند. همچنین حرف lو1 نیز ممکن است اشتباه گرفته شوند.
91 |
92 |
93 | ```java
94 | int a = l;
95 | if(0==1)
96 | a=01;
97 | else
98 | l = 01;
99 | ```
100 |
101 |
102 |
103 | شاید فکر کنید این اتفاق محال است ؛ اما ما کدهایی را بررسی کردهایم که چنین مواردی در آنها به وفور وجود داشت. در وهله اول نویسنده پیشنهاد میکند که فونت متن را تغییر دهید که باعث آشکار شدن بهتر تفاوتها میشود، اما این راه حل باید به توسعه دهندگان آینده به صورت شفاهی یا کتبی منتقل شود. بهترین راه حل یک تغییر نام ساده است.
104 |
105 | ## تفاوتهای با معنی ایجاد کنید
106 |
107 | برنامه نویسها با نوشتن کدهای کامپایلر پسند برای خودشان مشکل ایجاد میکنند. برای مثال شما نمیتوانید از یک اسم در دو متغیر مختلف استفاده کنید،شما مجبورید یکی از اسمها را کمی تغییر دهید. گاهی اوقات اینکار را با تغییر دادن املای کلمات انجام میدهید، در اینصورت ممکن است تصحیح خطاهای املایی باعث مشکل در کامپایل نرم افزار شود. افزودن اعداد یا حروف اضافه هرگز کافی نیست. اگر نامها باید متفاوت باشند، پس معنی آنها نیز باید فرق کند.
108 |
109 | اسامی شامل سری اعداد (a1,a2,…,aN) با نام گذاری اصولی در تضاد هستند. این اسمها اطلاعات غلط نمیدهند،چون اصلا اطلاعاتی نمیدهند و کاملا بی معنی هستند. اینها هیچ سرنخی از منظور شما به دیگران نمیدهند. به مثال نگاه کنید:
110 |
111 |
112 | ```java
113 | public static void copyChars(char a1[], char a2[] {
114 | for (int i=0; i<a1.length; i++) {
115 | A2\[[i] = a1[i];
116 | }
117 | }
118 | ```
119 |
120 |
121 | این تابع خواناتر میشود، اگر از اسم های source و destination در ارگومنت ها استفاده کنیم.
122 |
123 | حروف اضافه(noise words) موارد بی معنی دیگری هستند. تصور کنید شما کلاسی به اسم Product دارید. اگر شما کلاسهای دیگری با اسمهای ProductInfo یا ProductData بسازید، شاید اسمهای مختلفی انتخاب کرده باشید اما در معنای آنها تفاوتی وجود ندارد. کلمات Info و Data کلمات اضافه هستند، مثل a, an و the. دقت کنید که استفاده از این پیشوندها مشکلی ندارد، مثلا شما میتوانید از a برای همه متغیرهای محلی و از the برای همه آرگومنتهای توابعتان استفاده کنید. در حقیقت مشکل از جایی شروع میشود که شما یک متغیر را theZork بنامید، فقط به این دلیل که متغیر دیگری به نام Zork دارید. حروف اضافه،زائد هستند. کلمه Variable هیچوقت نباید در اسم یک متغیر نمایان شود. واژه table نباید در اسم یک Table نشان داده شود. چرا فکر میکنید NameString بهتر از Name است؟ آیا ممکن است Name یک عدد اعشاری باشد؟اگر جواب بله است،پس شما کل قوانین را زیر سوال برده اید!
124 |
125 | فرض کنیدکلاسی به اسم Customer و کلاسی دیگر به اسم CustomerObject دارید.از اختلاف این دو اسم چه چیزی دستگیرتان میشود؟ کدام یک از این دو اسم، بهتر میتواند تاریخچه پرداختهای یک مشتری را نشان دهد؟ در مثالهای زیر استفاده مناسب از حروف اضافه را میبینید.
126 |
127 |
128 | ```java
129 | getActiveAccount();
130 | getActiveAccounts();
131 | getActiveAccountInfo();
132 | ```
133 |
134 |
135 | برنامه نویس به راحتی میفهمد که کدام تابع را نیاز دارد.
136 |
137 | دقت کنید که حروف اضافه چه تغییری در اسم متغیر شما میدهند. تفاوت متغیر moneyAmount از money غیرقابل تشخیص است. تفاوت customerInfo از customer نیز همینطور.accountData از account و theMessage از message. اسامی قابل تشخیص باید تفاوت خود را به خواننده نشان دهند.
138 |
139 | ## از اسمهای قابل تلفظ استفاده کنید
140 |
141 | انسانها در استفاده از کلمات ماهرند. قسمتهای مشخصی از مغز ما به درک مفهوم کلمات اختصاص داده شده اند.مفهوم کلمات ارتباط مستقیمی با تلفظ آنها دارد. مغز ما کلمات را با توجه به تلفظ آنها درک میکند، نه نوشتار آنها. بنابراین، بهتر است از اسمهای قابل تلفظ استفاده کنید. اگر نمیتوانید یک اسم را تلفظ کنید، نمیتوانید درباره آن بحث کنید،بدون اینکه مثل یک احمق صدا در بیاورید! "Well,over here on the bee cee arr three cee enn tee we have a pee ess zee kyew int, see?" میتوانید این متن را بخوانید؟ فهمیدید که این موضوع مهم است، چون برنامه نویسی یک فعالیت اجتماعی است. یک کمپانی در برنامه خود، مفهومی به نام genymdhms دارد (generation date, year, month, day, hour, minute and second ). آنها برای اینکه این اسم را به خاطر بسپارند، قدم زنان میگویند "gen why emm dee aich emm ess". من عادت مسخره ای دارم که در آن هر چیزی را به همان شکلی که نوشته شده میخوانم، پس من شروع کردم به گفتن "gen-yah-mudda-hims.". بعدها این مفهوم توسط جمعی از طراحان و آنالیزورها به همین اسم نامیده شد، و ما هنوز هم به درآوردن این صدای احمقانه ادامه میدهیم. از آنجایی که این برای ما مثل یک شوخی به حساب میآمد، برای ما بانمک بود. بانمک باشد یا نباشد، ما داریم اسم گذاری ضعیف را تحمل میکنیم. برنامه نویسهای جدید ما نیازمند این هستند که این مفهوم را برایشان توضیح دهیم و آنها در مورد دلیل در آوردن این صداهای احمقانه به جای استفاده از قوانین صریح و کلمات بامعنای انگلیسی صحبت میکنند.مقایسه کنید:
142 |
143 |
144 | ```java
145 | class DtaRcrd102 {
146 | private Date genymdhms;
147 | private Date modymdhms;
148 | private final String pszqint = “102”;
149 | /\* _... \*_/
150 | }
151 | ```
152 |
153 | با
154 |
155 | ```java
156 | class Customer {
157 | private Date generationTimestamp;
158 | private Date modificationTimestamp;
159 | private final String recordId = "102";
160 | /\* _... \*_/
161 |
162 | }
163 | ```
164 |
165 |
166 | مکالمه عاقلانه اکنون امکان پذیر است:
167 |
168 | “Hey, Mikey, take a look at this record! The generation timestamp is set to tommorrow’s date! How can that be?"
169 |
170 | ## از اسامی قابل جستجو استفاده کنید
171 |
172 | اسامی تک حرفی و ثابتهای عددی این مشکل را دارند که در متن قابل پیداکردن نیستند.احتمالا پیدا کردن MAX\_CLASSES\_PER\_STUDENT در یک متن راحت است، اما مثلا پیدا کردن عدد 7 در یک متن طولانی، سخت و زمان بر است. جستجوها ممکن است اعداد دیگری را نیز برای شما پیدا کنند، مثل قسمتهای عددی اسم فایلها،ثابتهای توابع دیگر و در عبارات گوناگونی که از اعداد با اهداف متفاوتی استفاده میکنند. وقتی یک عدد طولانی استفاده میکنید، ممکن است شخصی رقمهایی را سهوا جابجا کند و همزمان این عدد از جستجوی شما فرار میکند. برای مثال، حرف e ضعیف ترین حرف ممکن برای نامگذاری یک متغیر برای برنامه نویسی است که نیازمند جستجو کردن است. چون این حرف پرکاربردترین حرف در زبان انگلیسی است و در هر عبارتی یافت میشود و باعث میشود حین جستجو هر متنی را که در هر برنامه ای وجود دارد ببینید.
173 |
174 | در این راستا در هر کدی، نامهای طولانیتر، بر نامهای کوتاهتر برتری دارند و نامهای قابل جستجو بر ثابتها. به نظر من نامهای تکحرفی تنها میتوانند به عنوان متغیرهای محلی در متدهای کوتاه استفاده شوند. **طول یک نام باید با دامنه استفاده آن مطابقت داشته باشد.** اگر ممکن است از یک متغیر در چندین محل از یک کد استفاده کنید، ضروری است که یک اسم جستجو-دوست (search-
175 | friendly)داشته باشید. یکبار دیگر مقایسه کنید.
176 |
177 |
178 | ```java
179 | for (int j=0; j<34; j++) {
180 | S+= (t[j]*4)/5;
181 | }
182 | ```
183 |
184 | با
185 |
186 | ```java
187 | int realDaysPerIdealDay = 3;
188 | const int WORK_DAYS_PER_WEEK = 5;
189 | int sum = 0;
190 | for (int j=0; j
198 | به sum دقت کنید، این اسم کاملا مناسب نیست، اما حداقل قابل جستجو کردن است. نوشتن کد با این نامگذاری ها شاید کمی طولانی تر باشد، اما این را هم در نظر داشته باشید که پیدا کردن WORK_DAYS_PER_WEEK راحت است زیرا فقط 5 بار از آن استفاده شده.
199 |
200 | ## از رمزگذاری خودداری کنید
201 |
202 | ما به اندازه کافی از رمزنگاریها برای زیاد کردن دردسرمان استفاده میکنیم، لطفا آن را از چیزی که هست بیشتر نکنید.نامهای رمزگذاری شده به سادگی قابل تلفظ نیستند و برای توسعه دهندگان جدید دردسر ایجاد میکنند،زیرا هر کارمند جدید باید زبان رمزنگاری شما را بیاموزد که خود باعث فشار روحی زیادی است.
203 |
204 | ### نمادگذاری مجارستانی
205 |
206 | در روزهای قبل، وقتی روی زبانهای name-length-challenged کار میکردیم، این امر را با پشیمانی و بخاطر ضرورت نقض کردیم. fortran رمزگذاری را اجبار میکرد. نسخههای اولیه BASIC فقط یک حرف به اضافه یک رقم را مجاز میکرد. HungarianNotation (HN) این مرحله را به سطح کاملا جدیدی رساند.
207 |
208 | و HN در Windows C API بسیار مهم به حساب میآمد،هنگامی که همه چیز یک دسته صحیح یا یک نشانگر طولانی یا یک Voidpointer یا یکی از چندین نوع "رشته" (با کاربردها و ویژگیهای مختلف) بود. کامپایلر نوع متغیرهای ورودی را بررسی نمیکرد، بنابراین برنامه نویسان برای کمک به آن در به خاطر سپردن نوع دادهها نیاز به عصا داشتند.
209 |
210 | در زبانهای مدرن سیستمهای بسیار غنیتری داریم و کامپایلرها میتوانند به خاطر بیاورند که هر داده ای از چه نوع است.گذشته از این موضوع،گرایش به کلاسهای کوچکتر و عملکردهای کوتاه تر نیز وجود دارد تا افراد معمولا بتوانند مکان اعلام هر متغیری که میخواهند را ببینند. برنامهنویسان جاوا نیازی به رمزگذاری ندارند.نوع اشیا مشخص است و محیطهای ویرایش به گونه ای پیشرفت کردهاند که یک خطای نوع را قبل از اینکه بتوانید برنامه را کامپایل کنید،تشخیص میدهند.
211 |
212 | ### پیشوندهای متغیر
213 |
214 | شما دیگر نیازی به پیشوند m_ در متغیرهای محلی(member variable) ندارید. کلاسها و توابع شما باید بهقدری کوچک باشند که نیازی به آنها نباشد و شما باید از یک محیط ویرایش استفادهکنید که اعضا را برجسته و یا رنگی و آنها را متمایز کند.
215 |
216 |
217 | ```java
218 | public class Part {
219 | private String m_dsc; // The textual description
220 | void setName(String name) {
221 | M_dsc = name;
222 | }
223 | }
224 | ```
225 |
226 | ```java
227 | public class Part {
228 | String description;
229 | void setDescription(String description) {
230 | this.description = description;
231 | }
232 | }
233 | ```
234 |
235 |
236 | علاوه بر این،افراد به سرعت یاد میگیرند که پیشوند ( یا پسوند) را نادیده بگیرند تا بخش بامعنای نام را ببینند. هرچه آن را بیشتر بخوانند، کمتر the را میبینند.در نهایت پیشوندها به صورت تصادفی دیده می شوند و نشانگر کد قدیمی تر هستند.
237 |
238 | ### واسطها (interface) و پیادهسازیها
239 |
240 | گاهی اوقات مورد خاصی برای رمزگذاری است. به عنوان مثال، میگویند شما در حال ساخت یک ABSTRACT FACTORY برای ایجاد شکلها هستید. این factory یک واسط خواهد بود و توسط یک کلاس concrete (کلاسی که همه متدها را پیادهسازی کند) پیادهسازی خواهد شد. چه اسمی باید برای انها بگذاریم؟ IShapeFactions و ShapeFective؟ من ترجیح میدهم واسط را بدون آراستگی رها کنم. پیشوند i، که در میان میراث (legacy) این روزها معمول است، در بهترین حالت حواس پرتی و در بدترین اطلاعات اضافی است. من نمی خواهم که کاربرانم بدانند که من interface خود را به آنها ارائه میکنم. من فقط میخواهم آنها بدانند که این یک shape factoryاست. بنابراین اگر من باید یا interface یا implementation را رمزگذاری کنم، implementation را انتخاب میکنم. نام ان را ShapeFactoryImp، یا حتی CShapeFective ناخوشایند بگذارید، رمزگذاری واسطها ضروری است.
241 |
242 | ## از نگاشت ذهنی خودداری کنید
243 |
244 | خوانندگان نباید مجبور باشند که نام انتخابی شما را در ذهنشان به نام دیگری که از قبل میشناسند ترجمه کنند. این مشکل معمولاً ناشی از انتخابی است که نه از دامنه اصطلاحات مسئله استفاده کرده است و نه از دامنه واژههای راه حل.
245 |
246 | این مشکل مربوط به نام متغیرهای تک حرفی است. مطمئناً یک دامنه نام برای شمارشگر حلقه ای که کوچک باشد و هیچ نام دیگری با آن به تناقض نرسد، i یا j یا k است (هرچند هیچگاه l نامگذاری نمیشود). دلیل این امر آن است که این نامهای تک حرفی از قدیم برای شمارشگر حلقه استفاده شده اند. با این وجود، در بیشتر زمینههای دیگر، یک نام تک حرفی انتخاب بدی است. این انتخاب تنها یک جایگزین است که خواننده باید در ذهن خود آن را به مفهومی واقعی نگاشت کند. دلیلی بدتر از اینکه a و b قبلاً استفاده شده بود برای استفاده از نام c نمیتواند وجود داشته باشد.
247 |
248 | به طور کلی برنامه نویسان افراد بسیار باهوشی هستند. افراد باهوش گاهی دوست دارند با نشان دادن تواناییهای ذهنی خود، هوشمندی خود را به معرض نمایش بگذارند. از این گذشته، اگر با اطمینان بتوانید به یاد داشته باشید که r نسخه کوتاه شده از آدرس url با میزبان و شمای حذف شده است، پس مشخصا باید بسیار باهوش باشید.
249 |
250 | یک تفاوت بین یک برنامه نویس هوشمند و یک برنامه نویس حرفه ای در این است که حرفه ای میفهمد که شفافیت پادشاه است. حرفهای ها به خوبی از تواناییهای خود برای نوشتن کدی که دیگران میتوانند آن را درک کنند استفاده میکنند.
251 |
252 | ## نام کلاسها
253 |
254 | کلاسها و اشیاء باید دارای نام یا عبارت اسمی مانند Customer، WikiPage، Account و AdressParser باشند. از کلماتی مانند Manager، Processor، Data یا Info برای نام کلاس خودداری کنید. **نام کلاس نباید یک فعل باشد.**
255 |
256 | ## نام متدها
257 |
258 | اسم متدها باید دارای فعل یا عبارت فعلی مانند postPayment، DeletePage یا save باشند. Accessorها، mutator ها و predicate ها را باید با مقدار خودشان نامگذاری کرد و با در نظر گرفتن استانداردهای javabean، با پیشوندهای get، set و is نام گذاری کرد.
259 |
260 |
261 | ```java
262 | String name = employee.getName();
263 | customer.setName("mike")
264 | if (paychech.isPosted()) ...
265 | ```
266 |
267 |
268 |
269 | زمانی که متدهای سازنده (constructor) زیاد شوند، از factory method های static با نام هایی که متغیرها را توصیف کنند استفاده کنید. به عنوان مثال:
270 |
271 |
272 | ```java
273 | Complex FulcrumPoint = Complex.FromRealNumber(23.0);
274 | ```
275 |
276 |
277 |
278 | به طور کلی بهتر است از :
279 |
280 |
281 | ```java
282 | Complex FulcrumPoint = new Complex(23.0);
283 | ```
284 |
285 |
286 |
287 | در نظر بگیرید که با private کردن متدهای سازنده مربوطه، بر استفاده از آنها تاکید کنید.
288 |
289 | ## بانمک نباشید
290 |
291 | اگر نامها خیلی هوشمندانه باشند، فقط در ذهن افرادی که از نظر شوخ طبعی به نویسنده شبیه هستند، و فقط تا زمانی که این افراد این شوخی را به خاطر میآورند، ماندگار میشوند. آیا آنها میدانند تابعی به نام HolyHandGrenade قرار است چه کاری انجام دهد؟ مطمئنا، بانمک است، اما شاید در این حالت DeleteItems نام بهتری باشد. شفافیت را در برابر سرگرمی انتخاب کنید.
292 |
293 | بامزگی در کد اغلب به شکل محاوره یا زبان عامیانه ظاهر میشود. به عنوان مثال، از نام whack به جای kill استفاده نکنید. از شوخی های خاص در یک فرهنگ مانند eatMyShors به جای abort استفاده نکنید.
294 |
295 | آن چیزی را بگویید که منظورتان است. منظورتان همان چیزی است که میگویید.
296 |
297 | ## برای هر مفهوم یک کلمه انتخاب کنید
298 |
299 | یک کلمه را برای یک مفهوم مجزا انتخاب کنید و به آن بچسبید. به عنوان مثال fetch ،retrieve و get به عنوان نام متدهای معادل در کلاسهای مختلف گیج کننده است. چگونه به یاد خواهید آورد که نام کدام متد در کدام کلاس ذکر شده است؟ متأسفانه، شما اغلب باید به خاطر داشته باشید كه كدام شركت، گروه یا فرد كتابخانه یا كلاس را نوشته است تا بتوانید به یاد آورید که كدام اصطلاح استفاده شده است. در غیر این صورت، شما زمان بسیار زیادی را صرف مرور در header ها و نمونه کدهای قبلی میکنید.
300 |
301 | محیطهای ویرایش مدرن مانند Eclipse و IntelliJ سرنخهای حساس به متن(context-sensitive clues) مانند لیست متدهایی که میتوانید در یک شی خاص فراخوانی کنید را فراهم میکنند. اما توجه داشته باشید که این لیست معمولاً comment هایی را که شما در مورد نام تابع و لیست پارامترهای خود نوشتید به شما نمیدهد. خوش شانس باشید، بتواند نام پارامترها را از توصیف توابع به شما ارائه دهد. اسامی توابع باید مستقل واضح باشند، و آنها باید سازگار باشند تا شما بتوانید متد صحیح را بدون جستجوهای اضافی انتخاب کنید.
302 |
303 | به همین ترتیب، داشتن یک Controller و یک manager و یک driver در یک پایگاه کد گیجکننده است. تفاوت اساسی بین DeviceManager و ProtocolController چیست؟ چرا هر دو Controller نیستند یا هر دو manager نیستند؟ آیا آن دو واقعاً driver هستند؟ این نامها باعث میشود که شما توقع دو شی که از نظر نوع و کلاس هایشان بسیار متفاوت هستند را داشته باشید.
304 |
305 | واژه نامه نامتناقض یک لطف بزرگ به برنامه نویسانی است که باید از کد شما استفاده کنند.
306 |
307 | ## با ایهام ننویسید
308 |
309 | از استفاده از یک کلمه برای دو منظور مختلف خودداری کنید. استفاده از یک اصطلاح یکسان برای دو ایده متفاوت در اصل یک ایهام است.
310 |
311 | اگر از قانون "یک کلمه برای هر مفهوم" پیروی کنید، میبینید که بسیاری از کلاسها مثلا یک متد add دارند. تا زمانی که لیست پارامترها و مقادیر برگشتی در متدهای مختلف add معنایی معادل داشته باشند، همه چیز خوب است.
312 |
313 | اما ممکن است شخص تصمیم بگیرد از کلمه add وقتی که منظورش افزودن نیست استفاده کند و تنها بخواهد سازگاری ایجاد کند. بیایید بگوییم که ما کلاسهای زیادی داریم که در آنها با اضافه کردن یا ملحق کردن دو مقدار موجود، مقدار جدیدی ایجاد میشود. حال فرض کنیم ما در حال نوشتن یک کلاس هستیم که متدی در آن است که یک پارامتر را درون یک مجموعه میگذارد. آیا باید این متد را add بنامیم؟ ممکن است به این دلیل که متدهای add دیگری داریم، سازگار به نظر برسد، اما در این حالت، مفاهیم متفاوت هستند، بنابراین باید به جای آن از اسمی مانند insert یا append استفاده کنیم. نامیدن متد جدید به add ایهام ایجاد میکند.
314 |
315 | هدف ما، به عنوان نویسنده، این است که کدهای خود را تا جایی که میتوانیم قابل درک کنیم. ما میخواهیم کد ما به جای اینکه یک مطالعه عمیق و مفهومی باشد، سریع خوانده شود. ما میخواهیم از مدل رایج کتابهای کاغذی استفاده کنیم که به موجب آن نویسنده وظیفه دارد منظور خود را شفاف سازد و نه مدل دانشگاهی كه در آن محققان وظیفه دارند مفاهیم و معانی را از مقالهها استخراج کنند.
316 |
317 | ## از دامنه واژگان مربوط به راه حل استفاده کنید
318 |
319 | به یاد داشته باشید افرادی که کد شما را میخوانند، برنامه نویس هستند. بنابراین از اصطلاحات علوم کامپیوتر، نام الگوریتم ها، نام الگوها، اصطلاحات ریاضی و موارد دیگر استفاده کنید. عاقلانه نیست که هر نام را از دامنه صورت مسئله انتخاب کنیم زیرا ما نمیخواهیم همکاران ما مجبور به فرار از مشتری ای باشند که چون هر مفهوم را با نام دیگری میشناسد، معنی هر کلمه را می پرسد.
320 |
321 | نام AccountVisitor برای یک برنامه نویس که با الگوی VISITOR آشنا است بسیار پر معنی است. چه برنامه نویسی نمی داند JobQueue چیست؟ موارد فنی بسیار زیادی وجود دارد که برنامه نویسان باید انجام دهند. انتخاب نامهای فنی برای آن موارد معمولاً مناسب ترین روش است.
322 |
323 | ## از دامنه واژگان صورت مسئله استفاده کنید
324 |
325 | وقتی "اصطلاح برنامه نویسی" برای کاری که انجام میدهید وجود ندارد، از دامنه صورت مسئله برای انتخاب نام استفاده کنید. حداقل برنامه نویسی که کد شما را نگهداری میکند می تواند از یک متخصص دامنه سوال کند که منظور چیست.
326 |
327 | جدا کردن دامنه راه حل و صورت مسئله بخشی از کار یک برنامه نویس و طراح خوب است. کدی که ارتباط بیشتری با مفاهیم مربوط به صورت مسئله دارد باید دارای نامهایی باشد که از دامنه صورت مسئله گرفته شده است.
328 |
329 | ## ساختارهای با معنی اضافه کنید
330 |
331 | تنها چند نام وجود دارند که به خودی خود معنی دارند و اکثر نامها به خودی خود بی معنی اند. درعوض، باید با قرار دادن آنها در کلاسها، توابع یا مکانهای نامگذاری شده، خوانندتان را در جریان وضوع قرار دهید. وقتی همه موارد دیگر شکست بخورد، ممکن است استفاده از پیشوند برای نام به عنوان آخرین راه حل اساسی مورد استفاده قرار گیرد.
332 | تصور کنید که متغیرهایی با اسامی firstName،lastName ،street ،houseNumber ،city ،state و zipcode دارید. آنها به طور واضح در کنار هم یک آدرس را تشکیل میدهند. اما اگر متغیر state را به تنهایی در یک تابع دیدید چه؟ آیا به طور خودکار استنباط میکنید که این متغیر بخشی از یک آدرس است؟
333 | میتوانید پیشوندهایی را به متن اضافه کنید: addrFirstName ،addrLastName ،addrState و غیره. حداقل خوانندگان خواهند فهمید که این متغیرها بخشی از یک ساختار بزرگتر هستند. البته یک راه حل بهتر ایجاد کلاس با نام Address است. سپس، حتی کامپایلر هم میداند که متغیرها متعلق به یک ساختار بزرگتر هستند.
334 | متد موجود در Listing 2-1 را در نظر بگیرید. آیا متغیرها به یک ساختار معنی دار تر نیاز دارند؟ نام تابع تنها بخشی از ساختار، و الگوریتم بقیه را ارائه میدهد. پس از خواندن این تابع، میبینید که سه متغیر، number، verb و pluralModifier بخشی از پیام "guess statistics" هستند. متأسفانه، مفهوم باید حدس زده شود. وقتی برای اولین بار به متد نگاه میکنید، معنی متغیرها مبهم است.
335 |
336 |
337 | Listing 2-1
338 | Variables with unclear context.
339 |
340 | ```java
341 | private void printGuessStatistics(char candidate, int count)
342 | {
343 | String number;
344 | String verb;
345 | String pluralModifier;
346 | if (count == 0){
347 | number = "no";
348 | verb = "are";
349 | pluralModifier = "s";
350 | } else if (count == 1) {
351 | number = "1";
352 | verb = "is";
353 | pluralModifier = "";
354 | } else {
355 | number = Integer.toString(count);
356 | verb = "are";
357 | pluralModifier = "s";
358 | }
359 | String guessMessage = String.format( "There %s %s %s%s", verb, number, candidate, pluralModifier );
360 | print(guessMessage);
361 | }
362 | ```
363 |
364 |
365 | این تابع کمی طولانی است و از متغیرها در کل آن استفاده می شود. برای تقسیم تابع به قطعات کوچکتر باید یک کلاس GuessStatisticsMessage ایجاد کنیم و سه فیلد متغیر این کلاس را بسازیم. بدین ترتیب یک متن واضح را برای سه متغیر فراهم می کنیم. آنها به طور قطع بخشی از GuessStatisticsMessage هستند. بهبود زمینه همچنین به الگوریتم اجازه می دهد تا با شکستن شدن به توابع کوچکتر، بسیار تمیزتر شود.
366 |
367 |
368 | Listing 2-2
369 | Variables have a context.
370 |
371 | ```java
372 | public class GuessStatisticsMessage{
373 | private String number;
374 | private String verb;
375 | private String pluralModifier;
376 | public String make(char candidate, int count){
377 | createPluralDependentMessageParts(count);
378 | return String.format( "There %s %s %s%s", verb, number, candidate, pluralModifier );
379 | }
380 | private void createPluralDependentMessageParts(int count{
381 | if (count == 0){
382 | thereAreNoLetters();
383 | } else if (count == 1) {
384 | thereIsOneLetter();
385 | } else {
386 | thereAreManyLetters(count);
387 | }
388 | }
389 | private void thereAreManyLetters(int count) {
390 | number = Integer.toString(count);
391 | verb = "are"; pluralModifier = "s";
392 | }
393 | private void thereIsOneLetter() {
394 | number = "1";
395 | verb = "is";
396 | pluralModifier = "";
397 | }
398 | private void thereAreNoLetters() {
399 | number = "no";
400 | verb = "are";
401 | pluralModifier = "s";
402 | }
403 | }
404 | ```
405 |
406 |
407 | ### متن(context) بیخود اضافه نکنید.
408 | در یک برنامه فرضی به نام “Gas Station Deluxe”، این که هر کلاس با پیشوند GSD شروع شود ایده بدی است. صادقانه بگویم، شما با این کار در برابر ابزارهای خود می ایستید. G را تایپ می کنید و کلید تکمیل را فشار می دهید و با یک لیست بلند بالا از تمام کلاس های سیستم مواجه می شوید. این عاقلانه است؟ چرا راه کمک را برای IDE دشوار میکنید؟
409 | به همین ترتیب، بیایید بگوییم که شما یک کلاس به نام MailingAddress را در ماژول حسابداری GSD نوشته اید و نام آن را GSDAccountAddress گذاشتید. بعداً، برای تماس با مشتری خود به یک آدرس پستی نیاز دارید. آیا از GSDAccountAddress استفاده می کنید؟ آیا این نام مناسب به نظر می رسد؟ 10 تا از 17 کاراکتر زائد یا بی ربط هستند.
410 | معمولا تا زمانی که نامهای کوتاهتر واضح باشند، از نامهای طولانی تر بهتر هستند. هیچ متنی بیشتر از آن چیزی که لازم است، به یک نام اضافه نکنید.
411 | نام های accountAddress و customerAddress نام های خوبی برای نمونه های کلاس Address هستند اما برای نام کلاس ها مناسب هستند. Address یک نام خوب برای یک کلاس است. اگر نیاز به تفکیک بین آدرس های MAC، آدرس پورت ها و آدرس های وب داشته باشم، ممکن است PostalAddress، MAC و URI را در نظر بگیرم. نامهای به دست آمده دقیق تر هستند، و این، هدف همه نامگذاری ها است.
412 |
413 | ## سخن پایانی
414 |
415 | سختترین کار در انتخاب نامهای خوب این است که به مهارتهای توصیفی خوب و پیشینه فرهنگی مشترک نیاز دارد. این مسئله یک مسئله فنی، تجاری یا مدیریتی نیست بلکه یک موضوع آموزشی است. در نتیجه بسیاری از افراد یاد نمیگیرند که این کار را به درستی انجام دهند.
416 | مردم همچنین از ترس اینکه برخی از توسعه دهندگان دیگر مورد تخریب قرار گیرند، از تغییر نام چیزها میترسند. ما این ترس را نداریم و وقتی اسم ها به چیز بهتری تغییر میکنند واقعاً سپاسگزاریم. بیشتر مواقع ما واقعا نام کلاسها و متدها را به خاطر نمیآوریم. ما از ابزارهای مدرن برای کلنجار رفتن با جزئیاتی از این دست استفاده میکنیم تا بتوانیم تمرکز خود را بر این مسئله بگذاریم که آیا کد باید مانند پاراگرافها و جملات خوانده شود، یا شبیه به جدولها و ساختار دادهها (یک جمله همیشه بهترین راه برای نمایش دادهها نیست). احتمالاً وقتی چیزها را تغییر نام دهید، دقیقاً مانند هر بهبود دیگری در کد، افراد را شگفت زده خواهید کرد. اجازه ندهید که این مسئله شما را در مسیرتان متوقف کند.
417 | برخی از این قوانین را دنبال کنید و ببینید آیا خوانایی کد خود را بهبود میبخشید یا خیر. اگر کد شخص دیگری را نگهداری میکنید، برای حل این مشکلات از ابزارهای refactoring استفاده کنید. در کوتاه مدت نتیجه را می بینید و درازمدت به افزایش بهبودها ادامه میدهد.
418 |
419 |
420 | * [فصل بعد](../3_Functions(completed)/3_Functions.md)
421 |
422 | * [فصل قبل](../1_Clean_Code(completed)/clean-code.md)
--------------------------------------------------------------------------------
/1_Clean_Code(completed)/clean-code.md:
--------------------------------------------------------------------------------
1 |
2 |
3 | # فصل یک - کد تمیز
4 |
5 |
6 |
7 | 
8 |
9 |
10 |
11 | به دو دلیل شما در حال خواندن این کتاب هستید: یک: یک برنامهنویس هستید. دو: میخواهید برنامهنویس بهتری شوید. خوب است. ما به برنامهنویسهای بهتر نیاز داریم.
12 |
13 | در کتاب پیشرو، میخواهیم راجع به خوب برنامه نوشتن صحبت کنیم. این کتاب، سرشار از کدهای مختلفی است که میخواهیم از جهات متفاوتی آنها را بررسی کنیم. این کدها را از بالا به پایین، و از درون به بیرون بررسی خواهیم کرد و در انتهای کار، شناخت بهتری از کد خواهیم داشت. علاوه بر این، قادر خواهیم بود کد خوب را از کد بد تشخیص دهیم. قادر به نوشتن یک کد خوب خواهیم بود و خواهیم دانست که چگونه یک کد بد را به یک کد خوب تبدیل کنیم.
14 |
15 | ## کد همیشه وجود خواهد داشت
16 |
17 | ممکن است فردی معتقد باشد یک کتاب پیرامون کد بدرد سالها پیش میخورد و امروزه کد مسئله اصلی نیست. بلکه ما باید نگران مدلها و نیازمندیها باشیم. بعضی از افراد معتقدند که به پایان دوران کدنویسی نزدیک هستیم. به زودی تمام کدها به جای نوشته شدن توسط برنامهنویسها، توسط کامپیوترها تولید خواهند شد. کسب و کارهای مختلف، نرمافزارهای موردنیازشان را از طریق خصوصیات فنی تولید خواهند کرد و دیگر به برنامهنویسان نیازی نخواهد بود.
18 |
19 | این حرف کاملا پوچ و خارج از منطق است. ما هرگز از کد فارغ نخواهیم شد، زیرا کد نمایانگر جزییات نیازمندیهاست. در بعضی سطوح، نمی توان جزییات را نادیده گرفت یا خلاصه کرد. آنها باید کاملا مشخص باشند و مشخص کردن نیازمندیها با چنان جزییاتی که یک ماشین بتواند آنها را اجرا کند *برنامهنویسی* است. این خصوصیات فنی نیز *کد* میباشد.
20 |
21 | انتظار دارم که سطح انتزاع زبانها به گسترش خود ادامه دهد. همچنین انتظار دارم که تعداد زبانهای مختص دامنه(domain-specific- زبانهایی که برای محدوده خاصی از مسائل ساخته شده اند) رشد پیدا کند. این مسئله خوب است. اما باعث حذف کد نمیشود.
22 |
23 | در واقع تمام مشخصات نوشته شده در این زبان های سطح بالا و مختص دامنه، "کد" خواهند بود! این کد همچنان نیاز دارد که سختگیرانه، دقیق، و بسیار رسمی و جزیی باشد تا یک ماشین بتواند آن را بفهمد و اجرا کند. گروهی که فکر میکنند که یک روز کد میتواند ناپدید شود شبیه به ریاضی دانانی هستند که امید دارند یک روز یک تعریف یا فرمول ریاضیای را کشف کنند که نیاز نداشته باشد که رسمی باشد. آنها امید دارند که یک روز راهی برای ساختن ماشینهایی کشف کنند که میتواند چیزی را که ما میخواهیم به جای چیزی که میگوییم انجام دهند. این ماشینها باید قادر باشند که آنقدر خوب ما را بفهمند که نیازمندیهای خاص و مبهم را به برنامههای کاملا قابل اجرا که با دقت، آن نیازمندیها را مرتفع میکنند، ترجمه کنند. این اتفاق هیچگاه نمیافتد. حتی انسانها با تمام بینش و خلاقیتشان قادر به ساخت موفق سیستمها از احساسات مبهم مشتریان نیستند.
24 |
25 | در واقع اگر نظم نیازمندیهای مشخصات چیزی به ما آموخته باشد، آن این است که نیازمندیهای دقیق توصیف شده به اندازه کد رسمی هستند و میتوانند به عنوان تستهای قابل اجرایی از کد عمل کنند! بهخاطر داشته باشید که کد زبانی است که در نهایت با آن، نیازمندیها را بیان میکنیم. ممکن است ما زبانهایی بسازیم که به نیازمندیها نزدیکتر باشند. ممکن است ما ابزارهایی بسازیم که به ما در براورده کردن و سرهمبندی این نیازمندیها با ساختارهای رسمی کمک کنند. اما هرگز دقت لازم را حذف نمیکنیم. پس کد وجود دارد.
26 |
27 | ### کد بد
28 |
29 | اخیرا یک پیشگفتار از کتاب Implementation Patterns نوشته Kent Beck خواندهام. او میگوید :"... این کتاب بر مبنای یک فرضیه ضعیف بنا شده است: این که کد خوب مهم است ..." یک فرضیه ضعیف؟ من مخالفم! من فکر میکنم آن فرضیه یکی از بیشمار فرضیههای گسترش یافته، مورد حمایت، و پربار در حرفه ماست(و فکر میکنم Kent این را میداند.) ما میدانیم که کد خوب مهم است زیرا ما زمان زیادی ناچار بودیم با نبود آن کنار بیاییم.
30 |
31 | من یک شرکت را میشناسم که در اواخر دهه 80 یک برنامه killer نوشته است. این برنامه خیلی معروف بود و تعداد زیادی از افراد حرفه ای آن را خریده و استفاده کردند. اما پس از آن، چرخه انتشار شروع به کش آمدن کرد. از یک انتشار تا انتشار بعدی باگها تعمیر نشدند. زمان بارگذاری افزایش یافت و crash افزایش یافت. من به خاطر دارم که یک روز من آن محصول را با ناامیدی پاک کردم و دیگر هیچگاه از آن استفاده نکردم. مدت کمی پس از آن، آن شرکت از صحنه تجارت خارج شد. دو دهه بعد من یکی از اولین کارکنان آن شرکت را دیدم و از او پرسیدم که چه اتفاقی افتاد. آن پاسخ، ترسهای من را تایید کرد. آنها در عرضه محصول به بازار عجله کرده بودند و حجم عظیمی از کد را درست کرده بودند. هرچه آنها ویژگیهای بیشتر و بیشتری اضافه کردند، کد بدتر و بدتر شد تا زمانی که دیگر آنها نتوانستند آن را مدیریت کنند.
32 |
33 | این کد بد بود که آن شرکت را نابود کرد. آیا تا کنون توسط یک کد بد به مشکل خورده اید؟ اگر شما یک برنامهنویس با هر سطح از تجربه باشید آنگاه شما در مواقع زیادی این مانع را احساس کردید.حتی یک نام برای آن داریم. ما آن را به سختی راه رفتن(wading) صدا میکنیم.
34 |
35 | ما در طول یک کد بد به سختی راه میرویم. ما در باتلاقی از خاربنهای در هم تنیده و تلههای مخفی تقلا میکنیم. ما برای یافتن مسیر، به امید چند اشاره، چند سر نخ از اینکه چه اتفاقی در شرف وقوع است تقلا میکنیم اما تمام چیزی که میبینیم کدهای بی معنی بیشتر و بیشتر است. قطعا شما با کدهای بد به مشکل برخورده اید. خب چرا آنها را نوشتید؟ میخواستید سریع پیش بروید؟ عجله داشتید؟احتمالا بله. احتمالا شما احساس کردید که زمان کافی برای انجام یک کار خوب ندارید؛ رئیس شما از شما عصبانی میشود اگر برای تمیز کردن کدتان زمان هدر دهید. احتمالا شما از کار کردن بر روی این برنامه خسته شده بودید و میخواستید تمام شود. یا شاید شما به کارهای ناتمام بقیه کارمندانی که به آنها قول داده بودید که کار را انجام میدهید نگاه کردید و متوجه شدید که نیاز دارید تا ماژولها را به یکدیگر بچسبانید تا بتوانید کارها را به مرحله بعد ببرید. همه ما این کارها را انجام دادیم. همه ما به ریخت و پاشی که درست کرده بودیم نگاه کردیم و سپس انجام آن را به روز دیگر موکول کردیم. همه ما آسودگی ناشی از کار کردن برنامه نامرتب خودمان را حس کردیم و تصمیم گرفتیم که انجام کار شلخته بهتر از هیچ کاری است.همه ما گفتیم بعدا که برمیگردیم، آن را تمیز میکنیم. قطعا در آن روزها ما قانون LeBlanc را نمیشناختیم : بعدا یعنی هیچوقت.
36 |
37 | ### هزینه کلی مالک یک شلختگی بودن
38 |
39 | اگر بیش از دو یا سه سال است که برنامهنویس بوده اید، احتمالاً با کد کثیف شخص دیگری معطل مانده اید. میزان معطل بودن می تواند قابل توجه باشد. طی یک بازه زمانی یک یا دو ساله، تیمهایی که در ابتدای یک پروژه بسیار سریع در حال حرکت بودند، خود را در حال حرکت با سرعت حلزونی میبینند. هر تغییری که در کد ایجاد کنند، دو یا سه قسمت دیگر کد را خراب می کند. تغییر ندادن مهم است. هرگونه افزودن یا تغییر در سیستم مستلزم این است که گره خوردگیها، پیچ و تابها و مشکلات "درک شوند" تا بتوانید تعداد بیشتری گره و پیچ و تاب اضافه کنید. با گذشت زمان شلختگی بسیار بزرگ و عمیق و بسیار بلند میشود، به گونه ای که نمی توان آنها را تمیز کرد. اصلاً راهی نیست. با ساخته شدن شلختگی، بهرهوری تیم همچنان رو به کاهش میرود، و در نهایت به صفر نزدیک میشود. با کاهش بهره وری، مدیریت تنها کاری که میتواند را انجام میدهد؛ آنها به امید افزایش بهره وری کارکنان بیشتری را به این پروژه اضافه میکنند. اما آن کارکنان جدید سیستم را نمیشناسند. آنها تفاوت بین تغییری را که منطبق با هدف طراحی انجام میشود و تغییری که هدف طراحی راناکارآمد میکند، نمی دانند. علاوه بر این، آنها و هر کس دیگری که در تیم حضور دارند، تحت فشارهای هولناکی برای افزایش بهره وری قرار دارند. بنابراین همه آنها بیشتر و بیشتر باعث شلختگی میشوند و باعث میشوند که بازدهی هر چه بیشتر به سمت صفر برسد. (شکل 1-1 را ببینید.)
40 |
41 |
42 |
43 |
44 |
45 |
46 | ### طراحی مجدد بزرگ در اسمان
47 |
48 | سرانجام تیم شورش میکند. آنها به مدیریت اطلاع میدهند که نمیتوانند بر مبنای این کد نفرت انگیز محصولی را توسعه دهند. آنها خواستار طراحی مجدد هستند. مدیریت نمیخواهد که منابع را صرف طراحی مجدد پروژه کند، اما آنها نمیتوانند انکار کنند که بهره وری وحشتناک است. سرانجام آنها به خواستههای توسعه دهندگان تن میدهند و اجازه انجام طراحی مجدد بزرگ در اسمان را میدهند.
49 |
50 | یک تیم جدید قوی انتخاب شده است. همه دوست دارند در این تیم حضور داشته باشند زیرا این یک پروژه Greenfield است. آنها دوباره شروع به کار میکنند و چیزی زیبا را ایجاد میکنند. اما فقط بهترینها و درخشان ترینها برای تیم قوی انتخاب میشوند. همه افراد دیگر باید به حفظ سیستم فعلی ادامه دهند. اکنون دو تیم در رقابت هستند. تیم قوی باید سیستم جدیدی بسازد که هر آنچه را که سیستم قدیمی انجام میدهد انجام دهد. نه تنها این، آنها باید با تغییراتی که به طور مداوم در سیستم قدیمی انجام میشود، به روز باشند. مدیریت تا زمانی که سیستم جدید نتواند کارهایی را که سیستم قدیمی انجام میدهد، انجام دهد، سیستم جدید را جایگزین سیستم قدیمی نخواهد کرد. این رقابت میتواند برای مدت زمان طولانی ادامه یابد. من دیده ام که 10 سال طول کشید. و زمانی که این کار انجام شد، اعضای اصلی تیم قوی مدتها بود که از تیم رفته بودند، و اعضای فعلی خواستار طراحی مجدد سیستم جدید هستند زیرا این سیستم بسیار شلخته است.
51 |
52 | اگر حتی یک بخش کوچک از داستانی را که تعریف کردم تجربه کرده اید، پس میدانید که صرف وقت برای تمیز کردن کد خود صرفاً مقرون به صرفه نیست. این یک کار حرفه ای برای بقا است.
53 |
54 | ### نگرش
55 |
56 | آیا تا به حال آنقدر با شلختگیها کلنجار رفته اید که کاری را که در طی چند ساعت میتوانستید انجام دهید، هفتهها طول بکشد؟ آیا دیده اید که چیزی که میتوانست با تغییر یک خط ایجاد شود، در عوض در تغییر در صدها ماژول مختلف انجام شد؟ این علائم بسیار شایع است. چرا این اتفاق برای کد میافتد؟ چرا کد خوب خیلی سریع به کد بد تبدیل میشود؟ توضیحات زیادی برای آن داریم. ما شاکی هستیم که نیازمندیها به گونه ای تغییر یافته که طرح اصلی را خنثی میکند. ما ناراحتیم که برنامهها برای انجام درست کارها بسیار فشرده بود. ما در مورد مدیران احمق و مشتریان عجول و انواع بازاریابیهای بی فایده و ضد عفونی کنندههای تلفنی صحبت میکنیم. اما Dilbert عزیز، مشکل در سرنوشت ما نیست، بلکه در خودمان است. ما غیر حرفه ای هستیم.
57 |
58 | ممکن است پذیرش این حقیقت تلخ، مشکل باشد. چطور ممکن است این شلختگی تقصیر ما باشد؟در مورد نیازمندیها چطور؟ در مورد برنامه چطور؟ در مورد مدیران احمق و انواع بی فایده بازاریابی چطور؟ آیا آنها مقصر نیستند؟ خیر. مدیران و بازاریابان برای دریافت اطلاعاتی که برای وعدهها و تعهدات لازم دارند، به ما نگاه میکنند. و حتی وقتی آنها به ما نگاه نمیکنند، ما نباید از گفتن آنچه که فکر میکنیم شرمنده باشیم. کاربران به ما نگاه میکنند تا تصدیق کنند که ما چگونه سیستم را با نیازمندیها پر میکنیم. مدیران پروژه از ما انتظار دارند که به پیش برد برنامه کمک کنیم. ما عمیقا درگیر برنامه ریزی پروژه هستیم و مسئولیت هرگونه خرابی را به عهده میگیریم. به خصوص اگر این شکستها مربوط به کد بد باشند! "اما صبر کنید!" شما بگویید. "اگر آنچه را که مدیر من میگوید، انجام ندهم، اخراج میشوم." احتمالا نه. اکثر مدیران حقیقت را میخواهند، حتی اگر چنین رفتار نکنند. اکثر مدیران کدهای خوبی میخواهند، حتی وقتی در مورد برنامه وسواس دارند. آنها ممکن است با شور و شوق از برنامهها و نیازمندیها دفاع کنند؛ اما این کار آنهاست این وظیفه شماست که با اشتیاق برابر، از کد دفاع کنید. برای اینکه این مسئله برای شما جا بیفتد، چه میشود اگر شما یک پزشک باشید و یک بیمار داشته باشید که به این دلیل که شستن دستها قبل از عمل جراحی زمان زیادی میبرد، خواستار جلوگیری از این کار احمقانه باشد؟(هنگامی که برای اولین بار در سال 1847 توسط Ignaz Semmelweis به پزشکان توصیه شد دستهای خود را بشویند، این توصیه به دلیل اینکه سر پزشکان خیلی شلوغ بود و وقت نداشتند میان ویزیت بیماران دستهای خود را بشویند رد شد.) به وضوح بیمار رئیس است. و با این وجود پزشک کاملاً باید از انجام عمل خودداری کند. چرا؟ زیرا پزشک بیشتر از بیمار از خطرات بیماری و عفونت اطلاع دارد. این که پزشک مطابق با خواست بیمار عمل کند (حتی اگر مجرمانه نباشد) غیرحرفه ای است. به همین ترتیب غیر حرفه ای است که برنامهنویسان به خواسته مدیرانی که ریسک ایجاد شلختگیها را نمیفهمند تن در دهند.
59 |
60 | ### مسئله بغرنج اصلی
61 |
62 | برنامهنویسان با مجموعه ای از مسائل پایه ای روبرو هستند. همه توسعه دهندگان با بیش از چند سال تجربه میدانند که شلختگیهای قبلی آنها را کند میکند. و با این وجود همه توسعه دهندگان فشار ناشی از ایجاد شلختگی را احساس میکنند زیرا باید به ضرب الاجل برسند. به طور خلاصه، آنها وقت لازم را برای حرکت سریع ندارند! حرفه ایها میدانند که قسمت دوم این مسئله اشتباه است. شما با ایجاد شلختگی به ضرب الاجل نمیرسید. در واقع، شلختگی فورا شما را کند میکند و شما را مجبور میکند که ضرب الاجل را از دست بدهید. تنها راه برای رسیدن به ضرب الاجل- تنها راه سریع پیشبرد کار- این است که همیشه کد را تا حد ممکن تمیز نگه دارید.
63 |
64 | ### هنر کد تمیز؟
65 |
66 | بیایید بگوییم شما معتقد هستید که کد کثیف مانع قابل توجهی است. بیایید بگوییم که شما میپذیرید که تنها راه پیشبرد سریع، تمیز نگه داشتن کدهایتان است. سپس باید از خود بپرسید: "چگونه میتوانم کد تمیز بنویسم؟" اگر نمی دانید تمیز بودن کد چیست، تلاشتان برای نوشتن کد تمیز خوب نیست! خبر بد این است که نوشتن کد تمیز بسیار شبیه به نقاشی کشیدن است. بیشتر ما میدانیم چه زمانی یک تصویر خوب یا بد نقاشی شده است. اما قدرت تشخیص هنر خوب از بد به معنای این نیست که بلدیم چگونه نقاشی کنیم. بنابراین قدرت تشخیص کد تمیز از کد کثیف به این معنی نیست که میدانیم چگونه می توان کد تمیز نوشت! نوشتن کد تمیز مستلزم استفاده منظم از تکنیکهای ظریف بی شماری است که این تکنیکها از طریق به کارگیری حس"پاکیزگی" بکار برده میشود. این "حس کردن کد" مهم است. برخی از ما با آن متولد میشویم. برخی از ما باید برای به دست آوردن آن بجنگیم. نه تنها این امکان را به ما میدهد که ببینیم آیا کد خوب است یا بد، بلکه برای تبدیل کد بد به کد تمیز، استراتژی استفاده از قوانین مان را به ما نشان میدهد. به طور خلاصه، یک برنامهنویس که کد تمیز مینویسد، هنرمندی است که میتواند یک صفحه خالی بگیرد و از طریق یک سری دگرگونیها آن را به یک سیستم با کدگذاری زیبا تغییر دهد.
67 |
68 | ### کد تمیز چیست؟
69 |
70 | احتمالاً به اندازه برنامهنویسها تعریف وجود دارد. بنابراین از برخی از برنامهنویسان بسیار شناخته شده و با تجربه پرسیدم که چه فکر میکنند. Bjarne Stroustrup مخترع زبان C++ و نویسنده The C++ Programming Language: من دوست دارم کد من زیبا و کارآمد باشد. منطق باید سر راست باشد تا پنهان کردن باگها دشوار باشد، وابستگیهای حداقلی برای سهولت در نگهداری، کنترل کامل خطا مطابق با یک استراتژی تکه به تکه و عملکرد نزدیک به بهینه، بگونه ای که مردم را وسوسه نکند تا کد را با بهینهسازی های غیر اصولی شلخته کنند. کد تمیز یک کار را به خوبی انجام میدهد. Bjarne از کلمه “ظریف” استفاده میکند. این کلمه کامل است! دیکشنری موجود در MacBook من این تعریف را برای این کلمه ارائه میدهد : از نظر ظاهری و رفتاری دلپذیر و برازنده و شیک است. کاملاً مبتکرانه و ساده. به کلمه "دلپذیر" دقت کنید. ظاهرا Bjarne فکر میکند که خواندن کد تمیز لذت بخش است. خواندن آن باید لبخند را به لبان شما بیاورد، هماگونه که یک جعبه موسیقی خوش ساخت و یا یک ماشین با طراحی زیبا باعث میشود لبخند بزنید Bjarne همچنین دو بار از واژه بازده استفاده می کند. شاید وقتی این کلمه از دهان مخترع C ++ خارج میشود، غافلگیر کننده نباشد. اما فکر میکنم چیزی فراتر از تمایل صرف برای سرعت وجود دارد. چرخههای تلف شده لذت بخش نیستند و ناخوشایند هستند و اکنون به کلماتی که Bjarne برای توصیف پیامد آن ناهنجاری استفاده میکند توجه داشته باشید. او از کلمه "وسوسه" استفاده میکند. در اینجا یک حقیقت عمیق وجود دارد. کد بد شلختگی را وسوسه میکند تا رشد کند! وقتی دیگران کد بد را تغییر میدهند، متمایل به بدتر کردن آن هستند. Dave Thomas عملگرا و Andy Hunt این نکته را با یک روش متفاوت میگویند. آنها از استعاره پنجرههای شکسته استفاده کرده اند. وقتی ساختمانی پنجرههای شکسته دارد اینظور به نظر میرسد که کسی به آن اهمیتی نمیدهد. بنابراین دیگران هم به آن ساختمان اهمیتی نمیدهند. آنها اجازه میدهند تا پنجرههای بیشتری شکسته شود. حتی خودشان هم شروع به شکستن پنجرهها میکنند. آنها با گرافیتی نما را خراب میکنند و اجازه میدهند در آن جا زباله جمع شود.
71 |
72 | یک پنجره شکسته روند زوال را شروع میکند. Bjarne همچنین خاطرنشان میکند که رسیدگی به خطا باید کامل باشد. این مربوط به قانون توجه به جزییات میشود. کنترل خطای مختصر فقط یکی از راههایی است که برنامهنویسان با استفاده از آن به تفصیل جزئیات میپردازند. نشت حافظه (Memory leaks) یکی دیگر از راهها و شرایط مسابقه(race condition) راه دیگر است. راه دیگر نامگذاری متناقض(Inconsistent naming) است. نتیجه اصلی این است که کد تمیز توجه زیادی به جزئیات دارد. Bjarne با این ادعا که کد تمیز یک کار را به خوبی انجام میدهد، بحث را میبندد. تصادفی نیست که بسیاری از اصول طراحی نرمافزار وجود دارند که میتوانند دلیل اصلی این توصیه ساده باشند.
73 |
74 | نویسندگان یکی پس از دیگری سعی در برقراری ارتباط با این اندیشه داشتند. کد بد بیش از حد خرابکاری میکند، تمایلات را زشت کرده و اهداف را مبهم میکند. کد تمیز متمرکز است. هر تابع، هر کلاس، هر ماژول یک نگرش تک ذهنیتی را که کاملاً دست نخورده و آلوده نشده باقی مانده است با جزئیات پیرامون خود در معرض نمایش قرار میدهد
75 |
76 | **گردی بوچ Grady Booch، نویسنده “Object Oriented analysis and Design with Applications**” :کد تمیز ساده و سر راست است. کد تمیز مثل یک نثر خوب نوشته شده است. کد تمیز هرگز هدف طراح را مبهم نمیکند بلکه پر از انتزاعات واضح و خطوط کنترل سر راست است. Grady برخی از نکاتی را که Bjarne بیان میکند، عنوان میکند، اما او یک جنبه خوانایی را در نظر میگیرد. من خصوصاً این نظر او را که كد تمیز باید مانند نثر خوب نوشته شده باشد دوست دارم. دوباره به کتاب خوبی که مطالعه کرده اید فکر کنید. به یاد آورید که چگونه کلمات ناپدید شدند تا تصاویر جایگزین شوند! مثل تماشای فیلم. اینطور نیست؟ بهتر! شخصیتها را دیدید، صداها را شنیدید، ترحم و طنز را تجربه کردید. خواندن کد تمیز هرگز شبیه به خواندن کتاب ارباب حلقهها نخواهد بود. با این وجود استعاره ادبی بد نیست. مانند یک رمان خوب، کد تمیز باید به وضوح تنشهای موجود در مشکل را حل کند. باید آن تنشها را به اوج خود برساند و سپس به خواننده بگوید که: "آها! اینه!" زیرا مشکلات و تنشها در ظهور یک راه حل واضح برطرف میشود.به نظر من استفاده grady از عبارت "انتزاع خشک(crisp abstraction)" به عنوان یک کلمه ضد و نقیض جذاب است! در نهایت، کلمه "خشک" تقریباً مترادف "واقع" است. فرهنگ لغت مک بوک من تعریف زیر از "خشک" را دارد: قاطعانه و سرنوشت ساز، بدون تردید و جزئیات غیر ضروری. علیرغم این کنار هم گذاشتن معانی، کلمات دارای پیام قدرتمندی هستند. کد ما باید برخلاف حدس و گمانها و واقعی باشد. کد باید فقط شامل چیزهای مهم و ضروری باشد. خوانندگان ما باید قاطعیت ما را درک کنند.
77 |
78 | **آقای Dave Thomas، موسس OTI، پدرخوانده استراتژی Eclipse** : کد تمیز میتواند بجز نویسنده اصلی آن، توسط یک توسعهدهنده دیگر نیز خوانده شود و بهبود یابد. این کد Unit test و Acceptance test دارد. این کد اسامی معنی دار دارد. کد تمیز به جای اینکه راههای زیادی برای انجام یک کار ارائه کند، یک راه برای انجام یک کار دارد. کد تمیز حداقل وابستگیها، که به طور واضح تعریف شده اند، و یک API واضح و حداقلی را ارائه میدهد. کد باید دانا باشد زیرا بسته به زبان، تمام اطلاعات لازم را نمی توان به طور مشخص و به تنهایی با کد بیان کرد. Dave بزرگ، تمایل Grady برای خوانایی را با پیچیدگی مهمی به اشتراک میگذارد. Dave ادعا میکند که کد تمیز باعث میشود بهبود آن برای سایر افراد آسان باشد. این ممکن است واضح به نظر برسد، اما نمیتواند بیش از حد مورد تأکید قرار بگیرد. از این گذشته، میان کدی که خواندن آن آسان است و کدی که تغییر آن آسان است تفاوت وجود دارد. Dave تمیز بودن کد را با تستها پیوند میزند! ده سال پیش این امر باعث تعجب بسیار میشد. اما قوانین توسعه مبتنی بر تست(Test Driven Development) تأثیر عمیقی بر صنعت ما گذاشته و به یکی از اساسیترین قوانین ما تبدیل شده است. حق با Dave است. کد، بدون تست، تمیز نیست. مهم نیست که چقدر زیبا باشد، هر چقدر هم که قابل خواندن و در دسترس باشد، اگر آزمایش نشده باشد، کثیف است. Dave دو بار از کلمه حداقل استفاده میکند. ظاهراً منظور او در این تعریف کدهای کوچک است. در واقع، از زمان پیدایش ادبیات نرمافزار تا کنون، این یک ترجمه رایج بوده است. کوچکتر بهتر است. Dave همچنین میگوید که کد باید دانا(Liteate) باشد. این یک اشاره ریز به ادبیات برنامهنویسی Knuth دارد. نتیجه کلی این است که کد باید به شکلی تهیه شود که برای انسانها خوانا باشد
79 |
80 | **میشل فیدرز Micheal Feathers، نویسنده Working Effectively with Legacy Code** :من میتوانم تمام خصوصیاتی را که در کد تمیز به آن توجه میکنم ذکر کنم، اما کیفیت فرا معماری وجود دارد که بر تمام آنان ارجح است. همیشه به نظر میرسد که کد تمیز توسط کسی نوشته شده است که به آن اهمیت داده است. هیچ چیز واضحی وجود ندارد که بتوانید انجام دهید تا کد بهتر شود. به همه این موارد توسط نویسنده کد فکر شده است و اگر سعی دارید پیشرفتها را تصور کنید، به جایی که هستید برمیگردید، جایی که از کد شخصی که برای شما باقی گذاشته تشکر میکنید - کدی که توسط کسی که عمیقاً به این مهارت اهمیت میدهد به جا گذاشته شده است. یک کلمه: اهمیت دادن. این کلمه واقعاً موضوع این کتاب است. شاید یک عنوان مناسب این باشد که چگونه به کد اهمیت دهیم. Micheal به مهمترین نکته اشاره کرد. کد تمیز کدی است که از آن مراقبت شده است. شخصی وقت خود را برای ساده و منظم نگه داشتن آن صرف کرده است. آنها توجه کافی به جزئیات داشته اند. آنها مراقبت کرده اند.
81 |
82 | **رون جفری.Ron Jeffries، نویسنده Extreme Programming Installed و Extreme Programming Adventures in C# :** رون حرفه برنامهنویسی خود را در Fortran در فرماندهی هوایی استراتژیک آغاز کرد و تقریباً به هر زبان و تقریباً بر روی هر دستگاهی، کدی را نوشت. این امر باعث شد که در مورد صحبت کردنش بسیار مراقب باشد: در سالهای اخیر من قوانین کد ساده Beck را شروع و تقریباً به پایان رساندم. به ترتیب اولویت، کد ساده:
83 |
84 | • تمام تستها را اجرا میکند؛
85 |
86 | • بدون (کد اضافه)Duplicate است.
87 |
88 | • تمام ایدههای طراحی موجود در سیستم را بیان میکند.
89 |
90 | • تعداد موجودیتهایی چون کلاسها، متدها، توابع و موارد مشابه را به حداقل میرساند.
91 |
92 | از این میان، بیشتر روی Duplication تمرکز میکنم. وقتی همین کار بارها و بارها انجام شد، این نشانگر این است که ایده ای در ذهن ما وجود دارد که به خوبی در کد نمایش داده نشده است. سعی میکنم بفهمم که چیست. سپس سعی میکنم این ایده را با وضوح بیشتری بیان کنم. برای من، بیانگر بودن شامل اسامی معنادار است، و من احتمالاً چندین بار اسامی چیزها را قبل از تثبیت آنها، تغییر میدهم. با ابزار مدرن کدنویسی مانند Eclipse، تغییر نام کاملا بدون هزینه است، بنابراین تغییر دادن برای من مشکل ساز نخواهد بود. با این وجود بیان کد فراتر از نامها است. من همچنین به این موضوع نگاه میکنم که آیا یک شی یا متد بیش از یک کار را انجام میدهد یا نه. اگر یک شیء باشد، احتمالاً باید به دو یا چند شیء تقسیم شود. اگر یک متد باشد، من همیشه از refactoring Extract Method روی آن استفاده میکنم، نتیجه اجرای این روش بر روی یک متد این است که چیزی که متد انجام میدهد را واضح تر بیان میکند، و برخی از زیرمتدها چگونگی انجام این کار را بیان میکنند. Duplication و صراحت، برای رسیدن به چیزی که من آن را کد تمیز تلقی کنم، راه بسیار طولانی ای را طی میکنند و بهبود کد کثیف فقط با توجه به این دو مورد میتواند تفاوت بزرگی ایجاد کند. با این حال، یک چیز دیگر وجود دارد که من از انجام آن آگاه هستم، که توضیح آن کمی سختتر است. بعد از سالها انجام این کار، به نظر من همه برنامهها با عناصر بسیار مشابهی ساخته شده اند. یک مثال "یافتن چیزها در یک مجموعه" است. چه بانک اطلاعاتی از سوابق کارمندان، یا نقشه درهم ساز(Hash map)کلیدها و مقادیر، و یا آرایه ای از بعضی از اقلام داشته باشیم، ما اغلب خودمان را خواهان مورد خاصی از آن مجموعه میبینیم. در پی آگاهی از وقوع این اتفاق، من اغلب پیادهسازی خاصی را در یک متد یا کلاس انتزاعی تر میپیچم. این به من چند مزیت جالب میدهد. من اکنون میتوانم آن عملکرد را با چیزی ساده پیادهسازی کنم، مثلا با یک هش مپ، اما از آنجایی که اکنون همه ارجاعات مربوط به آن جستجو را توسط انتزاع کوچکم تحت پوشش قرار دادم، میتوانم هر زمان که بخواهم، پیادهسازی را تغییر دهم. من بعدا میتوانم با حفظ توانایی خود برای تغییر، به سرعت پیش بروم. علاوه بر این، وقتی با چند روش نسبتا ساده میتوانم همه چیزی که میخواهم را بیابم، مجموعه انتزاع اغلب توجه مرا به آنچه که "واقعاً" در جریان است، جلب میکند و مرا از مسیر پیادهسازی مجموعه رفتارهای دلخواه منصرف میکند. Duplication کاهش یافته، بیان واضح و ساخت انتزاعات ساده از ابتدا. این چیزی است که برای من کد تمیز میسازد.
93 |
94 | در اینجا، در چند پاراگراف کوتاه، Ron مطالب این کتاب را خلاصه کرده است.
95 |
96 | بدون Duplication، یک چیز، بیان، تجریدهای کوچک. همه چیز آنجاست.
97 |
98 | و **Ward Cunningham مخترع ویکی، مخترع Fit، هم اختراع کننده eXtreme Programming. نیروی انگیزشی در پشت Design Pattern. رهبر فکری شی گرایی و Smalltalk. پدرخوانده همه کسانی که به کد اهمیت میدهند:**وقتی هر روالی(Routine) که میخوانید دقیقا همان چیزی است که انتظار دارید، شما میدانید که دارید روی کد تمیز کار میکنید. همچنین هنگامی که کد شبیه به زبانی که برای مشکل درست شده است، میتوانید آن را یک کد زیبا بنامید.
99 |
100 | جملههایی مانند این، خصوصیات Ward است. شما آن را خوانده اید، سر خود را تکان داده اید، و سپس به موضوع بعدی رفته اید. منطقی به نظر می رسد، بطور واضح این مسئله به سختی به عنوان یک مسئله عمیق و ژرف درنظر گرفته میشود. ممکن است فکر کنید تقریباً همان چیزی بود که انتظار داشتید. اما بیایید نگاه دقیق تری داشته باشیم. " . . تقریباً آنچه انتظار داشتید. " آخرین باری که ماژولی را دیدید که تقریباً همان چیزی بود که انتظار داشتید کی بود؟ آیا به احتمال زیاد ماژولهایی که به آنها نگاه میکنید گیج کننده، پیچیده و درهم و برهم نیستند؟ این قانون اشتباه نیست؟ آیا شما عادت نکردید که تلاش برای گرفتن و نگه داشتن تارهای استدلال که از کل سیستم به دست می آیند و راه خود را در ماژولی که میخوانید درست میکنند، به هیچ انگارید؟ آخرین باری که یک کد را خواندید و سر خود را به شکلی که Ward گفته است تکان دادید، کی بود؟ Ward انتظار دارد که وقتی کد تمیز را میخوانید به هیچ وجه تعجب نکنید. در واقع، شما حتی تلاش زیادی هم نمی کنید. شما آن را خواهید خواند، و تقریباً همان چیزی است که انتظار دارید. این امر آشکار، ساده و قانع کننده خواهد بود. هر ماژول مقدمات را برای مرحله بعد تنظیم میکند. هر کدام به شما میگوید که بعدی چگونه نوشته خواهد شد. برنامههایی که آن چنان تمیز هستند، به گونه ای عمقی و خوب نوشته شده اند که حتی متوجه آن نمیشوید. طراح باعث میشود مانند همه طرحهای استثنایی، این مسئله به طرز مسخره ای ساده به نظر برسد.
101 |
102 | تفکر Ward در مورد زیبایی چطور؟ همه ما در برابر این واقعیت که زبانهای ما برای مشکلات ما طراحی نشده اند جبهه میگیریم. اما جمله Ward باری را بر دوش ما میگذارد. او میگوید که کد زیبا باعث میشود اینطور به نظر برسد که زبان برای این مشکل ایجاد شده است! بنابراین این مسئولیت ماست که زبان را ساده جلوه دهیم! طرفداران زبانها در همه جا هستند، هشیار باشید **این زبان نیست که برنامهها را ساده جلوه دهد. این برنامهنویس است که باعث میشود زبان ساده به نظر برسد!**
103 |
104 | ### مکتب فکری!
105 |
106 | در مورد من(عمو Bob) چی؟ من در مورد کد تمیز چه فکر میکنم؟ این کتاب با جزییات زیاد آنچه من و همفکرانم درباره کد تمیز فکر میکنیم را به شما خواهد گفت. ما آنچه که فکر میکنیم یک نام متغیر تمیز، یک تابع تمیز، یک کلاس تمیز و غیره را ایجاد میکند به شما خواهیم گفت. ما این عقاید را مطلق ارائه خواهیم کرد و از سختگیری خود عذرخواهی نمیکنیم. برای ما، در این مرحله از حرفه مان، آنها مطلق هستند. آنها مکتب فکری ما در مورد کد تمیز هستند. هنرمندان رزمی همه با بهترین هنر رزمی یا بهترین تکنیک در یک هنر رزمی موافق نیستند. اغلب استادان هنرهای رزمی مکتب خود را تشکیل میدهند و دانش آموزان را برای یادگیری دور خود جمع میکنند. بنابراین ما Gracie Jiu Jistu را میبینیم، که توسط خانواده Gracie در برزیل تأسیس و تدریس شده است. ما Hakkoryu Jiu Jistu را میبینیم که توسط Okuyama Ryuho در توکیو تاسیس و تدریس شده است. ما Jeet Kune Do را میبینیم، که توسط بروس لی در ایالات متحده تاسیس و تدریس شده است. هنرجویان این رویکردها، خود را در آموزههای بنیانگذار غرق میکنند. آنها خود را وقف این می كنند كه آنچه آن استاد خاص تدریس میکند را فارغ از چیزی که استاد دیگر تدریس میکند، بیاموزند. بعداً با رشد هنرجویان در هنر خود، ممکن است دانش آموز استاد دیگری شوند تا بتوانند دانش و تمرین خود را گسترش دهند. عده ای سرانجام برای کشف مهارتهای خود، به کشف تکنیکهای جدید و تأسیس مکتب خود میروند. هیچ یک از این مکاتب مختلف کاملاً درست نیستند. با وجود این، در درون یک مکتب خاص به نظر میرسد که آموزهها و فنون صحیح هستند.
107 |
108 | از این گذشته، یک روش درست برای تمرین Hakkoryu Jiu Jitsu یا Jeet Kune Do وجود دارد. اما این حق در یک مکتب، آموزههای یک مکتب متفاوت را باطل نمیکند. این کتاب را در مورد توصیفات مکتب اشیا آموزشی در کد تمیز در نظر بگیرید. تکنیکها و آموزههای موجود روشی است که ما هنر خود را تمرین میکنیم. ما مایل هستیم ادعا کنیم که اگر این آموزهها را رعایت کنید، از مزایایی که ما از آنها لذت بردیم لذت خواهید برد و یاد میگیرید که کدی بنویسید که تمیز و حرفه ای باشد. اما این اشتباه را نکنید که فکر کنید که "حق" به طور مطلق با ما است.
109 |
110 | مکاتب و اساتید دیگری نیز وجود دارند که به همان اندازه که ما ادعا داریم، حرفه ای هستند. شایسته است که شما از آنها نیز بیاموزید. در واقع، بسیاری از توصیههای این کتاب جنجال برانگیز است. احتمالاً با همه آنها موافق نخواهید بود. ممکن است با بعضی از آنها به شدت مخالف باشید. خوب است. ما نمیتوانیم ادعای کمال اعتبار کنیم. از طرف دیگر، توصیههای موجود در این کتاب مواردی است که ما طولانی و سخت در مورد آنها فکر کرده ایم. ما آنها را طی چندین دهه تجربه و آزمایش و خطای مکرر آموخته ایم. بنابراین چه موافق باشید یا مخالف باشید، اگر به نقطه نظر ما احترام نگذارید و آن را نبینید شرم آور خواهد بود. ما نویسنده ایم فیلد @author در یک Javadoc به ما میگوید که ما کی هستیم. ما نویسنده هستیم و یک چیز در مورد نویسندگان وجود دارد و آن این است که آنها خواننده دارند. در واقع، نویسندگان مسئول برقراری ارتباط خوب با خوانندگان خود هستند. دفعه بعد که شما یک خط از یک کد را نوشتید، به یاد داشته باشید که شما نویسنده ای هستید که برای خوانندگانی که تلاش شما را قضاوت میکنند، مینویسید. ممکن است بپرسید : یک کد واقعا چه مقدار خوانده میشود؟ تمام تلاش ما صرف نوشتن آن نمیشود؟ آیا تاکنون به یک جلسه ویرایش دوباره باز گشته اید؟ در دهه 80 و 90 ویرایشگرانی مانند Emacs داشتیم که هرگونه فشار به صفحه کلید را ردیابی میکردند. میتوانید یک ساعت کار کنید و بعد از آن کلیه ویرایشهای خود را مانند یک فیلم پر سرعت پخش کنید. وقتی این کار را کردم، نتایج جالب توجه بود. هیچ یک از این مکاتب مختلف کاملاً درست نیستند. با وجود این، در درون یک مکتب خاص به نظر میرسد که آموزهها و فنون صحیح هستند.
111 |
112 | اکثریت قریب به اتفاق تجدید نظرها در مورد بخش پیمایش و هدایت به سایر ماژولها بود! باب وارد ماژول میشود. او به تابعی که نیاز به تغییر دارد میرود او با توجه به گزینههای خود مکث میکند. اوه، او در حال برگشتن به بالای ماژول برای بررسی مقدار اولیه داده شده به یک متغیر است. اکنون او دوباره به پایین برمیگردد و شروع به تایپ میکند. اوه، او دارد آنچه را که تایپ کرده است پاک میکند! او دوباره آن را تایپ میکند. او دوباره آن را پاک میکند! او نیمی از چیز دیگری را تایپ میکند اما بعد آن را پاک میکند! او به تابع دیگری میرود که تابعی را که دارد تغییر میدهد را صدا میزند تا ببیند چگونه آن تابع صدا زده شده است. او دوباره به بالا برمیگردد و همان کدی را که تازه پاک کرده است تایپ میکند. مکث میکند. او دوباره آن کد را پاک میکند! وی پنجره دیگری را باز میکند و به یک زیر کلاس نگاه میکند. آیا این تابع دوبار نوشته شده است؟ . . . شما بی اراده کار میکنید. در واقع، نسبت زمانی که صرف خواندن میکنید در مقابل زمانی که صرف نوشتن میکنید بیش از 10: 1 است. همیشه بخشی از تلاشمان برای نوشتن کد جدید، برای خواندن کد قدیمی صرف میشود. از آنجا که این نسبت بسیار زیاد است، میخواهیم خواندن کد آسان باشد، حتی اگر این کار نوشتن را سختتر کند. البته هیچ راهی برای نوشتن کد بدون خواندن آن وجود ندارد، بنابراین آسان تر کردن خواندن در واقع نوشتن آن را آسان تر میکند. از این منطق گریزی وجود ندارد. اگر نمیتوانید کدهای اطراف را بخوانید، نمیتوانید کد بنویسید. نوشتن کدی که میخواهید امروز بنویسید بسته به اینکه چقدر خواندن کد اطراف آن سخت یا آسان باشد، دشوار یا آسان خواهد بود. بنابراین اگر میخواهید سریع کار کنید، اگر میخواهید به سرعت کار خود را به اتمام برسانید، اگر میخواهید کد شما به راحتی نوشته شود، خواندن آن را آسان کنید قانون پیشاهنگان پسر اینکه کد به خوبی نوشته شود کافی نیست. کد باید در طول زمان تمیز نگه داشته شود. با گذشت زمان، همه ما شاهد پوسیدن و کاهش درجه ارزش کد هستیم. بنابراین ما باید نقش فعالی در جلوگیری از این تخریب داشته باشیم. پیشاهنگان پسر امریکا یک قانون ساده دارند که ما میتوانیم از آن در حرفه خود استفاده کنیم. محل اردوگاه را تمیزتر از آنچه که به آن وارد شدید، ترک کنید اگر همه ما هنگام ورود به کد، كد خود را كمي تميزتر از زماني كه آن را رها کرده بوديم کنیم، كد به سادگي نمي تواند پوسيده شود. پاکسازی لازم نیست چیز بزرگی باشد. بهتر کردن نام یک متغیر، شکستن یک تابع نسبتا بزرگ به توابع کوچکتر، از بین بردن یک تکثیر، پاک کردن یک عبارت شرطی ترکیبی باعث تمیزتر شدن کد میشود. آیا میتوانید کار کردن روی پروژه ای که کدش با گذشت زمان به آسانی بهتر شده است را تصور کنید؟آیا معتقدید که گزینه ای غیر از این حرفه ای است؟ در واقع، آیا پیشرفت مداوم جز ذاتی حرفه ای بودن نیست؟ مقدمه و اصول از بسیاری جهات، این کتاب "مقدمه" کتابی است که من در سال 2002 با عنوان توسعه نرمافزار چابک: اصول، الگوهای و عملکردها نوشتم. کتاب PPP خود با اصول طراحی شی گرا و بسیاری از شیوههایی که توسط توسعه دهندگان حرفه ای استفاده میشود درگیر است. اگر PPP را نخوانده اید، ممکن است در آینده متوجه شوید که آن کتاب، داستانی که توسط این کتاب گفته شده را ادامه میدهد. اگر قبلاً آن را خوانده اید، میتوانید تکرار بسیاری از تفکرات آن کتاب در سطح کد را در این کتاب ببینید. در این کتاب اشاراتی پراکنده به اصول مختلف طراحی خواهید یافت. در میان این اصول اصل تک مسئولیت4، اصل بسته باز5 و اصل وارونگی وابستگی6 وجود دارد. این اصول به تفصیل در PPP شرح داده شده است نتیجه گیری کتابهای مربوط به هنر قول نمی دهند شما را به یک هنرمند تبدیل کنند. تمام کاری که آنها میتوانند انجام دهند این است که برخی از ابزارها، تکنیکها و فرآیندهای فکری که سایر هنرمندان استفاده کرده اند را به شما ارائه میدهند. بنابراین این کتاب نیز نمیتواند قول دهد شما را به یک برنامهنویس خوب تبدیل کند. نمیتواند قول بدهد که به شما "درک کد" را بدهد. تمام کاری که میتواند انجام دهد این است که فرآیندهای فکری برنامهنویسان خوب و ترفندها، تکنیکها و ابزارهایی را که از آنها استفاده میکنند به شما نشان دهد. درست مانند یک کتاب در زمینه هنر، این کتاب پر از جزئیات خواهد بود. تعداد زیادی کد وجود دارد. هم کد خوب خواهید دید و هم کد بد. میبینید که کد بد را به کد خوب تبدیل میکنید. لیستهای از اکتشاف، قوانین و تکنیکها را مشاهده خواهید کرد. مثال پشت مثال خواهید دید. پس از آن، به شما بستگی دارد. شوخی قدیمی درباره ویولنیست کنسرت را که در راه رسیدن به یک اجرا گم شده بود را به یاد میآورید؟ او پیرمردی را در گوشه ای متوقف کرد و از او پرسید که چگونه به Carnegie Hall برسد. پیرمرد به ویولنیست و ویولون زیر بازویش نگاه کرد و گفت: "تمرین کن پسرم. تمرین کن!"
113 |
114 |
115 |
116 | * [فصل بعد](../2_meaningful-names(completed)/meaningful-names.md)
117 |
118 | * [فصل قبل](../0_introduction(completed)/introduction.md)
--------------------------------------------------------------------------------
/5_Formatting(completed)/5_Formatting.md:
--------------------------------------------------------------------------------
1 | # ۵ قالببندی
2 |
3 | 
4 |
5 |
6 |
7 | هنگامیکه دیگران شروع میکنند به بررسی زیر و بم کد، میخواهیم آنها را تحت تأثیر منظم بودن ، قوام و توجه به جزئیاتی که درک میکنند تحت تأثیر قرار دهیم. میخواهیم با نظم تحتتاثیر قرارگیرند. وقتیکه به ماژولها دقت میکنند، ابروهایشان بالا رود. میخواهیم بفهمند که افراد حرفهای پشت کار بودهاند. اگر در عوض، توده کدی بینند که گویی توسط تعدادی ملوان مست نوشته شدهاست، به احتمال زیاد نتیجه میگیرند که همین عدم توجه به جزئیات، بر دیگر جنبههای پروژه نیز حاکم است.
8 |
9 | باید مراقب باشید که کد شما به خوبی قالببندی شود. باید مجموعهای از قوانین ساده را انتخاب کنید که بر فرمت کد شما حاکم باشد، و سپس باید آن قوانین را به طور مداوم اعمال کنید. اگر در یک تیم کار میکنید ، تیم باید با یک مجموعه از قوانین قالببندی موافقت کند و همه اعضا، آن را رعایت کنند. داشتن ابزاری خودکار که بتواند آن قوانین قالببندی را برای شما اعمال کند، میتواند کمککننده باشد.
10 |
11 | ## هدف قالببندی
12 |
13 | اول از همه، بگذارید واضح باشیم. قالببندی کد مهم است. بسیار مهم است که نادیده گرفتهنشود و بسیار مهم است که مثل یک رفتار مذهبی به آن اهمیت دهید. قالببندی کد مربوط به ارتباطات است و ارتباطات، مهمترین بخش برای توسعهدهندگان حرفهای است.
14 |
15 | شاید فکر کرده باشید که "به نتیجه رساندن" مهمترین بخش برای یک توسعهدهنده حرفهای است. با این حال امیدوارم تاکنون این کتاب شما را از این ایده خارج کردهباشد. عملکردی که امروز ایجاد می کنید شانس زیادی برای تغییر در نسخه بعدی دارد ، اما خوانایی کد شما تأثیر عمیقی در تمام تغییراتی خواهد داشت که ایجاد میشود. شیوه کد نویسی و خوانایی مواردی را ایجاد می کند که مدت ها بعد از تغییر کد اصلی، بر حفظ و توسعه آن تأثیر می گذارد. سبک و نظم شما زنده می ماند ، حتی اگر کد شما اینگونه نباشد.
16 |
17 | بنابراین چه موارد قالببندی به ما کمک میکند تا بهترین ارتباط را برقرار کنیم؟
18 |
19 | ## قالب بندی عمودی
20 |
21 | بیایید با اندازه عمودی شروع کنیم. یک فایل منبع چقدر باید بزرگ باشد؟ در جاوا ، اندازه فایل با اندازه کلاس ارتباط نزدیک دارد. وقتی در مورد کلاس صحبت کنیم ، درباره اندازه کلاس صحبت خواهیم کرد. در حال حاضر بگذارید فقط اندازه فایل را در نظر بگیریم.
22 |
23 | بزرگترین فایلهای منبع جاوا چقدر بزرگ هستند؟ به نظر میرسد که طیف وسیعی از اندازهها و تفاوتهای قابل توجه در سبک وجود دارد. شکل 5-1 برخی از این تفاوتها را نشان میدهد.
24 |
25 | هفت پروژه مختلف به تصویر کشیده شده است.Junit, FitNesse, testNG, Time and Money, JDepend, Ant, و Tomcat. خطوط موجود در کادرها حداقل و حداکثر طول فایل را در هر پروژه نشان میدهد. این کادر تقریباً یک سوم فایلها (یک انحراف استاندارد) را نشان می دهد. وسط جعبه، میانگین است. بنابراین متوسط اندازه فایل در پروژه FitNesse حدود 65 خط است و حدود یک سوم پرونده ها بین 40 تا 100 خط است. بزرگترین فایل در FitNesse حدود 400 خط و کوچکترین آن 6 خط است. توجه داشته باشید که این مقیاس لگاریتمی است، بنابراین اختلاف کم در موقعیت عمودی نشانگر اختلاف بسیار بزرگ در اندازه مطلق است.
26 |
27 |
28 |
29 |
30 |
31 |
32 |
33 | توزیع طول فایل در مقیاس لگاریتمی (box height = sigma)
34 |
35 | Junit ، FitNesse و Time and Money از فایلهای نسبتاً کمی تشکیل شده اند. هیچکدام بیش از 500 خط نیستند و بیشتر این فایلها کمتر از 200 خط هستند. از طرف دیگر ، Tomcat و Ant دارای برخی از فایلها هستند که چندین هزار خط طول دارند و نزدیک به نیمی از آنها بیش از 200 خط هستند.
36 |
37 | برای ما چه معنایی دارد؟ به نظر میرسد امکان ساخت سیستم های قابل توجهی وجود دارد (FitNesse نزدیک به 50000 خط است) از فایلهایی که معمولاً 200 خط طول دارند و حد بالایی آنها 500 است. اگرچه این یک قانون سخت و سریع نیست ، اما باید بسیار مورد توجه قرار گیرد که درک فایلهای کوچک معمولاً آسانتر از فایلهای بزرگ است.
38 |
39 | ### استعاره روزنامه
40 |
41 | به یک مقاله خوش نوشت روزنامه فکر کنید. آن را به صورت عمودی می خوانید. در بالا، یک عنوان وجود دارد که به شما بگویید داستان از چه قرار است و به شما امکان میدهد تصمیم بگیرید که آیا مطلبی است که می خواهید بخوانید یا نه. پاراگراف اول خلاصه ای از کل داستان را به شما می دهد و تمام جزئیات را پنهان می کند. وقتی به سمت پایین ادامه می دهید ، جزئیات بیشتر میشوند، تا زمانی که همه تاریخها ، نامها ، نقل قولها ، ادعاها و سایر جزئیات را دارید.
42 |
43 | دوست داریم که یک فایل منبع مانند مقاله روزنامه باشد. نام باید ساده، اما توضیحی باشد. این نام به خودی خود باید کافی باشد تا به ما بگوید آیا در ماژول درستی هستیم یا نه. بالاترین قسمتهای فایل منبع باید مفاهیم و الگوریتمهای سطح بالایی را ارائه دهند. با حرکت به سمت پایین جزئیات باید افزایش یابد تا اینکه در پایان، توابع و جزئیات پایینترین سطح را در فایل منبع پیدا کنیم.
44 |
45 | یک روزنامه از مقالات زیادی تشکیل شده است؛ بیشتر آنها بسیار کوچک هستند. بعضی از آنها کمی بزرگتر هستند. تعداد کمی از آنها درحد یک صفحه هستند. این باعث می شود روزنامه قابل استفاده باشد. اگر روزنامه فقط یک داستان طولانی بود که شامل مجموعهای بینظم از واقعیتها، تاریخها و نامها بود، بهراحتی آن را نمیخواندیم.
46 |
47 | ### گشودگی عمودی بین مفاهیم
48 |
49 | تقریباً همه کدها از چپ به راست و بالا به پایین خوانده میشوند. هر سطر بیانگر یک عبارت یا بند است و هر گروه از خطوط بیانگر یک تفکر کامل است. این افکار را باید با خطوط خالی از یکدیگر جدا کرد.
50 |
51 | برای مثال ، لیست 5-1 را در نظر بگیرید. خطوط خالیای وجود دارد که تعریف پکیج ، import(ها) و هر یک از توابع را جدا می کند. این قانون بسیار ساده، تأثیر پیشبینی شدهای در طرح بصری کد دارد. هر خط خالی، یک نشانه بصری است که مفهوم جدید و جداگانهای را مشخص میکند. هنگامی که لیست را اسکن میکنید ، چشمتان به اولین خطی میرود که بعد یک خط خالی آمده.
52 |
53 |
54 |
55 | Listing 5-1
56 |
57 | BoldWidget.java
58 | ```java
59 | package fitnesse.wikitext.widgets;
60 |
61 | import java.util.regex.*;
62 |
63 | public class BoldWidget extends ParentWidget {
64 | public static final String REGEXP = "'''.+?'''";
65 | private static final Pattern pattern = Pattern.compile("'''(.+?)'''",
66 | Pattern.MULTILINE + Pattern.DOTALL
67 | );
68 |
69 | public BoldWidget(ParentWidget parent, String text) throws Exception {
70 | super(parent);
71 | Matcher match = pattern.matcher(text);
72 | match.find();
73 | addChildWidgets(match.group(1));
74 | }
75 |
76 | public String render() throws Exception {
77 | StringBuffer html = new StringBuffer("
");
78 | html.append(childHtml()).append("");
79 | return html.toString();
80 | }
81 | }
82 | ```
83 |
84 |
85 | حذف آن خطوط خالی، مانند لیست 5-2، تأثیر قابل ملاحظه ای در خوانایی کد دارد.
86 |
87 |
88 |
89 | Listing 5-2
90 |
91 | BoldWidget.java
92 | ```java
93 | package fitnesse.wikitext.widgets;
94 | import java.util.regex.*;
95 | public class BoldWidget extends ParentWidget {
96 | public static final String REGEXP = "'''.+?'''";
97 | private static final Pattern pattern = Pattern.compile("'''(.+?)'''",
98 | Pattern.MULTILINE + Pattern.DOTALL);
99 | public BoldWidget(ParentWidget parent, String text) throws Exception {
100 | super(parent);
101 | Matcher match = pattern.matcher(text);
102 | match.find();
103 | addChildWidgets(match.group(1));
104 | }
105 | public String render() throws Exception {
106 | StringBuffer html = new StringBuffer("
");
107 | html.append(childHtml()).append("");
108 | return html.toString();
109 | }
110 | }
111 | ```
112 |
113 |
114 | هنگامی که چشم خود را متمرکز نکنید این اثر حتی بیشتر نمایان می شود. در مثال اول، گروهبنهدیهای مختلف خطوط، واضحاند، درحالیکه مثال دوم، به نظر می رسد درهم و برهم است. تفاوت این دو لیست درمقدار کمی از گشودگی عمودی است.
115 |
116 | ### تراکم عمودی
117 |
118 | اگر گشودگی، مفاهیم را از هم جدا کند ، پس تراکم عمودی به معنای یک ارتباط نزدیک است. بنابراین خطوط کدی که کاملاً با هم مرتبط هستند، باید به صورت عمودی متراکم به نظر برسند. توجه کنید که چگونه کامنتهای بی فایده در لیست 5-3 ارتباط نزدیک دو متغیر نمونه را از بین میبرد.
119 |
120 |
121 |
122 | Listing 5-3
123 | ```java
124 | public class ReporterConfig {
125 |
126 | /**
127 | * The class name of the reporter listener
128 | */
129 | private String m_className;
130 |
131 | /**
132 | * The properties of the reporter listener
133 | */
134 | private List
m_properties = new ArrayList();
135 |
136 | public void addProperty(Property property) {
137 | m_properties.add(property);
138 | }
139 | }
140 | ```
141 |
142 |
143 | خواندن لیست 5-4 بسیار راحتتر است. این در یک "نگاه" قرار میگیرد ، یا حداقل برای من اینطور است. بدون اینکه خیلی سر یا چشمهایم را حرکت دهم، می توانم به آن نگاه کنم و ببینم که این یک کلاس با دو متغیر و یک تابع است. لیست قبلی من را مجبور میکند تا از حرکت چشم و سر بسیار بیشتری برای رسیدن به سطح درک مشابه استفاده کنم.
144 |
145 |
146 |
147 | Listing 5-4
148 | ```java
149 | public class ReporterConfig {
150 | private String m_className;
151 | private List m_properties = new ArrayList();
152 | public void addProperty(Property property) {
153 | m_properties.add(property);
154 | }
155 | }
156 | ```
157 |
158 |
159 | ### فاصله عمودی
160 | تابحال شده که در کلاسی پرسه بزنید، از یک تابع به تابع دیگر بروید، سورس فایل را بالا و پایین کنید، ارتباط و عملکرد توابع را بفهمید اما نهایتا گیج شوید؟ آیا تابحال برای فهمیدن تعریف یک متغیر یا تابع به زنجیرهای از وراثت برخورد کردهاید؟ این ناامیدکننده است زیرا شما در حال فهمیدن این هستید که سیستم چه کاری انجام می دهد ، اما وقت و انرژی ذهنی خود را صرف این می کنید که مکانها را بیابید و به خاطر بسپارید.
161 |
162 | مفاهیمی که ارتباط تنگاتنگی دارند باید به صورت عمودی نزدیک به یکدیگر نگه داشته شوند [G10]. واضح است که این قانون برای مفاهیمی که در فایلهای جداگانه قرار دارند کار نمی کند. اما در این صورت مفاهیم نزدیک به هم را نباید در فایلهای مختلف جدا کرد ، مگر اینکه دلیل خیلی خوبی داشته باشید. در واقع ، این یکی از دلایلی است که باید از متغیرهای محافظت شده اجتناب شود.
163 |
164 | برای آن دسته از مفاهیمی که چنان با هم مرتبط هستند که در همان پرونده منبع قرار دارند ، تفکیک عمودی آنها باید معیاری برای میزان اهمیت هر یک برای قابل درک بودن دیگری باشد. میخواهیم از اجبار خوانندگان خود برای جستجوی فایلها و کلاسهای منبع جلوگیری کنیم.
165 |
166 | **تعریف متغیر** متغیرها باید تا حد امکان نزدیک به کاربرد آنها تعریف شوند. از آنجا که توابع ما بسیار کوتاه هستند ، متغیرهای محلی باید در بالای هر تابع ظاهر شوند ، مانند این تابع longish از Junit4.3.1.
167 |
168 |
169 |
170 | ```java
171 | private static void readPreferences() {
172 | InputStream is= null;
173 | try {
174 | is= new FileInputStream(getPreferencesFile());
175 | setPreferences(new Properties(getPreferences()));
176 | getPreferences().load(is);
177 | } catch (IOException e) {
178 | try {
179 | if (is != null)
180 | is.close();
181 | } catch (IOException e1) {
182 | }
183 | }
184 | }
185 | ```
186 |
187 |
188 | متغیرهای کنترلی برای حلقهها معمولاً باید در عبارت حلقه اعلان شوند ، همانطور که در این تابع کوچک زیبا از همان منبع وجود دارد.
189 |
190 |
191 |
192 | ```java
193 | public int countTestCases() {
194 | int count= 0;
195 | for (Test each : tests)
196 | count += each.countTestCases();
197 | return count;
198 | }
199 | ```
200 |
201 |
202 | در موارد نادر ، یک متغیر ممکن است در بالای یک بلوک یا درست قبل از حلقه در یک تابع طولانی اعلام شود. چنین متغیری را می توانید از وسط یک تابع بسیار طولانی در TestNG در این قطعه مشاهده کنید.
203 |
204 |
205 |
206 | ```java
207 | ...
208 | for (XmlTest test : m_suite.getTests()) {
209 | TestRunner tr = m_runnerFactory.newTestRunner(this, test);
210 | tr.addListener(m_textReporter);
211 | m_testRunners.add(tr);
212 | invoker = tr.getInvoker();
213 | for (ITestNGMethod m : tr.getBeforeSuiteMethods()) {
214 | beforeSuiteMethods.put(m.getMethod(), m);
215 | }
216 | for (ITestNGMethod m : tr.getAfterSuiteMethods()) {
217 | afterSuiteMethods.put(m.getMethod(), m);
218 | }
219 | }
220 | ...
221 | ```
222 |
223 |
224 | **متغیرهای نمونه** از طرف دیگر، باید در بالای کلاس اعلام شود. نباید فاصله عمودی این متغیرها را افزایش داد، زیرا در یک کلاس خوب طراحی شده، اگر نه همه ، بسیاری از متدهای کلاس از آنها استفاده میکنند.
225 |
226 | بحث های زیادی در مورد اینکه متغیرهای نمونه باید به کجا بروند وجود داشته است. در C ++ معمولاً قانون به اصطلاح قیچی را اجرا میکنیم که همه متغیرهای نمونه را در پایین قرار میدهد. با این حال ، قرارداد رایج در جاوا این است که همه آنها را در بالای کلاس قرار دهید. من دلیلی برای پیروی از هر قرارداد دیگری نمیبینم. نکته مهم این است که متغیرهای نمونه در یک مکان شناخته شده اعلام شوند. همه باید بدانند که برای دیدن تعاریف به کجا مراجعه کنند.
227 |
228 | به عنوان مثال ، مورد عجیب کلاس TestSuite را در JUnit 4.3.1 در نظر بگیرید. من این کلاس را بسیار ضعیف کردم تا نکته را بیان کنم. اگر نگاهی به نیمه لیست بیندازید ، دو متغیر نمونه در آنجا تعریف شده. پنهانکردن آنها در مکان بهتر دشوار خواهد بود. شخصی که این کد را می خواند باید در تعریفها تصادفی بلغزد (همانطور که من این کار را کردم).
229 |
230 |
231 |
232 | ```java
233 | public class TestSuite implements Test {
234 | static public Test createTest(Class extends TestCase> theClass,
235 | String name) {
236 | ...
237 | }
238 | public static Constructor extends TestCase>
239 | getTestConstructor(Class extends TestCase> theClass)
240 | throws NoSuchMethodException {
241 | ...
242 | }
243 | public static Test warning(final String message) {
244 | ...
245 | }
246 | private static String exceptionToString(Throwable t) {
247 | ...
248 | }
249 | private String fName;
250 | private Vector fTests= new Vector(10);
251 | public TestSuite() {
252 | }
253 | public TestSuite(final Class extends TestCase> theClass) {
254 | ...
255 | }
256 | public TestSuite(Class extends TestCase> theClass, String name) {
257 | ...
258 | }
259 | ... ... ... ... ...
260 | }
261 | ```
262 |
263 |
264 | **توابع وابسته** اگر یک تابع، دیگری را فراخوانی میکند ، باید به صورت عمودی نزدیک باشند و در صورت امکان، صدازننده باید بالاتر از صدازدهشده باشد. این به برنامه جریان طبیعی میبخشد. اگر این قرارداد با اطمینان دنبال شود ، خوانندگان می توانند اعتماد کنند که تعاریف تابع کمی بعد از استفاده دنبال می شوند. به عنوان مثال ، قطعه FitNesse را در لیست 5-5 در نظر بگیرید. توجه کنید که بالاترین تابع چگونه توابع زیر خود را فراخوانی میکند و چگونه آنها به نوبه خود توابع زیر خود را فراخوانی میکنند. این کار، پیدا کردن توابع فراخوانی شده را آسان میکند و خوانایی کل ماژول را تا حد زیادی افزایش میدهد.
265 |
266 |
267 |
268 | Listing 5-5
269 |
270 | WikiPageResponder.java
271 | ```java
272 | public class WikiPageResponder implements SecureResponder {
273 | protected WikiPage page;
274 | protected PageData pageData;
275 | protected String pageTitle;
276 | protected Request request;
277 | protected PageCrawler crawler;
278 | public Response makeResponse(FitNesseContext context, Request request)
279 | throws Exception {
280 | String pageName = getPageNameOrDefault(request, "FrontPage");
281 | loadPage(pageName, context);
282 | if (page == null)
283 | return notFoundResponse(context, request);
284 | else
285 | return makePageResponse(context);
286 | }
287 | private String getPageNameOrDefault(Request request, String defaultPageName) {
288 | String pageName = request.getResource();
289 | if (StringUtil.isBlank(pageName))
290 | pageName = defaultPageName;
291 | return pageName;
292 | }
293 | protected void loadPage(String resource, FitNesseContext context)
294 | throws Exception {
295 | WikiPagePath path = PathParser.parse(resource);
296 | crawler = context.root.getPageCrawler();
297 | crawler.setDeadEndStrategy(new VirtualEnabledPageCrawler());
298 | page = crawler.getPage(context.root, path);
299 | if (page != null)
300 | pageData = page.getData();
301 | }
302 | private Response notFoundResponse(FitNesseContext context, Request request)
303 | throws Exception {
304 | return new NotFoundResponder().makeResponse(context, request);
305 | }
306 | private SimpleResponse makePageResponse(FitNesseContext context)
307 | throws Exception {
308 | pageTitle = PathParser.render(crawler.getFullPath(page));
309 | String html = makeHtml(context);
310 | SimpleResponse response = new SimpleResponse();
311 | response.setMaxAge(0);
312 | response.setContent(html);
313 | return response;
314 | }
315 | }
316 | ...
317 | ```
318 |
319 |
320 | بعلاوه، این قطعه، نمونه خوبی از نگه داشتن ثابتها در سطح مناسب است [G35]. ثابت "FrontPage" می توانست در تابع getPageNameOrDefault دفن شود ، اما این می تواند یک ثابت شناخته شده و مورد انتظار را در تابع نامناسب سطح پایین پنهان کند. بهتر بود که آن ثابت را از جایی که منطقی است باشد، به محلی انتقال دهیم که واقعاً از آن استفاده می کند.
321 |
322 |
323 |
324 |
325 |
326 |
327 |
328 |
329 |
330 | **میل مفهومی** بخشهای خاصی از کد نیازست نزدیک بخشهای دیگر باشند. آنها میل مفهومی خاصی دارند. هرچه این میل قویتر باشد ، فاصله عمودی کمتری باید بین آنها وجود داشته باشد.
331 |
332 | همانطور که دیدیم، این میل ممکن است بر اساس یک وابستگی مستقیم باشد، مانند اینکه یک تابع، تابع دیگری را صدا میکند، یا یک تابع از یک متغیر استفاده میکند. اما علل احتمالی دیگری نیز وجود دارد. وابستگی ممکن است ایجاد شود زیرا گروهی از توابع عملیاتی مشابه را انجام می دهند. این قطعه کد را از Junit 4.3.1 در نظر بگیرید:
333 |
334 |
335 |
336 | ```java
337 | public class Assert {
338 | static public void assertTrue(String message, boolean condition) {
339 | if (!condition)
340 | fail(message);
341 | }
342 | static public void assertTrue(boolean condition) {
343 | assertTrue(null, condition);
344 | }
345 | static public void assertFalse(String message, boolean condition) {
346 | assertTrue(message, !condition);
347 | }
348 | static public void assertFalse(boolean condition) {
349 | assertFalse(null, condition);
350 | }
351 | }
352 | ...
353 | ```
354 |
355 |
356 | این توابع از یک تمایل مفهومی قوی برخوردار هستند زیرا آنها دارای یک طرح مشترک نامگذاری هستند و صورتهای مختلفی از یک کار پایه را انجام می دهند. این واقعیت که آنها یکدیگر را صدا می کنند در درجه دوم است. حتی اگر این کار را نکردند، هنوز هم نیاز است به هم نزدیک باشند.
357 |
358 | ### ترتیب عمودی
359 |
360 | به طور کلی می خواهیم وابستگی های فراخوانی تابع به سمت پایین باشد. یعنی تابعی که فراخوانی می شود باید زیر تابعی باشد که فراخوانی را انجام می دهد. این یک جریان خوب از ماژول کد منبع از سطح بالا به سطح پایین ایجاد می کند.
361 |
362 | همانند مقالات روزنامهها، انتظار داریم مهمترین مفاهیم ابتدا مطرح شوند، همچنین انتظار داریم که با کمترین جزئیات آلوده کننده بیان شوند. ما انتظار داریم که جزئیات سطح پایین آخر باشد. این به ما اجازه میدهد بدون اینکه خود را در جزئیات غوطهور کنیم، از فایلهای منبع خلاص شویم، و از چند تابع اول خلاصه کنیم. لیست 5-5 از این طریق سازمانیافته است. شاید حتی مثالهای بهتر این موارد عبارتند از لیست 15-5 در صفحه 263 و لیست 3-7 در صفحه 50.
363 |
364 | ## قالببندی افقی
365 |
366 | یک خط باید چقدر عرض داشته باشد؟ برای پاسخ دادن به آن ، بیایید بررسی کنیم که خطوط در برنامه های معمول چقدر عرض دارند. باز هم، ما هفت پروژه مختلف را بررسی می کنیم. شکل 5-2 توزیع طول خطوط هر هفت پروژه را نشان می دهد. منظم بودن، خصوصاً در حدود 45 کاراکتر چشمگیر است. در واقع، هر اندازه از 20 تا 60 نشان دهنده حدود 1 درصد از تعداد کل خطوط است. این 40 درصد است! شاید 30 درصد دیگر کمتر از 10 حرف عرض داشته باشند. به یاد داشته باشید این مقیاس ورود به سیستم است، بنابراین شکل خطی افت بیش از 80 کاراکتر واقعاً قابل توجه است. برنامه نویسان به وضوح خطوط کوتاه را ترجیح می دهند.
367 |
368 |
369 |
370 |
371 |
372 |
373 |
374 | Java line width distribution
375 |
376 |
377 |
378 | این نشان می دهد که ما باید تلاش کنیم خطوط خود را کوتاه نگه داریم. حد 80 قدیمی هولریت کمی خودسرانه است و من مخالف این نیستم که خطوط به 100 یا حتی 120 برسد. اما فراتر از آن احتمالاً فقط بی احتیاطی است.
379 |
380 | من قبلاً از این قانون پیروی می کردم که شما هرگز نباید به سمت راست پیمایش کنید. اما امروزه مانیتورها برای این امر بسیار گسترده هستند و برنامه نویسان جوان می توانند فونت را به اندازه ای کوچک کنند که بتوانند 200 کاراکتر در صفحه نمایش دهند. چنین کاری نکن من، شخصاً حد خودم را 120 گذاشتم.
381 |
382 | ### گشودگی و چگالی افقی
383 |
384 | ما از فضای سفید افقی برای ارتباط چیزهایی که به شدت مرتبط هستند و جدا کردن مواردی که ارتباط ضعیفتری دارند استفاده میکنیم. تابع زیر را در نظر بگیرید:
385 |
386 |
387 |
388 | ```java
389 | private void measureLine(String line) {
390 | lineCount++;
391 | int lineSize = line.length();
392 | totalChars += lineSize;
393 | lineWidthHistogram.addLine(lineSize, lineCount);
394 | recordWidestLine(lineSize);
395 | }
396 | ```
397 |
398 |
399 | من اپراتورهای انتصاب را با فضای سفید احاطه کردم تا آنها را برجسته کنم. عبارات انتساب دارای دو عنصر مشخص و اصلی هستند: سمت چپ و سمت راست. فضاها آن تفکیک را آشکار می سازند.
400 |
401 | از طرف دیگر ، من بین نام تابع و پرانتز باز فاصله نگذاشتم. این به این دلیل است که عملکرد و آرگومان های آن ارتباط تنگاتنگی دارند. جدا کردن آنها باعث می شود که به جای متصل بودن ، از هم جدا به نظر برسند. من آرگومان های درون پرانتز فراخوانی تابع را برای برجسته کردن ویرگول، جدا می کنم و نشان می دهم که آرگومان ها جدا هستند.
402 |
403 | یکی دیگر از موارد استفاده از فضای خالی ، تأکید بر تقدم عملگرها است.
404 |
405 |
406 |
407 | ```java
408 | public class Quadratic {
409 | public static double root1(double a, double b, double c) {
410 | double determinant = determinant(a, b, c);
411 | return (-b + Math.sqrt(determinant)) / (2*a);
412 | }
413 | public static double root2(int a, int b, int c) {
414 | double determinant = determinant(a, b, c);
415 | return (-b - Math.sqrt(determinant)) / (2*a);
416 | }
417 | private static double determinant(double a, double b, double c) {
418 | return b*b - 4*a*c;
419 | }
420 | }
421 | ```
422 |
423 |
424 | توجه کنید که تساویها به چه زیبایی خوانده میشوند. بین فاکتورها فضای خالی وجود ندارد زیرا از اولویت بالایی برخوردار هستند. ترمها با فضای خالی از هم جدا میشوند زیرا جمع و تفریق اولویتهای کمتری هستند.
425 |
426 | متأسفانه ، بیشتر ابزارها برای اصلاح مجدد کد از اولویت عملگرها چشم پوشی می کنند و فاصله یکسانی را در کل اعمال می کنند. بنابراین فاصله های ظریف مانند آنچه در بالا نشان داده شده است پس از اصلاح کد ، از بین می روند.
427 |
428 | ### ترازبندی افقی
429 |
430 | هنگامی که من یک برنامه نویس زبان اسمبلی بودم ، از تراز افقی برای برجسته سازی برخی ساختارها استفاده می کردم. وقتی شروع به کد نویسی در C ، C ++ و سرانجام جاوا کردم ، سعی کردم همه نام متغیرها را در مجموعه ای از اعلامیه ها یا همه مقادیر را در مجموعه عبارات انتساب ردیف کنم. کد من ممکن است به این شکل باشد:
431 |
432 |
433 |
434 | ```java
435 | public class FitNesseExpediter implements ResponseSender {
436 | private Socket socket;
437 | private InputStream input;
438 | private OutputStream output;
439 | private Request request;
440 | private Response response;
441 | private FitNesseContext context;
442 | protected long requestParsingTimeLimit;
443 | private long requestProgress;
444 | private long requestParsingDeadline;
445 | private boolean hasError;
446 |
447 | public FitNesseExpediter(Socket s,
448 | FitNesseContext context) throws Exception {
449 | this.context = context;
450 | socket = s;
451 | input = s.getInputStream();
452 | output = s.getOutputStream();
453 | requestParsingTimeLimit = 10000;
454 | }
455 | }
456 | ```
457 |
458 |
459 | من فهمیدم که این نوع هم ترازی مفید نیست. به نظر می رسد هم ترازی موارد پرت را تأکید میکند و چشم من را از قصد واقعی دور میکند. به عنوان مثال ، در لیست اعلامیه های بالا وسوسه می شوید لیستی از نام های متغیر را بدون بررسی انواع آنها بخوانید. به همین ترتیب ، در لیست عبارات انتساب ، وسوسه می شوید که لیست مقادیر را بدون دیدن عملگر انتساب به پایین نگاه کنید. بدتر از آن ، ابزارهای قالب بندی مجدد خودکار معمولاً این نوع هم ترازی را از بین می برند.
460 |
461 | بنابراین ، در پایان ، من دیگر این نوع کارها را انجام نمی دهم. امروزه من ترجیح می دهم تعاریف و انتساب غیر همتراز ، همانطور که در زیر نشان داده شده است ، زیرا آنها یک نقص مهم را نشان می دهند. اگر من لیست های طولانی دارم که باید تراز شوند ، مشکل طولانی بودن لیست ها است ، نه عدم هم ترازی. طول لیست تعاریف در FitNesseExpediter در زیر نشان می دهد که این کلاس باید تقسیم شود.
462 |
463 |
464 |
465 | ```java
466 | public class FitNesseExpediter implements ResponseSender {
467 | private Socket socket;
468 | private InputStream input;
469 | private OutputStream output;
470 | private Request request;
471 | private Response response;
472 | private FitNesseContext context;
473 | protected long requestParsingTimeLimit;
474 | private long requestProgress;
475 | private long requestParsingDeadline;
476 | private boolean hasError;
477 | public FitNesseExpediter(Socket s, FitNesseContext context) throws Exception {
478 | this.context = context;
479 | socket = s;
480 | input = s.getInputStream();
481 | output = s.getOutputStream();
482 | requestParsingTimeLimit = 10000;
483 | }
484 | }
485 | ```
486 |
487 |
488 | ### تورفتگی
489 |
490 | فایل منبع یک سلسله مراتب است و بیشتر شبیه یک طرح کلی است. اطلاعاتی وجود دارد که مربوط به فایل به طور کلی ، به کلاسهای جداگانه درون فایل ، به متدهای درون کلاسها ، به بلوک های درون متدها و به طور بازگشتی به بلوک های درون بلوک ها است. هر سطح از این سلسله مراتب محدوده ای است که می توان در آن اسامی را اعلام کرد و در آن تعاریف و دستورات اجرایی را تفسیر می کند.
491 |
492 | برای اینکه این سلسله مراتب از محدوده ها قابل مشاهده باشد ، متناسب با موقعیت آنها در سلسله مراتب ، خطوط کد منبع را تورفتگی می دهیم. عبارات موجود در سطح فایل ، مانند اکثر تعاریف کلاس ، به هیچ وجه فرورفته نیستند. متدهای درون یک کلاس در یک سطح سمت راست کلاس قرار دارند. پیاده سازی آن متدها در یک سطح به سمت راست تعریف متد اجرا می شود. پیاده سازی بلوک در یک سطح سمت راست بلوک حاوی آن اجرا می شود و غیره.
493 |
494 | برنامه نویسان به شدت به این طرح تورفتگی اعتماد می کنند. آنها به صورت تصویری خطوطی را در سمت چپ قرار می دهند تا ببینند در چه دامنه ای ظاهر می شوند. این به آنها امکان می دهد تا به سرعت در دامنه هایی مانند پیاده سازی دستورات if یا while که مربوط به وضعیت فعلی آنها نیستند ، جست و جو کنند. آنها سمت چپ را برای اعلامیه های متد جدید ، متغیرهای جدید و حتی کلاس های جدید اسکن می کنند. بدون تورفتگی ، برنامه ها برای انسان عملاً قابل خواندن نیستند.
495 |
496 | برنامه های زیر را که از نظر نحوی و معنایی یکسان هستند در نظر بگیرید:
497 |
498 |
499 |
500 | ```java
501 | public class FitNesseServer implements SocketServer { private FitNesseContext
502 | context; public FitNesseServer(FitNesseContext context) { this.context =
503 | context; } public void serve(Socket s) { serve(s, 10000); } public void
504 | serve(Socket s, long requestTimeout) { try { FitNesseExpediter sender = new
505 | FitNesseExpediter(s, context);
506 | sender.setRequestParsingTimeLimit(requestTimeout); sender.start(); }
507 | catch(Exception e) { e.printStackTrace(); } } }
508 | -----
509 |
510 | public class FitNesseServer implements SocketServer {
511 | private FitNesseContext context;
512 | public FitNesseServer(FitNesseContext context) {
513 | this.context = context;
514 | }
515 | public void serve(Socket s) {
516 | serve(s, 10000);
517 | }
518 | public void serve(Socket s, long requestTimeout) {
519 | try {
520 | FitNesseExpediter sender = new FitNesseExpediter(s, context);
521 | sender.setRequestParsingTimeLimit(requestTimeout);
522 | sender.start();
523 | }
524 | catch (Exception e) {
525 | e.printStackTrace();
526 | }
527 | }
528 | }
529 | ```
530 |
531 |
532 |
533 | چشم شما به سرعت می تواند ساختار پرونده تورفتگی را تشخیص دهد. تقریباً بلافاصله میتوانید متغیرها ، سازنده ها ، دسترسی ها و متد ها را تشخیص دهید. فقط چند ثانیه طول میکشد تا متوجه شوید که این نوعی ازفرانتاند ساده یک سوکت است که دارای زمان است. با این وجود، مطالعه نسخه بدون تورفتگی شدیدا غیر قابل نفوذ است.
534 |
535 | **نادیده گرفتن تورفتگی**
536 |
537 | شکستن قانون تورفتگی برای دستورات کوتاه if، حلقه های کوتاه یا توابع کوتاه ، وسوسه انگیز است. هر وقت که تسلیم این وسوسه شدم ، تقریباً همیشه برمیگردم و تورفتگی را دوباره برمیگردانم. بنابراین از فرو ریختن دامنه ها به یک خط مانند این جلوگیری میکنم:
538 |
539 |
540 |
541 | ```java
542 | public class CommentWidget extends TextWidget {
543 | public static final String REGEXP = "^#[^\r\n]*(?:(?:\r\n)|\n|\r)?";
544 | public CommentWidget(ParentWidget parent, String text){
545 | super(parent, text);
546 | }
547 | public String render() throws Exception {
548 | return "";
549 | }
550 | }
551 | ```
552 |
553 |
554 | من ترجیح میدهم به جای این موارد دامنه ها را گسترش و تورفتگی بدهم:
555 |
556 |
557 |
558 | ```java
559 | public class CommentWidget extends TextWidget {
560 | public static final String REGEXP = "^#[^\r\n]*(?:(?:\r\n)|\n|\r)?";
561 | public CommentWidget(ParentWidget parent, String text) {
562 | super(parent, text);
563 | }
564 | public String render() throws Exception {
565 | return "";
566 | }
567 | }
568 | ```
569 |
570 |
571 | ### دامنه های ساختگی
572 |
573 | همانطور که در زیر نشان داده میشود ، بعضی اوقات بدنه while یا for ساختگی است. من این نوع ساختارها را دوست ندارم و سعی میکنم از آنها اجتناب کنم. وقتی نمی توانم از آنها اجتناب کنم ، مطمئن میشوم که بدنه ساختگی به درستی فرورفتگی داشته و توسط براکت احاطه شده باشد. نمیتوانم به شما بگویم که چند بار گول یک نقطه ویرگول را خوردهام که در انتهای حلقه while روی همان خط بوده. مگر اینکه آن نقطه ویرگول را با تورفته کردن روی خط خود قابل مشاهده کنید ، دیدن آن خیلی سخت است.
574 |
575 |
576 |
577 | ```java
578 | while (dis.read(buf, 0, readBufferSize) != -1);
579 | ```
580 |
581 |
582 | ## قوانین تیم
583 |
584 |
585 |
586 |
587 |
588 |
589 |
590 |
591 | عنوان این بخش بازی با کلمات است. هر برنامه نویس قوانین قالب بندی مورد علاقه خود را دارد ، اما اگر در یک تیم کار کند ، قوانین تیم حاکم است.
592 |
593 | یک تیم از توسعهدهندگان باید بر روی یک سبک قالب بندی واحد توافق کنند و سپس هر یک از اعضای آن تیم باید از آن سبک استفاده کنند. ما میخواهیم که این نرم افزار سبک سازگار داشته باشد. ما نمیخواهیم که به نظر می رسد توسط گروهی از افراد مخالف نوشته شده است.
594 |
595 | هنگامی که پروژه FitNesse را در سال 2002 شروع کردم ، با تیم برای کار در یک سبک کدگذاری نشستم. این کار حدود 10 دقیقه طول کشید. ما تصمیم گرفتیم که براکتهای خود را کجا قرار دهیم ، اندازه فرورفتگی ما چه اندازه باشد ، چگونه کلاس ها ، متغیرها و روش ها را نام ببریم و موارد دیگر. سپس ما آن قوانین را در قالب ساز کد IDE خود رمزگذاری کردیم و از آن زمان با آنها همراه هستیم. این قوانینی نبود که من ترجیح میدهم. آنها قوانینی بودند که توسط تیم تصمیم گرفتهشد. من به عنوان عضوی از این تیم هنگام نوشتن کد در پروژه FitNesse آنها را دنبال می کردم.
596 |
597 | به یاد داشته باشید ، یک سیستم نرمافزاری خوب از مجموعه اسنادی تشکیل شده است که به زیبایی خوانده میشوند. آنها باید سبک ثابت و روان داشته باشند. خواننده باید بتواند اعتماد کند که حرکات قالببندی که در یک فایل منبع دیدهاست ، در دیگران معنای مشابهی خواهدداشت. آخرین کاری که میخواهیم انجام دهیم افزودن پیچیدگی بیشتر به کد منبع با نوشتن آن در مخلوطی از سبک های مختلف فردی است.
598 |
599 | ## قوانین قالب بندی عمو باب
600 |
601 | قوانینی که من شخصاً استفاده میکنم بسیار ساده هستند و توسط کدی در لیست 5-6 نشان داده شدهاند. این را مثالی از نحوه ایجاد کد بهترین سند استاندارد کدگذاری در نظر بگیرید.
602 |
603 |
604 |
605 |
606 | Listing 5-6
607 |
608 | CodeAnalyzer.java
609 | ```java
610 | public class CodeAnalyzer implements JavaFileAnalysis {
611 | private int lineCount;
612 | private int maxLineWidth;
613 | private int widestLineNumber;
614 | private LineWidthHistogram lineWidthHistogram;
615 | private int totalChars;
616 | public CodeAnalyzer() {
617 | lineWidthHistogram = new LineWidthHistogram();
618 | }
619 | public static List findJavaFiles(File parentDirectory) {
620 | List files = new ArrayList();
621 | findJavaFiles(parentDirectory, files);
622 | return files;
623 | }
624 | private static void findJavaFiles(File parentDirectory, List files) {
625 | for (File file : parentDirectory.listFiles()) {
626 | if (file.getName().endsWith(".java"))
627 | files.add(file);
628 | else if (file.isDirectory())
629 | findJavaFiles(file, files);
630 | }
631 | }
632 | public void analyzeFile(File javaFile) throws Exception {
633 | BufferedReader br = new BufferedReader(new FileReader(javaFile));
634 | String line;
635 | while ((line = br.readLine()) != null)
636 | measureLine(line);
637 | }
638 | private void measureLine(String line) {
639 | lineCount++;
640 | int lineSize = line.length();
641 | totalChars += lineSize;
642 | lineWidthHistogram.addLine(lineSize, lineCount);
643 | recordWidestLine(lineSize);
644 | }
645 | private void recordWidestLine(int lineSize) {
646 | if (lineSize > maxLineWidth) {
647 | maxLineWidth = lineSize;
648 | widestLineNumber = lineCount;
649 | }
650 | }
651 | public int getLineCount() {
652 | return lineCount;
653 | }
654 | public int getMaxLineWidth() {
655 | return maxLineWidth;
656 | }
657 | public int getWidestLineNumber() {
658 | return widestLineNumber;
659 | }
660 | public LineWidthHistogram getLineWidthHistogram() {
661 | return lineWidthHistogram;
662 | }
663 | public double getMeanLineWidth() {
664 | return (double)totalChars/lineCount;
665 | }
666 | public int getMedianLineWidth() {
667 | Integer[] sortedWidths = getSortedWidths();
668 | int cumulativeLineCount = 0;
669 | for (int width : sortedWidths) {
670 | cumulativeLineCount += lineCountForWidth(width);
671 | if (cumulativeLineCount > lineCount/2)
672 | return width;
673 | }
674 | throw new Error("Cannot get here");
675 | }
676 | private int lineCountForWidth(int width) {
677 | return lineWidthHistogram.getLinesforWidth(width).size();
678 | }
679 | private Integer[] getSortedWidths() {
680 | Set widths = lineWidthHistogram.getWidths();
681 | Integer[] sortedWidths = (widths.toArray(new Integer[0]));
682 | Arrays.sort(sortedWidths);
683 | return sortedWidths;
684 | }
685 | }
686 | ```
687 |
688 | * [فصل قبل](../4_Comments(completed)/4_Comments.md)
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | GNU GENERAL PUBLIC LICENSE
2 | Version 3, 29 June 2007
3 |
4 | Copyright (C) 2007 Free Software Foundation, Inc.
5 | Everyone is permitted to copy and distribute verbatim copies
6 | of this license document, but changing it is not allowed.
7 |
8 | Preamble
9 |
10 | The GNU General Public License is a free, copyleft license for
11 | software and other kinds of works.
12 |
13 | The licenses for most software and other practical works are designed
14 | to take away your freedom to share and change the works. By contrast,
15 | the GNU General Public License is intended to guarantee your freedom to
16 | share and change all versions of a program--to make sure it remains free
17 | software for all its users. We, the Free Software Foundation, use the
18 | GNU General Public License for most of our software; it applies also to
19 | any other work released this way by its authors. You can apply it to
20 | your programs, too.
21 |
22 | When we speak of free software, we are referring to freedom, not
23 | price. Our General Public Licenses are designed to make sure that you
24 | have the freedom to distribute copies of free software (and charge for
25 | them if you wish), that you receive source code or can get it if you
26 | want it, that you can change the software or use pieces of it in new
27 | free programs, and that you know you can do these things.
28 |
29 | To protect your rights, we need to prevent others from denying you
30 | these rights or asking you to surrender the rights. Therefore, you have
31 | certain responsibilities if you distribute copies of the software, or if
32 | you modify it: responsibilities to respect the freedom of others.
33 |
34 | For example, if you distribute copies of such a program, whether
35 | gratis or for a fee, you must pass on to the recipients the same
36 | freedoms that you received. You must make sure that they, too, receive
37 | or can get the source code. And you must show them these terms so they
38 | know their rights.
39 |
40 | Developers that use the GNU GPL protect your rights with two steps:
41 | (1) assert copyright on the software, and (2) offer you this License
42 | giving you legal permission to copy, distribute and/or modify it.
43 |
44 | For the developers' and authors' protection, the GPL clearly explains
45 | that there is no warranty for this free software. For both users' and
46 | authors' sake, the GPL requires that modified versions be marked as
47 | changed, so that their problems will not be attributed erroneously to
48 | authors of previous versions.
49 |
50 | Some devices are designed to deny users access to install or run
51 | modified versions of the software inside them, although the manufacturer
52 | can do so. This is fundamentally incompatible with the aim of
53 | protecting users' freedom to change the software. The systematic
54 | pattern of such abuse occurs in the area of products for individuals to
55 | use, which is precisely where it is most unacceptable. Therefore, we
56 | have designed this version of the GPL to prohibit the practice for those
57 | products. If such problems arise substantially in other domains, we
58 | stand ready to extend this provision to those domains in future versions
59 | of the GPL, as needed to protect the freedom of users.
60 |
61 | Finally, every program is threatened constantly by software patents.
62 | States should not allow patents to restrict development and use of
63 | software on general-purpose computers, but in those that do, we wish to
64 | avoid the special danger that patents applied to a free program could
65 | make it effectively proprietary. To prevent this, the GPL assures that
66 | patents cannot be used to render the program non-free.
67 |
68 | The precise terms and conditions for copying, distribution and
69 | modification follow.
70 |
71 | TERMS AND CONDITIONS
72 |
73 | 0. Definitions.
74 |
75 | "This License" refers to version 3 of the GNU General Public License.
76 |
77 | "Copyright" also means copyright-like laws that apply to other kinds of
78 | works, such as semiconductor masks.
79 |
80 | "The Program" refers to any copyrightable work licensed under this
81 | License. Each licensee is addressed as "you". "Licensees" and
82 | "recipients" may be individuals or organizations.
83 |
84 | To "modify" a work means to copy from or adapt all or part of the work
85 | in a fashion requiring copyright permission, other than the making of an
86 | exact copy. The resulting work is called a "modified version" of the
87 | earlier work or a work "based on" the earlier work.
88 |
89 | A "covered work" means either the unmodified Program or a work based
90 | on the Program.
91 |
92 | To "propagate" a work means to do anything with it that, without
93 | permission, would make you directly or secondarily liable for
94 | infringement under applicable copyright law, except executing it on a
95 | computer or modifying a private copy. Propagation includes copying,
96 | distribution (with or without modification), making available to the
97 | public, and in some countries other activities as well.
98 |
99 | To "convey" a work means any kind of propagation that enables other
100 | parties to make or receive copies. Mere interaction with a user through
101 | a computer network, with no transfer of a copy, is not conveying.
102 |
103 | An interactive user interface displays "Appropriate Legal Notices"
104 | to the extent that it includes a convenient and prominently visible
105 | feature that (1) displays an appropriate copyright notice, and (2)
106 | tells the user that there is no warranty for the work (except to the
107 | extent that warranties are provided), that licensees may convey the
108 | work under this License, and how to view a copy of this License. If
109 | the interface presents a list of user commands or options, such as a
110 | menu, a prominent item in the list meets this criterion.
111 |
112 | 1. Source Code.
113 |
114 | The "source code" for a work means the preferred form of the work
115 | for making modifications to it. "Object code" means any non-source
116 | form of a work.
117 |
118 | A "Standard Interface" means an interface that either is an official
119 | standard defined by a recognized standards body, or, in the case of
120 | interfaces specified for a particular programming language, one that
121 | is widely used among developers working in that language.
122 |
123 | The "System Libraries" of an executable work include anything, other
124 | than the work as a whole, that (a) is included in the normal form of
125 | packaging a Major Component, but which is not part of that Major
126 | Component, and (b) serves only to enable use of the work with that
127 | Major Component, or to implement a Standard Interface for which an
128 | implementation is available to the public in source code form. A
129 | "Major Component", in this context, means a major essential component
130 | (kernel, window system, and so on) of the specific operating system
131 | (if any) on which the executable work runs, or a compiler used to
132 | produce the work, or an object code interpreter used to run it.
133 |
134 | The "Corresponding Source" for a work in object code form means all
135 | the source code needed to generate, install, and (for an executable
136 | work) run the object code and to modify the work, including scripts to
137 | control those activities. However, it does not include the work's
138 | System Libraries, or general-purpose tools or generally available free
139 | programs which are used unmodified in performing those activities but
140 | which are not part of the work. For example, Corresponding Source
141 | includes interface definition files associated with source files for
142 | the work, and the source code for shared libraries and dynamically
143 | linked subprograms that the work is specifically designed to require,
144 | such as by intimate data communication or control flow between those
145 | subprograms and other parts of the work.
146 |
147 | The Corresponding Source need not include anything that users
148 | can regenerate automatically from other parts of the Corresponding
149 | Source.
150 |
151 | The Corresponding Source for a work in source code form is that
152 | same work.
153 |
154 | 2. Basic Permissions.
155 |
156 | All rights granted under this License are granted for the term of
157 | copyright on the Program, and are irrevocable provided the stated
158 | conditions are met. This License explicitly affirms your unlimited
159 | permission to run the unmodified Program. The output from running a
160 | covered work is covered by this License only if the output, given its
161 | content, constitutes a covered work. This License acknowledges your
162 | rights of fair use or other equivalent, as provided by copyright law.
163 |
164 | You may make, run and propagate covered works that you do not
165 | convey, without conditions so long as your license otherwise remains
166 | in force. You may convey covered works to others for the sole purpose
167 | of having them make modifications exclusively for you, or provide you
168 | with facilities for running those works, provided that you comply with
169 | the terms of this License in conveying all material for which you do
170 | not control copyright. Those thus making or running the covered works
171 | for you must do so exclusively on your behalf, under your direction
172 | and control, on terms that prohibit them from making any copies of
173 | your copyrighted material outside their relationship with you.
174 |
175 | Conveying under any other circumstances is permitted solely under
176 | the conditions stated below. Sublicensing is not allowed; section 10
177 | makes it unnecessary.
178 |
179 | 3. Protecting Users' Legal Rights From Anti-Circumvention Law.
180 |
181 | No covered work shall be deemed part of an effective technological
182 | measure under any applicable law fulfilling obligations under article
183 | 11 of the WIPO copyright treaty adopted on 20 December 1996, or
184 | similar laws prohibiting or restricting circumvention of such
185 | measures.
186 |
187 | When you convey a covered work, you waive any legal power to forbid
188 | circumvention of technological measures to the extent such circumvention
189 | is effected by exercising rights under this License with respect to
190 | the covered work, and you disclaim any intention to limit operation or
191 | modification of the work as a means of enforcing, against the work's
192 | users, your or third parties' legal rights to forbid circumvention of
193 | technological measures.
194 |
195 | 4. Conveying Verbatim Copies.
196 |
197 | You may convey verbatim copies of the Program's source code as you
198 | receive it, in any medium, provided that you conspicuously and
199 | appropriately publish on each copy an appropriate copyright notice;
200 | keep intact all notices stating that this License and any
201 | non-permissive terms added in accord with section 7 apply to the code;
202 | keep intact all notices of the absence of any warranty; and give all
203 | recipients a copy of this License along with the Program.
204 |
205 | You may charge any price or no price for each copy that you convey,
206 | and you may offer support or warranty protection for a fee.
207 |
208 | 5. Conveying Modified Source Versions.
209 |
210 | You may convey a work based on the Program, or the modifications to
211 | produce it from the Program, in the form of source code under the
212 | terms of section 4, provided that you also meet all of these conditions:
213 |
214 | a) The work must carry prominent notices stating that you modified
215 | it, and giving a relevant date.
216 |
217 | b) The work must carry prominent notices stating that it is
218 | released under this License and any conditions added under section
219 | 7. This requirement modifies the requirement in section 4 to
220 | "keep intact all notices".
221 |
222 | c) You must license the entire work, as a whole, under this
223 | License to anyone who comes into possession of a copy. This
224 | License will therefore apply, along with any applicable section 7
225 | additional terms, to the whole of the work, and all its parts,
226 | regardless of how they are packaged. This License gives no
227 | permission to license the work in any other way, but it does not
228 | invalidate such permission if you have separately received it.
229 |
230 | d) If the work has interactive user interfaces, each must display
231 | Appropriate Legal Notices; however, if the Program has interactive
232 | interfaces that do not display Appropriate Legal Notices, your
233 | work need not make them do so.
234 |
235 | A compilation of a covered work with other separate and independent
236 | works, which are not by their nature extensions of the covered work,
237 | and which are not combined with it such as to form a larger program,
238 | in or on a volume of a storage or distribution medium, is called an
239 | "aggregate" if the compilation and its resulting copyright are not
240 | used to limit the access or legal rights of the compilation's users
241 | beyond what the individual works permit. Inclusion of a covered work
242 | in an aggregate does not cause this License to apply to the other
243 | parts of the aggregate.
244 |
245 | 6. Conveying Non-Source Forms.
246 |
247 | You may convey a covered work in object code form under the terms
248 | of sections 4 and 5, provided that you also convey the
249 | machine-readable Corresponding Source under the terms of this License,
250 | in one of these ways:
251 |
252 | a) Convey the object code in, or embodied in, a physical product
253 | (including a physical distribution medium), accompanied by the
254 | Corresponding Source fixed on a durable physical medium
255 | customarily used for software interchange.
256 |
257 | b) Convey the object code in, or embodied in, a physical product
258 | (including a physical distribution medium), accompanied by a
259 | written offer, valid for at least three years and valid for as
260 | long as you offer spare parts or customer support for that product
261 | model, to give anyone who possesses the object code either (1) a
262 | copy of the Corresponding Source for all the software in the
263 | product that is covered by this License, on a durable physical
264 | medium customarily used for software interchange, for a price no
265 | more than your reasonable cost of physically performing this
266 | conveying of source, or (2) access to copy the
267 | Corresponding Source from a network server at no charge.
268 |
269 | c) Convey individual copies of the object code with a copy of the
270 | written offer to provide the Corresponding Source. This
271 | alternative is allowed only occasionally and noncommercially, and
272 | only if you received the object code with such an offer, in accord
273 | with subsection 6b.
274 |
275 | d) Convey the object code by offering access from a designated
276 | place (gratis or for a charge), and offer equivalent access to the
277 | Corresponding Source in the same way through the same place at no
278 | further charge. You need not require recipients to copy the
279 | Corresponding Source along with the object code. If the place to
280 | copy the object code is a network server, the Corresponding Source
281 | may be on a different server (operated by you or a third party)
282 | that supports equivalent copying facilities, provided you maintain
283 | clear directions next to the object code saying where to find the
284 | Corresponding Source. Regardless of what server hosts the
285 | Corresponding Source, you remain obligated to ensure that it is
286 | available for as long as needed to satisfy these requirements.
287 |
288 | e) Convey the object code using peer-to-peer transmission, provided
289 | you inform other peers where the object code and Corresponding
290 | Source of the work are being offered to the general public at no
291 | charge under subsection 6d.
292 |
293 | A separable portion of the object code, whose source code is excluded
294 | from the Corresponding Source as a System Library, need not be
295 | included in conveying the object code work.
296 |
297 | A "User Product" is either (1) a "consumer product", which means any
298 | tangible personal property which is normally used for personal, family,
299 | or household purposes, or (2) anything designed or sold for incorporation
300 | into a dwelling. In determining whether a product is a consumer product,
301 | doubtful cases shall be resolved in favor of coverage. For a particular
302 | product received by a particular user, "normally used" refers to a
303 | typical or common use of that class of product, regardless of the status
304 | of the particular user or of the way in which the particular user
305 | actually uses, or expects or is expected to use, the product. A product
306 | is a consumer product regardless of whether the product has substantial
307 | commercial, industrial or non-consumer uses, unless such uses represent
308 | the only significant mode of use of the product.
309 |
310 | "Installation Information" for a User Product means any methods,
311 | procedures, authorization keys, or other information required to install
312 | and execute modified versions of a covered work in that User Product from
313 | a modified version of its Corresponding Source. The information must
314 | suffice to ensure that the continued functioning of the modified object
315 | code is in no case prevented or interfered with solely because
316 | modification has been made.
317 |
318 | If you convey an object code work under this section in, or with, or
319 | specifically for use in, a User Product, and the conveying occurs as
320 | part of a transaction in which the right of possession and use of the
321 | User Product is transferred to the recipient in perpetuity or for a
322 | fixed term (regardless of how the transaction is characterized), the
323 | Corresponding Source conveyed under this section must be accompanied
324 | by the Installation Information. But this requirement does not apply
325 | if neither you nor any third party retains the ability to install
326 | modified object code on the User Product (for example, the work has
327 | been installed in ROM).
328 |
329 | The requirement to provide Installation Information does not include a
330 | requirement to continue to provide support service, warranty, or updates
331 | for a work that has been modified or installed by the recipient, or for
332 | the User Product in which it has been modified or installed. Access to a
333 | network may be denied when the modification itself materially and
334 | adversely affects the operation of the network or violates the rules and
335 | protocols for communication across the network.
336 |
337 | Corresponding Source conveyed, and Installation Information provided,
338 | in accord with this section must be in a format that is publicly
339 | documented (and with an implementation available to the public in
340 | source code form), and must require no special password or key for
341 | unpacking, reading or copying.
342 |
343 | 7. Additional Terms.
344 |
345 | "Additional permissions" are terms that supplement the terms of this
346 | License by making exceptions from one or more of its conditions.
347 | Additional permissions that are applicable to the entire Program shall
348 | be treated as though they were included in this License, to the extent
349 | that they are valid under applicable law. If additional permissions
350 | apply only to part of the Program, that part may be used separately
351 | under those permissions, but the entire Program remains governed by
352 | this License without regard to the additional permissions.
353 |
354 | When you convey a copy of a covered work, you may at your option
355 | remove any additional permissions from that copy, or from any part of
356 | it. (Additional permissions may be written to require their own
357 | removal in certain cases when you modify the work.) You may place
358 | additional permissions on material, added by you to a covered work,
359 | for which you have or can give appropriate copyright permission.
360 |
361 | Notwithstanding any other provision of this License, for material you
362 | add to a covered work, you may (if authorized by the copyright holders of
363 | that material) supplement the terms of this License with terms:
364 |
365 | a) Disclaiming warranty or limiting liability differently from the
366 | terms of sections 15 and 16 of this License; or
367 |
368 | b) Requiring preservation of specified reasonable legal notices or
369 | author attributions in that material or in the Appropriate Legal
370 | Notices displayed by works containing it; or
371 |
372 | c) Prohibiting misrepresentation of the origin of that material, or
373 | requiring that modified versions of such material be marked in
374 | reasonable ways as different from the original version; or
375 |
376 | d) Limiting the use for publicity purposes of names of licensors or
377 | authors of the material; or
378 |
379 | e) Declining to grant rights under trademark law for use of some
380 | trade names, trademarks, or service marks; or
381 |
382 | f) Requiring indemnification of licensors and authors of that
383 | material by anyone who conveys the material (or modified versions of
384 | it) with contractual assumptions of liability to the recipient, for
385 | any liability that these contractual assumptions directly impose on
386 | those licensors and authors.
387 |
388 | All other non-permissive additional terms are considered "further
389 | restrictions" within the meaning of section 10. If the Program as you
390 | received it, or any part of it, contains a notice stating that it is
391 | governed by this License along with a term that is a further
392 | restriction, you may remove that term. If a license document contains
393 | a further restriction but permits relicensing or conveying under this
394 | License, you may add to a covered work material governed by the terms
395 | of that license document, provided that the further restriction does
396 | not survive such relicensing or conveying.
397 |
398 | If you add terms to a covered work in accord with this section, you
399 | must place, in the relevant source files, a statement of the
400 | additional terms that apply to those files, or a notice indicating
401 | where to find the applicable terms.
402 |
403 | Additional terms, permissive or non-permissive, may be stated in the
404 | form of a separately written license, or stated as exceptions;
405 | the above requirements apply either way.
406 |
407 | 8. Termination.
408 |
409 | You may not propagate or modify a covered work except as expressly
410 | provided under this License. Any attempt otherwise to propagate or
411 | modify it is void, and will automatically terminate your rights under
412 | this License (including any patent licenses granted under the third
413 | paragraph of section 11).
414 |
415 | However, if you cease all violation of this License, then your
416 | license from a particular copyright holder is reinstated (a)
417 | provisionally, unless and until the copyright holder explicitly and
418 | finally terminates your license, and (b) permanently, if the copyright
419 | holder fails to notify you of the violation by some reasonable means
420 | prior to 60 days after the cessation.
421 |
422 | Moreover, your license from a particular copyright holder is
423 | reinstated permanently if the copyright holder notifies you of the
424 | violation by some reasonable means, this is the first time you have
425 | received notice of violation of this License (for any work) from that
426 | copyright holder, and you cure the violation prior to 30 days after
427 | your receipt of the notice.
428 |
429 | Termination of your rights under this section does not terminate the
430 | licenses of parties who have received copies or rights from you under
431 | this License. If your rights have been terminated and not permanently
432 | reinstated, you do not qualify to receive new licenses for the same
433 | material under section 10.
434 |
435 | 9. Acceptance Not Required for Having Copies.
436 |
437 | You are not required to accept this License in order to receive or
438 | run a copy of the Program. Ancillary propagation of a covered work
439 | occurring solely as a consequence of using peer-to-peer transmission
440 | to receive a copy likewise does not require acceptance. However,
441 | nothing other than this License grants you permission to propagate or
442 | modify any covered work. These actions infringe copyright if you do
443 | not accept this License. Therefore, by modifying or propagating a
444 | covered work, you indicate your acceptance of this License to do so.
445 |
446 | 10. Automatic Licensing of Downstream Recipients.
447 |
448 | Each time you convey a covered work, the recipient automatically
449 | receives a license from the original licensors, to run, modify and
450 | propagate that work, subject to this License. You are not responsible
451 | for enforcing compliance by third parties with this License.
452 |
453 | An "entity transaction" is a transaction transferring control of an
454 | organization, or substantially all assets of one, or subdividing an
455 | organization, or merging organizations. If propagation of a covered
456 | work results from an entity transaction, each party to that
457 | transaction who receives a copy of the work also receives whatever
458 | licenses to the work the party's predecessor in interest had or could
459 | give under the previous paragraph, plus a right to possession of the
460 | Corresponding Source of the work from the predecessor in interest, if
461 | the predecessor has it or can get it with reasonable efforts.
462 |
463 | You may not impose any further restrictions on the exercise of the
464 | rights granted or affirmed under this License. For example, you may
465 | not impose a license fee, royalty, or other charge for exercise of
466 | rights granted under this License, and you may not initiate litigation
467 | (including a cross-claim or counterclaim in a lawsuit) alleging that
468 | any patent claim is infringed by making, using, selling, offering for
469 | sale, or importing the Program or any portion of it.
470 |
471 | 11. Patents.
472 |
473 | A "contributor" is a copyright holder who authorizes use under this
474 | License of the Program or a work on which the Program is based. The
475 | work thus licensed is called the contributor's "contributor version".
476 |
477 | A contributor's "essential patent claims" are all patent claims
478 | owned or controlled by the contributor, whether already acquired or
479 | hereafter acquired, that would be infringed by some manner, permitted
480 | by this License, of making, using, or selling its contributor version,
481 | but do not include claims that would be infringed only as a
482 | consequence of further modification of the contributor version. For
483 | purposes of this definition, "control" includes the right to grant
484 | patent sublicenses in a manner consistent with the requirements of
485 | this License.
486 |
487 | Each contributor grants you a non-exclusive, worldwide, royalty-free
488 | patent license under the contributor's essential patent claims, to
489 | make, use, sell, offer for sale, import and otherwise run, modify and
490 | propagate the contents of its contributor version.
491 |
492 | In the following three paragraphs, a "patent license" is any express
493 | agreement or commitment, however denominated, not to enforce a patent
494 | (such as an express permission to practice a patent or covenant not to
495 | sue for patent infringement). To "grant" such a patent license to a
496 | party means to make such an agreement or commitment not to enforce a
497 | patent against the party.
498 |
499 | If you convey a covered work, knowingly relying on a patent license,
500 | and the Corresponding Source of the work is not available for anyone
501 | to copy, free of charge and under the terms of this License, through a
502 | publicly available network server or other readily accessible means,
503 | then you must either (1) cause the Corresponding Source to be so
504 | available, or (2) arrange to deprive yourself of the benefit of the
505 | patent license for this particular work, or (3) arrange, in a manner
506 | consistent with the requirements of this License, to extend the patent
507 | license to downstream recipients. "Knowingly relying" means you have
508 | actual knowledge that, but for the patent license, your conveying the
509 | covered work in a country, or your recipient's use of the covered work
510 | in a country, would infringe one or more identifiable patents in that
511 | country that you have reason to believe are valid.
512 |
513 | If, pursuant to or in connection with a single transaction or
514 | arrangement, you convey, or propagate by procuring conveyance of, a
515 | covered work, and grant a patent license to some of the parties
516 | receiving the covered work authorizing them to use, propagate, modify
517 | or convey a specific copy of the covered work, then the patent license
518 | you grant is automatically extended to all recipients of the covered
519 | work and works based on it.
520 |
521 | A patent license is "discriminatory" if it does not include within
522 | the scope of its coverage, prohibits the exercise of, or is
523 | conditioned on the non-exercise of one or more of the rights that are
524 | specifically granted under this License. You may not convey a covered
525 | work if you are a party to an arrangement with a third party that is
526 | in the business of distributing software, under which you make payment
527 | to the third party based on the extent of your activity of conveying
528 | the work, and under which the third party grants, to any of the
529 | parties who would receive the covered work from you, a discriminatory
530 | patent license (a) in connection with copies of the covered work
531 | conveyed by you (or copies made from those copies), or (b) primarily
532 | for and in connection with specific products or compilations that
533 | contain the covered work, unless you entered into that arrangement,
534 | or that patent license was granted, prior to 28 March 2007.
535 |
536 | Nothing in this License shall be construed as excluding or limiting
537 | any implied license or other defenses to infringement that may
538 | otherwise be available to you under applicable patent law.
539 |
540 | 12. No Surrender of Others' Freedom.
541 |
542 | If conditions are imposed on you (whether by court order, agreement or
543 | otherwise) that contradict the conditions of this License, they do not
544 | excuse you from the conditions of this License. If you cannot convey a
545 | covered work so as to satisfy simultaneously your obligations under this
546 | License and any other pertinent obligations, then as a consequence you may
547 | not convey it at all. For example, if you agree to terms that obligate you
548 | to collect a royalty for further conveying from those to whom you convey
549 | the Program, the only way you could satisfy both those terms and this
550 | License would be to refrain entirely from conveying the Program.
551 |
552 | 13. Use with the GNU Affero General Public License.
553 |
554 | Notwithstanding any other provision of this License, you have
555 | permission to link or combine any covered work with a work licensed
556 | under version 3 of the GNU Affero General Public License into a single
557 | combined work, and to convey the resulting work. The terms of this
558 | License will continue to apply to the part which is the covered work,
559 | but the special requirements of the GNU Affero General Public License,
560 | section 13, concerning interaction through a network will apply to the
561 | combination as such.
562 |
563 | 14. Revised Versions of this License.
564 |
565 | The Free Software Foundation may publish revised and/or new versions of
566 | the GNU General Public License from time to time. Such new versions will
567 | be similar in spirit to the present version, but may differ in detail to
568 | address new problems or concerns.
569 |
570 | Each version is given a distinguishing version number. If the
571 | Program specifies that a certain numbered version of the GNU General
572 | Public License "or any later version" applies to it, you have the
573 | option of following the terms and conditions either of that numbered
574 | version or of any later version published by the Free Software
575 | Foundation. If the Program does not specify a version number of the
576 | GNU General Public License, you may choose any version ever published
577 | by the Free Software Foundation.
578 |
579 | If the Program specifies that a proxy can decide which future
580 | versions of the GNU General Public License can be used, that proxy's
581 | public statement of acceptance of a version permanently authorizes you
582 | to choose that version for the Program.
583 |
584 | Later license versions may give you additional or different
585 | permissions. However, no additional obligations are imposed on any
586 | author or copyright holder as a result of your choosing to follow a
587 | later version.
588 |
589 | 15. Disclaimer of Warranty.
590 |
591 | THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY
592 | APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT
593 | HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY
594 | OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO,
595 | THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
596 | PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM
597 | IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF
598 | ALL NECESSARY SERVICING, REPAIR OR CORRECTION.
599 |
600 | 16. Limitation of Liability.
601 |
602 | IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
603 | WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS
604 | THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY
605 | GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE
606 | USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF
607 | DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD
608 | PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS),
609 | EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF
610 | SUCH DAMAGES.
611 |
612 | 17. Interpretation of Sections 15 and 16.
613 |
614 | If the disclaimer of warranty and limitation of liability provided
615 | above cannot be given local legal effect according to their terms,
616 | reviewing courts shall apply local law that most closely approximates
617 | an absolute waiver of all civil liability in connection with the
618 | Program, unless a warranty or assumption of liability accompanies a
619 | copy of the Program in return for a fee.
620 |
621 | END OF TERMS AND CONDITIONS
622 |
623 | How to Apply These Terms to Your New Programs
624 |
625 | If you develop a new program, and you want it to be of the greatest
626 | possible use to the public, the best way to achieve this is to make it
627 | free software which everyone can redistribute and change under these terms.
628 |
629 | To do so, attach the following notices to the program. It is safest
630 | to attach them to the start of each source file to most effectively
631 | state the exclusion of warranty; and each file should have at least
632 | the "copyright" line and a pointer to where the full notice is found.
633 |
634 |
635 | Copyright (C)
636 |
637 | This program is free software: you can redistribute it and/or modify
638 | it under the terms of the GNU General Public License as published by
639 | the Free Software Foundation, either version 3 of the License, or
640 | (at your option) any later version.
641 |
642 | This program is distributed in the hope that it will be useful,
643 | but WITHOUT ANY WARRANTY; without even the implied warranty of
644 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
645 | GNU General Public License for more details.
646 |
647 | You should have received a copy of the GNU General Public License
648 | along with this program. If not, see .
649 |
650 | Also add information on how to contact you by electronic and paper mail.
651 |
652 | If the program does terminal interaction, make it output a short
653 | notice like this when it starts in an interactive mode:
654 |
655 | Copyright (C)
656 | This program comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
657 | This is free software, and you are welcome to redistribute it
658 | under certain conditions; type `show c' for details.
659 |
660 | The hypothetical commands `show w' and `show c' should show the appropriate
661 | parts of the General Public License. Of course, your program's commands
662 | might be different; for a GUI interface, you would use an "about box".
663 |
664 | You should also get your employer (if you work as a programmer) or school,
665 | if any, to sign a "copyright disclaimer" for the program, if necessary.
666 | For more information on this, and how to apply and follow the GNU GPL, see
667 | .
668 |
669 | The GNU General Public License does not permit incorporating your program
670 | into proprietary programs. If your program is a subroutine library, you
671 | may consider it more useful to permit linking proprietary applications with
672 | the library. If this is what you want to do, use the GNU Lesser General
673 | Public License instead of this License. But first, please read
674 | .
675 |
--------------------------------------------------------------------------------
/4_Comments(completed)/4_Comments.md:
--------------------------------------------------------------------------------
1 | 
2 |
3 | # کامنتها ۴
4 |
5 | « کد بد را کامنت نکنید – دوباره بنویسید.»
6 | —Brian W. Kernighan and P. J. Plaugher
7 |
8 | هیچ چیز نمیتواند به اندازه ی یک کامنت که در جای مناسب قرار گرفته مفید باشد. هیچ چیز نمیتواند یک ماژول را به اندازه ی کامنتهای بیهوده به هم بریزد. هیچ چیز نمیتواند مضر تراز یک کامنت ضعیف قدیمی که اطلاعات غلط میدهد باشد.
9 |
10 | کامنتها شبیه شیندلرلیست (نام یک فیلم) نیستند . آنها کاملا خوب نیستند. در حقیقت کامنتها جنایت های لازمی هستند .اگر زبان های برنامه نویسی ما به اندازه ی کافی رسا بودند یا ما تونایی استفاده ی ماهرانه از ان زبان ها برای بیان منظور را داشتیم خیلی به کامنتها نیاز نداشتیم . شاید هم اصلا!
11 |
12 | کاربرد مناسب کامنت برای جبران شکست رساندن مفهوم با کد است . توجه داشته باشید از واژه شکست استفاده میکنم.منظورم این است که کامنتها همیشه نشانه شکست هستند . ما باید از آنها استفاده کنیم چون همیشه راهی برای توضیح دادن منظورمان بدون آنها پیدا نمی کنیم ولی استفاده از آنها دلیلی برای خوشحالی نیست.
13 |
14 | وقتی خودتان را در موقعیتی میبینید که کامنت بگذارید، در موردش فکر کنید و ببینید راهی برای عوض کد و توضیح منظورتان در کد وجود ندارد؟ هر بار که میتوانید منظورتان را درخود کد برسانید باید خودتان را تشویق کنید . هر بار که منظورتان را در کامنت توضیح میدهید، باید به خودتان دهن کجی کنید واز توانایی بیانتان احساس شکست کنید .
15 |
16 | چرا من انقدر با کامنت مخالفم؟چون آنها دروغ میگویند. نه همیشه ونه عمدا،ولی خیلی زیاد.
17 | هر چه کامنت قدیمی تر باشد و از کدی که توصیف میکند دورتر باشد ، بیشتر احتمال دارد که اشتباه باشد.دلیلش ساده است، برنامه نویس ها نمیتوانند واقع بینانه از انها استفاده کنند.
18 |
19 | کد تغییر میکند و تکامل پیدا میکند. تکه های آن جابه جا میشود.آن تکه ها دوشاخه 1 و باز نویسی میشوند و دوباره گرد هم می آیند تا یک چیز خارق العاده را خلق کنند.
20 |
21 | متاسفانه کامنتها همیشه آنها را دنبال نمیکنند-در واقع نمیتوانند دنبال کنند.اغلب اوقات از کدی که توصیف میکنند فاصله میگیرند وتکه های بریده ای میشوند که باعث کاهش مداوم دقت هستند. به طور مثال ، ببینید چه اتفاقی برای این کامنت و کدی که قصد داشت توضیح بدهد افتاد:
22 |
23 |
24 | ```java
25 | MockRequest request;
26 | private final String HTTP_DATE_REGEXP =
27 | "[SMTWF][a-z]{2}\\,\\s[0-9]{2}\\s[JFMASOND][a-z]{2}\\s"+
28 | "[0-9]{4}\\s[0-9]{2}\\:[0-9]{2}\\:[0-9]{2}\\sGMT";
29 | private Response response;
30 | private FitNesseContext context;
31 | private FileResponder responder;
32 | private Locale saveLocale;
33 | ```
34 |
35 | بقیه ی متغیر های نمونه احتمالا بعدا بین ثابت HTTP_DATE_REGEXP وکامنت توضیحی آن اضافه شده اند.
36 |
37 | می توان این نکته را بیان کرد که برنامه نویسان باید به اندازه کافی نظم و انضباط داشته باشند که کامنت را به روز،مرتبط و دقیق نگه دارند.
38 |
39 | من موافق این کار هستم اما ترجیح میدهم آنها این انرژی را صرف واضح کردن کد کنند که در وهله اول نیاز به کامنت نداشته باشد.
40 | کامنتهای نادرست به مراتب بدتر از نبود هیچ کامنتی هستند. آنها خواننده را گمراه میکنند. آنها انتظاراتی به وجود می اورند که هیچ وقت براورده نمیکنند و قوانینی را مشخص میکنند که لازم نیست یا نباید بعد از این دنبال شوند.
41 |
42 | حقیقت را در یک جا میتوان یافت:کد. فقط کد میتواند به درستی به شما بگوید چه کاری انجام میدهد.این تنها منبع درست اطلاعات است.بنابراین، با اینکه کامنتها بعضی اوقات لازم اند ، ما انرژی زیادی صرف میکنیم تا آنها را به کمترین حد برسانیم.
43 |
44 |
45 | ## کامنتها برای کد بد نوشته نشده اند
46 | یکی از انگیزه های رایج نوشتن کامنت کد بد است. ما یک ماژول مینویسیم و میدانیم که گیجکننده و بی نظم است. میدانیم که کثیف است. ما خودمان میدانیم و به خود میگوییم:,
47 | «اوه ،بهتراست کامنتش کنم»، نه! بهتراست پاکش کنی.
48 | کامنتهای زیاد بهتر است. به جای اینکه وقتتان را صرف نوشتن کامنت روی کد کثیف کنید که آن را توضیح دهد، صرف تمیز کردنش کنید
49 |
50 | ## منظورتان را با کد برسانید
51 | مطمئناً مواردی وجود دارد که کد وسیله ی ضعیفی برای توصیف است. متاسفانه بسیاری از برنامه نویسان این را اینطور برداشت کرده اند که کد بندرت میتواند راه خوبی برای توصیف باشد. این به وضوح اشتباه است. شما ترجیح میدهید کدام را ببینید؟ این:
52 |
53 |
54 | ```java
55 | // Check to see if the employee is eligible for full benefits
56 | if ((employee.flags & HOURLY_FLAG) &&
57 | (employee.age > 65))
58 | ```
59 |
60 | یا این؟
61 |
62 |
63 | ```java
64 | if (employee.isEligibleForFullBenefits())
65 | ```
66 |
67 | فقط چند ثانیه زمان میبرد که بیشتر منظورتان را در کد توضیح دهید . در بیشتر موارد این به سادگی ایجاد یک تابع است که همان چیزی را می گوید که با کامنت می خواهید بگویید.
68 |
69 | ## کامنتهای خوب
70 | بعضی از کامنتها لازم یا مفید هستند. ما چند مورد را بررسی میکنیم که من آنها را لایق بیت هایی که مصرف میکنند میدانم. به خاطر داشته باشید، در هر حال، تنها کامنتی که واقعا خوب است کامنتی است که راهی برای ننوشتنش پیدا کنیم.
71 |
72 | ## کامنتهای قانونی
73 | گاهی اوقات استاندارد های برنامه نویسی شرکتی ما را مجبور میکند به دلایل قانونی کامنتهای مشخصی بنویسیم. برای مثال کپی رایت و حق تالیف چیز های منطقی و لازمی هستند برای اینکه اول هر سورس کدی قرار بگیرند.
74 |
75 | در اینجا، مثلا، این یک کامنت استاندارد است که درا ول همه سورس ها در FitNesse قرار میدهیم. خوشحالم که بگویم IDE ما با از بین بردن این کامنت به طور اتوماتیک، از عمل کردن آن به عنوان یک اخلال گر جلوگیری میکند.
76 |
77 |
78 | ```java
79 | // Copyright (C) 2003,2004,2005 by Object Mentor, Inc. All rights reserved.
80 | // Released under the terms of the GNU General Public License version 2 or later.
81 | ```
82 |
83 | کامنتهایی مانند این نباید نوشته شوند. تا جایی که ممکن است، به مجوز های استاندارد یا بقیه ی مدارک خارجی مراجعه شود ، به جای اینکه همه ی آن شرایط و ضوابط را در کامنت قرار دهیم.
84 |
85 | ## کامنتهای آموزنده
86 | ارائه ی اطلاعات پایه ای در کامنت مفید است. برای مثال ، به نظر می آید که این کامنت مقدار بازگشتی یک متد abstractرا برمیگرداند .
87 |
88 |
89 | ```java
90 | // Returns an instance of the Responder being tested.
91 | protected abstract Responder responderInstance();
92 | ```
93 |
94 | یک کامنت مثل این گاهی میتواند مفید باشد، اما بهتر است تاجای ممکن برای انتقال اطلاعات از نام تابع استفاده کنیم . مثلا، دراین مورد کامنت می تواند با عوض کردن نام تابع حذف شود. responderBeingTested .
95 | در این مورد کمی بهتر است:
96 |
97 |
98 | ```java
99 | // format matched kk:mm:ss EEE, MMM dd, yyyy
100 | Pattern timeMatcher = Pattern.compile(
101 | "\\d*:\\d*:\\d* \\w*, \\w* \\d*, \\d*");
102 | ```
103 |
104 | در این مورد کامنت به ما اجازه میدهد بدانیم که این عبارت منظم برای مطابقت زمان و تاریخ در نظر گرفته شده است که با SimpleDateFormat.format قالب بندی(فرمت) شده است.
105 | تابعی که از فرمت استرینگ معینی استفاده میکند.باز هم میتوانست بهتر باشد ، و واضح تر،اگر این کد به کلاس خاصی که فرمت های تاریخ و زمان را تغییر می دهدمنتقل شده بود ،سپس کامنت احتمالا زیادی میشد.
106 |
107 | ## شرح نیت
108 |
109 | بعضی اوقات یک کامنت فقط از دادن اطلاعات مفید در مورد اجرا فراتر می رود و هدف تصمیم گیری را فراهم می کند. در مورد زیر ، یک تصمیم جالب را می بینیم که توسط یک کامنت مستند شده است. هنگام مقایسه دو شی، ، نویسنده به این نتیجه رسید که می خواهد اشیا کلاس خود را بالاتر از اشیا دیگر مرتب کند.
110 |
111 |
112 |
113 | ```java
114 | public int compareTo(Object o)
115 | {
116 | if(o instanceof WikiPagePath)
117 | {
118 | WikiPagePath p = (WikiPagePath) o;
119 | String compressedName = StringUtil.join(names, "");
120 | String compressedArgumentName = StringUtil.join(p.names, "");
121 | return compressedName.compareTo(compressedArgumentName);
122 | }
123 | return 1; // we are greater because we are the right type.
124 | }
125 | ```
126 |
127 |
128 |
129 | در اینجا یک مثال حتی بهتر است. شما ممکن است با راه حل برنامه نویس برای مشکل موافق نباشید ، اما حداقل می دانید که او می خواست چه کاری انجام دهد.
130 |
131 |
132 |
133 | ```java
134 | public void testConcurrentAddWidgets() throws Exception {
135 | WidgetBuilder widgetBuilder =
136 | new WidgetBuilder(new Class[]{BoldWidget.class});
137 | String text = "'''bold text'''";
138 | ParentWidget parent =
139 | new BoldWidget(new MockWidgetRoot(), "'''bold text'''");
140 | AtomicBoolean failFlag = new AtomicBoolean();
141 | failFlag.set(false);
142 | //This is our best attempt to get a race condition
143 | //by creating large number of threads.
144 | for (int i = 0; i < 25000; i++) {
145 | WidgetBuilderThread widgetBuilderThread =
146 | new WidgetBuilderThread(widgetBuilder, text, parent, failFlag);
147 | Thread thread = new Thread(widgetBuilderThread);
148 | thread.start();
149 | }
150 | assertEquals(false, failFlag.get());
151 | }
152 | ```
153 |
154 |
155 |
156 | ## شفاف سازی
157 |
158 | گاهی اوقات فقط ترجمه معنای برخی از آرگومانهای مبهم یا بازگردان مقدار به چیزی که قابل فهمیدن بوده، مفید است. به طور کلی ، بهتر است راهی پیدا کنید که آن آرگومان یا مقدار بازگشتی را به خودی خود روشن کند. اما اگر بخشی از آن در کتابخانه استاندارد باشد یا در کدی باشد که نمی توانید تغییر دهید ، یک توضیح روشن و خوب می تواند مفید باشد.
159 |
160 |
161 |
162 | ```java
163 | public void testCompareTo() throws Exception
164 | {
165 | WikiPagePath a = PathParser.parse("PageA");
166 | WikiPagePath ab = PathParser.parse("PageA.PageB");
167 | WikiPagePath b = PathParser.parse("PageB");
168 | WikiPagePath aa = PathParser.parse("PageA.PageA");
169 | WikiPagePath bb = PathParser.parse("PageB.PageB");
170 | WikiPagePath ba = PathParser.parse("PageB.PageA");
171 | assertTrue(a.compareTo(a) == 0); // a == a
172 | assertTrue(a.compareTo(b) != 0); // a != b
173 | assertTrue(ab.compareTo(ab) == 0); // ab == ab
174 | assertTrue(a.compareTo(b) == -1); // a < b
175 | assertTrue(aa.compareTo(ab) == -1); // aa < ab
176 | assertTrue(ba.compareTo(bb) == -1); // ba < bb
177 | assertTrue(b.compareTo(a) == 1); // b > a
178 | assertTrue(ab.compareTo(aa) == 1); // ab > aa
179 | assertTrue(bb.compareTo(ba) == 1); // bb > ba
180 | }
181 | ```
182 |
183 |
184 |
185 | البته یک خطر اساسی وجود دارد که یک کامنت روشن نادرست باشد. مثال قبلی را مرور کنید و ببینید تایید صحت آنها چقدر دشوار است. هم شفافسازی لازم است و هم اینکه چرا خطرناک است. بنابراین قبل از نوشتن کامنتهایی از این دست ، مراقب باشید که راهی بهتر وجود نداشته باشد و حتی بیشتر دقت کنید که درست باشند.
186 |
187 |
188 |
189 | 
190 |
191 |
192 |
193 | ## هشدار پیامدها
194 |
195 | گاهی اوقات مفید است که به سایر برنامه نویسان در مورد عواقب خاص هشدار دهید. به عنوان مثال ، در اینجا یک کامنت وجود دارد که توضیح می دهد چرا یک مورد آزمایشی خاص خاموش است:
196 |
197 |
198 |
199 | ```java
200 | // Don't run unless you
201 | // have some time to kill.
202 | public void _testWithReallyBigFile()
203 | {
204 | writeLinesToFile(10000000);
205 | response.setBody(testFile);
206 | response.readyToSend(this);
207 | String responseString = output.toString();
208 | assertSubString("Content-Length: 1000000000", responseString);
209 | assertTrue(bytesSent > 1000000000);
210 | }
211 | ```
212 |
213 |
214 | البته امروزه ، ما می توانیم با استفاده از ویژگی @Ignore با یک رشته توضیحی مناسب ، مورد آزمایشی را خاموش کنیم. @Ignore ("برای اجرای خیلی طولانی می شود"). اما در روزهای قبل از JUnit4 ، قرار دادن underscore در مقابل نام متد یک امر عادی بود. این کامنت هر چند گنگ است ، اما نکته را به خوبی بیان می کند.در اینجا مثال مهیج تر دیگری وجود دارد:
215 |
216 |
217 |
218 | ```java
219 | public static SimpleDateFormat makeStandardHttpDateFormat()
220 | {
221 | //SimpleDateFormat is not thread safe,
222 | //so we need to create each instance independently.
223 | SimpleDateFormat df = new SimpleDateFormat("EEE, dd MMM yyyy HH:mm:ss z");
224 | df.setTimeZone(TimeZone.getTimeZone("GMT"));
225 | return df;
226 | }
227 | ```
228 |
229 |
230 |
231 | ممکن است شکایت کنید که روش های بهتری برای حل این مشکل وجود دارد. ممکن است با شما موافق باشم اما کامنت ، همانطور که در اینجا ارائه شد ، کاملاً منطقی است. این باعث می شود که برخی از برنامه نویسان بیش از حد مشتاق از یک مقداردهنده اولیه ثابت برای کارایی استفاده نکنند.
232 |
233 | ## TODO کامنتهای
234 |
235 | گاهی اوقات منطقی است که یادداشت های "TODO" را در قالب کامنتهای TODO // انجام دهید. در مورد زیر ، کامنتهای TODO توضیح می دهد که چرا این تابع یک اجرای منحط دارد و آینده آن تابع چگونه است.
236 |
237 |
238 |
239 | ```java
240 | //TODO-MdM these are not needed
241 | // We expect this to go away when we do the checkout model
242 | protected VersionInfo makeVersion() throws Exception
243 | {
244 | return null;
245 | }
246 | ```
247 |
248 |
249 |
250 | TODO کارهایی است که به نظر برنامه نویس باید انجام شود ، اما به دلایلی فعلاً نمی تواند انجام دهد. این ممکن است یک یادآوری برای حذف یک ویژگی منسوخ شده یا یک درخواست برای شخص دیگری برای بررسی یک مشکل باشد. این ممکن است درخواستی باشد که شخص دیگری به نام بهتر فکر کند یا یادآوری باشد برای ایجاد تغییری وابسته به یک برنامه ریزی. TODO هرچه باشد ، بهانه ای برای گذاشتن کد بد در سیستم نیست.
251 |
252 | امروزه ، اکثر IDE های خوب ویژگی های خاصی را برای یافتن همه کامنتهای TODO ارائه می دهند ، بنابراین احتمالاً گم نمی شوند. اگر هم نمی خواهید کد شما با TODO پر شود، مرتباً از طریق آنها اسکن کرده و مواردی را که می توانید حذف کنید.
253 |
254 | ## تقویت
255 |
256 | ممکن است کامنت برای تقویت اهمیت چیزی استفاده شود که در غیر این صورت بی اهمیت به نظر می رسد.
257 |
258 |
259 |
260 | ```java
261 | String listItemContent = match.group(3).trim();
262 | // the trim is real important. It removes the starting
263 | // spaces that could cause the item to be recognized
264 | // as another list.
265 | new ListItemWidget(this, listItemContent, this.level + 1);
266 | return buildList(text.substring(match.end()));
267 | ```
268 |
269 |
270 |
271 | ## اسناد java در API های عمومی
272 |
273 | هیچ چیز به اندازه یک API عمومی خوشتوضیح، مفید و رضایت بخش وجود ندارد. javadocs برای کتابخانه استاندارد جاوا نمونه ای از این موارد است. در بهترین حالت نوشتن برنامه های جاوا بدون آنها دشوار خواهد بود.
274 |
275 | اگر در حال نوشتن یک API عمومی هستید ، مطمئناً باید javadocs خوبی برای آن بنویسید. اما بقیه توصیه های این فصل را به خاطر بسپارید. Javadocs می تواند مانند هر نوع نظر دیگر گمراه کننده ، غیرمحلی و غیر صادق باشد.
276 |
277 | # کامنتهای بد
278 |
279 | بیشتر کامنتها در این گروه قرار می گیرند. معمولاً آنها بهانهای برای کد ضعیف یا توجیهی برای تصمیمات ناکافی هستند، کمی بیشتر از صحبت های برنامه نویس با خودش.
280 |
281 | ## غرزدن
282 |
283 | یهویی کامنتی نوشتن فقط به این دلیل که احساس می کنید باید این کار را انجام دهید یا این که روند کار به آن نیاز دارد، جالب نیست. اگر تصمیم دارید یک کامنت بنویسید ، وقت لازم را صرف کنید تا مطمئن شوید بهترین کامنتی است که می توانید بنویسید.
284 |
285 | به عنوان مثال ، این مورد موردی است که من در FitNesse پیدا کردم ، جایی که یک کامنت واقعاً مفید بوده است. اما نویسنده عجله داشت یا فقط توجه زیادی نمیکرد. غر زدن او یک معما را پشت سر گذاشت:
286 |
287 |
288 |
289 | ```java
290 | public void loadProperties()
291 | {
292 | try
293 | {
294 | String propertiesPath = propertiesLocation + "/" + PROPERTIES_FILE;
295 | FileInputStream propertiesStream = new FileInputStream(propertiesPath);
296 | loadedProperties.load(propertiesStream);
297 | }
298 | catch(IOException e)
299 | {
300 | // No properties files means all defaults are loaded
301 | }
302 | }
303 | ```
304 |
305 |
306 |
307 | این کامنت در بلوک catch به چه معناست؟ واضح است که این برای نویسنده معنی داشته است ، اما معنی آن واضح نیست. ظاهراً ، اگر IOException دریافت کنیم ، به این معنی است که هیچ فایلی وجود نداشته است. و در این حالت تمام پیش فرض ها بارگیری می شوند. اما چه کسی تمام پیش فرض ها را بارگیری می کند؟ آیا آنها قبل از صدازدن loadProperties.load بارگیری شده اند؟ یا آیا loadProperties.load استثنا را گرفت ، پیش فرض ها را بارگذاری کرد و سپس استثنا را به ما منتقل کرد تا نادیده بگیریم؟ یا آیا loadProperties.load قبل از بارگیری فایل ، همه پیش فرض ها را بارگیری کرده است؟ آیا نویسنده سعی در دلجویی از این واقعیت داشت که بلوک catch را خالی می گذارد؟ یا - و این احتمال ترسناک است - آیا نویسنده سعی داشته به خودش بگوید بعداً به اینجا برگردد و کدی را بنویسد که پیش فرض ها را بارگیری کند؟
308 |
309 | تنها راه حل ما این است که کد را در قسمت های دیگر سیستم بررسی کنیم تا بفهمیم چه خبر است. هر کامنتی که شما را مجبور کند به دنبال معنای آن کامنت در یک ماژول دیگر بگردید ، در برقراری ارتباط با شما ناموفق بوده و ارزش بیت های مصرفی آن را ندارد.
310 |
311 | ## کامنتهای اضافی
312 |
313 | لیست 4-1 تابع ساده ای را با یک عنوان هدر کاملاً زائد نشان می دهد.
314 | خواندن این کامنت احتمالاً طولانی تر از خود کد است.
315 |
316 |
317 |
318 | Listing 4-1
319 |
320 | waitForClose
321 | ```java
322 | // Utility method that returns when this.closed is true. Throws an exception
323 | // if the timeout is reached.
324 | public synchronized void waitForClose(final long timeoutMillis)
325 | throws Exception
326 | {
327 | if(!closed)
328 | {
329 | wait(timeoutMillis);
330 | if(!closed)
331 | throw new Exception("MockResponseSender could not be closed");
332 | }
333 | }
334 | ```
335 |
336 |
337 | این کامنت چه هدفی را دنبال می کند؟ مطمئناً از کد بیشتر آموزنده نیست. این کد را توجیه نمی کند ، یا قصد یا منطقی را ارائه نمی دهد. خواندن آن از کد آسان نیست. در حقیقت ، دقت آن کمتر از کد است و خواننده را فریب می دهد که به جای درک درست ، عدم دقت را بپذیرد. این کار دقیقاً مانند این است که یک فروشنده ماشین دست دوم خوشحال به شما اطمینان دهد که نیازی به دیدن زیر کاپوت نیست.
338 |
339 | اکنون javadocs بی فایده و زائد را در لیست 4-2 برگرفته از تامکت در نظر بگیرید. این کامنتها فقط برای بهم ریختن و پنهان کردن کد کار می کنند. اصلاً هدف مستندی ندارند. برای بدتر کردن ، من فقط چند مورد اول را به شما نشان دادم. تعداد بیشتری در این ماژول وجود دارد.
340 |
341 |
342 |
343 | Listing 4-2
344 |
345 | ContainerBase.java (Tomcat)
346 | ```java
347 | public abstract class ContainerBase
348 | implements Container, Lifecycle, Pipeline,
349 | MBeanRegistration, Serializable {
350 | /**
351 | * The processor delay for this component.
352 | */
353 | protected int backgroundProcessorDelay = -1;
354 | /**
355 | * The lifecycle event support for this component.
356 | */
357 | protected LifecycleSupport lifecycle =
358 | new LifecycleSupport(this);
359 | /**
360 | * The container event listeners for this Container.
361 | */
362 | protected ArrayList listeners = new ArrayList();
363 | /**
364 | * The Loader implementation with which this Container is
365 | * associated.
366 | */
367 | protected Loader loader = null;
368 | /**
369 | * The Logger implementation with which this Container is
370 | * associated.
371 | */
372 | protected Log logger = null;
373 | /**
374 | * Associated logger name.
375 | */
376 | protected String logName = null;
377 | /**
378 | * The Manager implementation with which this Container is
379 | * associated.
380 | */
381 | protected Manager manager = null;
382 | /**
383 | * The cluster with which this Container is associated.
384 | */
385 | protected Cluster cluster = null;
386 | /**
387 | * The human-readable name of this Container.
388 | */
389 | protected String name = null;
390 | /**
391 | * The parent Container to which this Container is a child.
392 | */
393 | protected Container parent = null;
394 | /**
395 | * The parent class loader to be configured when we install a
396 | * Loader.
397 | */
398 | protected ClassLoader parentClassLoader = null;
399 | /**
400 | * The Pipeline object with which this Container is
401 | * associated.
402 | */
403 | protected Pipeline pipeline = new StandardPipeline(this);
404 | /**
405 | * The Realm with which this Container is associated.
406 | */
407 | protected Realm realm = null;
408 | /**
409 | * The resources DirContext object with which this Container
410 | * is associated.
411 | */
412 | protected DirContext resources = null;
413 | }
414 | ```
415 |
416 |
417 |
418 | ## کامنتهای گمراه کننده
419 |
420 | گاهی اوقات ، با بهترین آرزوها ، یک برنامه نویس بیانیه ای را در کامنتهای خود ارائه می دهد که دقیق نیست. لیست ۴-۲ را درنظر بگیرید.
421 |
422 | آیا کشف کردید که چگونه این کامنت گمراه کننده است؟ وقتی this.closed درست است، این متد چیزی برنمی گرداند. اگر this.closed درست باشد ، بر می گردد. در غیر این صورت ، منتظر تایم اوت است و اگر this.closed همچنان درست نباشد، exception پرتاب میشود.
423 |
424 | این اطلاعات نادرست ، که در کامنتی ارائه می شود که خواندن آن دشوارتر از متن کد است ، می تواند باعث شود تا برنامه نویس دیگری با خیال راحت این تابع را صدا زند. آن برنامه نویس ضعیف سپس خود را درحال رفع اشکال پیدا می کند و می خواهد بفهمد چرا کد او به این کندی اجرا شده است.
425 |
426 | ## کامنتهای مجاز
427 |
428 | این یک قانون احمقانهای است که هر تابع باید یک javadoc، یا هر متغیر باید یک کامنت داشته باشد. کامنتهایی از این دست فقط کد را بهم می ریزند ، دروغ ها را تبلیغ می کنند ، و باعث سردرگمی و بی نظمی می شوند.
429 |
430 | به عنوان مثال ، javadocs مورد نیاز برای هر تابع منجر به مکروهاتی مانند لیست 4-3 می شود. این بی نظمی چیزی اضافه نمی کند و فقط باعث کدرشدن کد و ایجاد پتانسیل دروغ وسوتفاهم میشود.
431 |
432 |
433 |
434 | Listing 4-3
435 | ```java
436 | /**
437 | *
438 | * @param title The title of the CD
439 | * @param author The author of the CD
440 | * @param tracks The number of tracks on the CD
441 | * @param durationInMinutes The duration of the CD in minutes
442 | */
443 | public void addCD(String title, String author,
444 | int tracks, int durationInMinutes) {
445 | CD cd = new CD();
446 | cd.title = title;
447 | cd.author = author;
448 | cd.tracks = tracks;
449 | cd.duration = duration;
450 | cdList.add(cd);
451 | }
452 | ```
453 |
454 |
455 |
456 | ## کامنتهای گزارشی
457 |
458 | گاهی اوقات افراد هر بار که ویرایش می کنند یک کامنت به شروع ماژول اضافه می کنند. این کامنتها به عنوان نوعی ژورنال ، یا گزارش ، از هر تغییری که ایجاد شده است جمع می شود. من چند ماژول با ده ها صفحه از این ورودی های ژورنال دیده ام.
459 |
460 |
461 |
462 | ```
463 | Changes (from 11-Oct-2001)
464 | --------------------------
465 | * 11-Oct-2001 : Re-organised the class and moved it to new package
466 | * com.jrefinery.date (DG);
467 | * 05-Nov-2001 : Added a getDescription() method, and eliminated NotableDate
468 | * class (DG);
469 | * 12-Nov-2001 : IBD requires setDescription() method, now that NotableDate
470 | * class is gone (DG); Changed getPreviousDayOfWeek(),
471 | * getFollowingDayOfWeek() and getNearestDayOfWeek() to correct
472 | * bugs (DG);
473 | * 05-Dec-2001 : Fixed bug in SpreadsheetDate class (DG);
474 | * 29-May-2002 : Moved the month constants into a separate interface
475 | * (MonthConstants) (DG);
476 | * 27-Aug-2002 : Fixed bug in addMonths() method, thanks to N???levka Petr (DG);
477 | * 03-Oct-2002 : Fixed errors reported by Checkstyle (DG);
478 | * 13-Mar-2003 : Implemented Serializable (DG);
479 | * 29-May-2003 : Fixed bug in addMonths method (DG);
480 | * 04-Sep-2003 : Implemented Comparable. Updated the isInRange javadocs (DG);
481 | * 05-Jan-2005 : Fixed bug in addYears() method (1096282) (DG);
482 | ```
483 |
484 |
485 |
486 | مدت ها پیش دلیل خوبی برای ایجاد و نگهداری این ورودی های log در ابتدای هر ماژول وجود داشت. ما سیستم های کنترل کد منبع نداشتیم که این کار را برای ما انجام دهند. امروزه ، این ژورنالهای طولانی فقط به ماژول آشفتگی اضافه میکنند. باید کاملاً برداشته شوند.
487 |
488 | ## کامنتهای شلوغ
489 |
490 | بعضی اوقات کامنتهایی را می بینید که چیزی جز سر و صدا نیست. موارد واضحی را بیان می کنند و هیچ اطلاعات جدیدی ارائه نمی دهند.
491 |
492 |
493 |
494 | ```java
495 | /**
496 | * Default constructor.
497 | */
498 | protected AnnualDateRule() {
499 | }
500 | ```
501 |
502 |
503 |
504 | نه، واقعا؟ یا چگونه در مورد این:
505 |
506 |
507 |
508 | ```java
509 | /** The day of the month. */
510 | private int dayOfMonth;
511 | ```
512 |
513 |
514 |
515 | و سپس این مثال اضافی وجود دارد:
516 |
517 |
518 |
519 | ```java
520 | /**
521 | * Returns the day of the month.
522 | *
523 | * @return the day of the month.
524 | */
525 | public int getDayOfMonth() {
526 | return dayOfMonth;
527 | }
528 | ```
529 |
530 |
531 |
532 | این کامنتها آنقدر پر سر و صدا هستند که یاد می گیریم آنها را نادیده بگیریم. وقتی کد را می خوانیم ، چشمانمان به راحتی از روی آنها عبور می کنند. سرانجام با تغییر کد پیرامون ، کامنتها شروع به دروغ گفتن می کنند.
533 |
534 | اولین کامنت در لیست 4-4 مناسب به نظر می رسد. دلیل نادیده گرفته شدن بلوک catch را توضیح می دهد. اما کامنت دوم کاملا سر و صدا است. ظاهراً برنامه نویس از نوشتن بلوک های try / catch در این تابع آنقدر ناامید شده بود که نیاز به تخلیه داشت.
535 |
536 |
537 |
538 | Listing 4-4
539 |
540 | startSending
541 |
542 | ```java
543 | private void startSending()
544 | {
545 | try
546 | {
547 | doSending();
548 | }
549 | catch(SocketException e)
550 | {
551 | // normal. someone stopped the request.
552 | }
553 | catch(Exception e)
554 | {
555 | try
556 | {
557 | response.add(ErrorResponder.makeExceptionString(e));
558 | response.closeAll();
559 | }
560 | catch(Exception e1)
561 | {
562 | //Give me a break!
563 | }
564 | }
565 | }
566 | ```
567 |
568 |
569 |
570 | به جای تخلیه کامنتهای بی ارزش و پر سر و صدا ، برنامه نویس باید تشخیص می داد که با بهبود ساختار کد خود می تواند ناامیدی او را برطرف کند. باید انرژی خود را به استخراج آخرین بلوک try / catch به یک تابع جداگانه هدایت کند ، همانطور که در لیست 4-5 نشان داده شده است.
571 |
572 |
573 |
574 | Listing 4-5
575 | ```java
576 | startSending (refactored)
577 | private void startSending()
578 | {
579 | try
580 | {
581 | doSending();
582 | }
583 | catch(SocketException e)
584 | {
585 | // normal. someone stopped the request.
586 | }
587 | catch(Exception e)
588 | {
589 | addExceptionAndCloseResponse(e);
590 | }
591 | }
592 | private void addExceptionAndCloseResponse(Exception e)
593 | {
594 | try
595 | {
596 | response.add(ErrorResponder.makeExceptionString(e));
597 | response.closeAll();
598 | }
599 | catch(Exception e1)
600 | {
601 | }
602 | }
603 | ```
604 |
605 |
606 |
607 | وسوسه ایجاد نویز را با تصمیم برای پاک کردن کد خود جایگزین کنید. خواهید فهمید که این باعث می شود شما یک برنامه نویس بهتر و شاد باشید.
608 |
609 | ## شلوغی هولناک
610 |
611 | Javadocs همچنین می تواند پر سر و صدا باشد. Javadocs زیر (از یک کتابخانه منبع باز مشهور) چه هدفی را دنبال می کند؟ جواب: هیچی. فقط کامنتهای پر سر و صداي زائدي هستند كه به دليل تمايل بي جا به ارائه مستندات نوشته شده اند.
612 |
613 |
614 |
615 | ```java
616 | /** The name. */
617 | private String name;
618 | /** The version. */
619 | private String version;
620 | /** The licenceName. */
621 | private String licenceName;
622 | /** The version. */
623 |
624 | private String info;
625 | ```
626 |
627 |
628 |
629 | این کامنتها را با دقت بیشتری دوباره بخوانید. خطای cut-paste را مشاهده می کنید؟ اگر نویسندگان هنگام نوشتن کامنتها (یا چسباندن) توجه نمی کنند ، چرا از خوانندگان انتظار می رود که از آنها سود ببرند؟
630 |
631 | ## زمانی که میتوانید از یک تابع یا متغییر استفاده کنید از کامنتها استفاده نکنید
632 |
633 | بخش زیر کد را در نظر بگیرید:
634 |
635 |
636 |
637 | ```java
638 | // does the module from the global list depend on the
639 | // subsystem we are part of?
640 | if (smodule.getDependSubsystems().contains(subSysMod.getSubSystem()))
641 | ```
642 |
643 |
644 |
645 | بدون تفسیر می توان این را دوباره بیان کرد
646 |
647 |
648 |
649 | ```java
650 | ArrayList moduleDependees = smodule.getDependSubsystems();
651 | String ourSubSystem = subSysMod.getSubSystem();
652 | if (moduleDependees.contains(ourSubSystem))
653 | ```
654 |
655 |
656 |
657 | نویسنده کد اصلی ممکن است ابتدا کامنت را نوشته باشد (بعید است) و سپس کد را برای تحقق کامنت نوشته باشد. با این حال ، نویسنده باید همانند من کدها را مجدداً ویرایش میکرد تا بتواند کامنت را حذف کند.
658 |
659 | ## نشانگرهای موقعیت
660 |
661 | گاهی اوقات برنامه نویسان دوست دارند موقعیت خاصی را در یک فایل منبع علامت گذاری کنند. به عنوان مثال ، من اخیراً این را در برنامه ای یافتم که در جستجوی آن بودم:
662 |
663 |
664 |
665 | ```java
666 | // Actions //////////////////////////////////
667 | ```
668 |
669 |
670 |
671 | موارد نادری وجود دارد که جمع آوری برخی کارها در زیر یک بنر مانند این منطقی باشد. اما به طور کلی، بی نظمی هستند که باید از بین بروند - به ویژه قطار پر سر و صدا اسلش در انتها.
672 |
673 | اینجوری فکر کن اگر شما اغلب بنرها را مشاهده نکنید ، یک بنر حیرت انگیز و واضح است. بنابراین خیلی کم و فقط در صورت سودمند بودن از آنها استفاده کنید. اگر بیش از اندازه از بنرها استفاده نکنید ، در سر و صدای پس زمینه قرار می گیرند و نادیده گرفته می شوند.
674 |
675 | ## کامنتهای بستن آکولاد
676 |
677 | بعضی اوقات ، برنامه نویسان نظیر لیست 4-6 ، کامنتهای ویژه ای در مورد آکولادهای بسته مینهند. اگرچه این ممکن است برای توابع طولانی با ساختارهای کاملاً تو در تو منطقی باشد ، اما در انواع توابع کوچک و محصور شده فقط منجر به بهم ریختن میشود. بنابراین اگر متوجه شدید که می خواهید آکولادهای بسته خود را مشخص کنید ، سعی کنید در عوض توابع خود را کوتاه کنید.
678 |
679 |
680 |
681 | Listing 4-6
682 |
683 | wc.java
684 |
685 | ```java
686 | public class wc {
687 | public static void main(String[] args) {
688 | BufferedReader in = new BufferedReader(new InputStreamReader(System.in));
689 | String line;
690 | int lineCount = 0;
691 | int charCount = 0;
692 | int wordCount = 0;
693 | try {
694 | while ((line = in.readLine()) != null) {
695 | lineCount++;
696 | charCount += line.length();
697 | String words[] = line.split("\\W");
698 | wordCount += words.length;
699 | } //while
700 | System.out.println("wordCount = " + wordCount);
701 | System.out.println("lineCount = " + lineCount);
702 | System.out.println("charCount = " + charCount);
703 | } // try
704 | catch (IOException e) {
705 | System.err.println("Error:" + e.getMessage());
706 | } //catch
707 | } //main
708 | }
709 | ```
710 |
711 |
712 |
713 | ## خصیصهها و خطوط معرف نویسنده کد
714 |
715 |
716 |
717 |
718 | ```java
719 | /* Added by Rick */
720 | ```
721 |
722 |
723 |
724 | سیستم های کنترل کد منبع در به خاطر سپردن اینکه چه کسی چه چیزی را اضافه کرده است ، بسیار خوب است. نیازی به آلوده سازی کد با کمترین bylines نیست. ممکن است فکر کنید چنین کامنتهایی برای کمک به دیگران در دانستن اینکه با چه کسی در مورد کد صحبت می کنند مفید باشد. اما واقعیت این است که سالها و سالها در اطراف بمانند ، هرچه دقیق تر و کم اهمیت تر می شوند.
725 |
726 | باز هم ، سیستم کنترل کد منبع مکان بهتری برای این نوع اطلاعات است.
727 |
728 | ## کامنت کردن کد
729 |
730 | تعداد کمی از اعمال به اندازه کد توضیح دادن کراهت دارند. این کار را نکنید!
731 |
732 |
733 |
734 | ```java
735 | // InputStreamResponse response = new InputStreamResponse();
736 | // response.setBody(formatter.getResultStream(), formatter.getByteCount());
737 | // InputStream resultsStream = formatter.getResultStream();
738 | // StreamReader reader = new StreamReader(resultsStream);
739 | // response.setContent(reader.read(formatter.getByteCount()));
740 | ```
741 |
742 |
743 |
744 | دیگران که این کد کامنت شده را می بینند ، جرات حذف آن را ندارند. آنها فکر می کنند آنجا به دلایلی وجود دارد و حذف آنها بسیار خطرناک است. بنابراین کد کامنت شده مانند خاکه ته یک بطری بد شراب جمع می شود.
745 |
746 | این را از apache commons در نظر بگیرید:
747 |
748 |
749 |
750 | ```java
751 | this.bytePos = writeBytes(pngIdBytes, 0);
752 | //hdrPos = bytePos;
753 | writeHeader();
754 | writeResolution();
755 | //dataPos = bytePos;
756 | if (writeImageData()) {
757 | writeEnd();
758 | this.pngBytes = resizeByteArray(this.pngBytes, this.maxPos);
759 | }
760 | else {
761 | this.pngBytes = null;
762 | }
763 | return this.pngBytes;
764 | ```
765 |
766 |
767 |
768 | چرا آن دو خط کد کامنت داده شده است؟ آیا آنها مهم هستند؟ آیا آنها به عنوان یادآوری برای برخی تغییرات قریب الوقوع باقی مانده بودند؟ یا اینها فقط ظلم هایی هستند که کسی سالها پیش در مورد آنها کامنت داده و زحمت تمیز کردنش را نکشیده است.
769 |
770 | زمانی در دهه شصت بود که ممکن است کد کامنت شده مفید باشد. اما مدت زمان زیادی است که سیستم های کنترل کد منبع خوبی داریم. آن سیستم ها کد را برای ما به خاطر می آورند. دیگر لازم نیست درباره آن توضیح دهیم. فقط کد را حذف کنید. ما آن را از دست نخواهیم داد. قول میدهم.
771 |
772 | ## HTML کامنتهای
773 |
774 | همانطور که می توانید با خواندن کد زیر متوجه شوید HTML در کامنتهای کد منبع مکروه است. خواندن کامنتها در مکانی که خواندن آنها آسان است - ادیتور / IDE - را دشوار می کند. اگر قرار است کامنتها توسط برخی از ابزارها (مانند Javadoc) برای نمایش در یک صفحه وب استخراج شود ، تزیین کامنتها با HTML مناسب باید به عهده آن ابزار باشد و نه برنامه نویس.
775 |
776 |
777 |
778 | ```java
779 | /**
780 | * Task to run fit tests.
781 | * This task runs fitnesse tests and publishes the results.
782 | *
783 | *
784 | * Usage:
785 | * <taskdef name="execute-fitnesse-tests"
786 | *
787 | classname="fitnesse.ant.ExecuteFitnesseTestsTask"
788 | *
789 | classpathref="classpath" />
790 | * OR
791 | * <taskdef classpathref="classpath"
792 | *
793 | resource="tasks.properties" />
794 | *
795 | * <execute-fitnesse-tests
796 | *
797 | suitepage="FitNesse.SuiteAcceptanceTests"
798 | *
799 | fitnesseport="8082"
800 | *
801 | resultsdir="${results.dir}"
802 | *
803 | resultshtmlpage="fit-results.html"
804 | *
805 | classpathref="classpath" />
806 | *
807 | */
808 | ```
809 |
810 |
811 |
812 | ## اطلاعات غیرمحلی
813 |
814 | اگر لازم است یک کامنت بنویسید، پس مطمئن شوید که کامنت شما کد اطراف خودش را توضیح میدهد. در یک کامنت محلی نیازی نیست اطلاعات بین المللی به خواننده بدهید، همانقدر که آن قسمت از کد را توضیح دهید کفایت میکند. فرضا این کامنت در مثال جاوایی زیر را درنظر بگیرید. با اینکه به طور ترسناکی زائد به نظر میرسد، اما اطلاعات خوبی درباره پورت پیشفرض برنامه به استفاده کننده میدهد. تابع مطلقا کنترلی روی اینکه پیشفرضش چه باشد ندارد. این کامنت ، تابع را توضیح نمیدهد و در حقیقت چیزی که این کامنت توضیح میدهد در نقطه ای دورتر از این قسمت قرار دارد. مطمئنا هیچ تضمینی نیست که اگر پورت پیشفرض برنامه عوض شد، این کامنت هم تغییر کند.
815 |
816 |
817 |
818 | ```java
819 | /**
820 | * Port on which fitnesse would run. Defaults to 8082.
821 | *
822 | * @param fitnessePort
823 | */
824 | public void setFitnessePort(int fitnessePort)
825 | {
826 | this.fitnessePort = fitnessePort;
827 | }
828 | ```
829 |
830 |
831 |
832 | ## اطلاعات بیش از اندازه
833 |
834 | بحث های جذاب تاریخی و توصیف های بی ربطتان را در جایی غیر از کامنتهایتان قرار دهید. کامنت زیر را در یک ماژول پیدا کردیم که طراحی شده بود برای تست یک تابع که کارش انکد و دیکد کردن base64 است. به جز کد RFC، بقیه نوشته ها اضافی هستند و کسی که این کد را میخواند نیازی به داشتن این اطلاعات مسخره ندارد.
835 |
836 |
837 |
838 | ```java
839 | /*
840 | RFC 2045 - Multipurpose Internet Mail Extensions (MIME)
841 | Part One: Format of Internet Message Bodies
842 | section 6.8. Base64 Content-Transfer-Encoding
843 | The encoding process represents 24-bit groups of input bits as output
844 | strings of 4 encoded characters. Proceeding from left to right, a
845 | 24-bit input group is formed by concatenating 3 8-bit input groups.
846 | These 24 bits are then treated as 4 concatenated 6-bit groups, each
847 | of which is translated into a single digit in the base64 alphabet.
848 | When encoding a bit stream via the base64 encoding, the bit stream
849 | must be presumed to be ordered with the most-significant-bit first.
850 | That is, the first bit in the stream will be the high-order bit in
851 | the first 8-bit byte, and the eighth bit will be the low-order bit in
852 | the first 8-bit byte, and so on.
853 | */
854 | ```
855 |
856 |
857 |
858 | ## ارتباط نامشخص
859 |
860 | ارتباط بین کامنت و کدی که در حال توضیح آن است باید واضح باشد. اگر قصد کامنت نوشتن دارید به این نکته توجه کنید که خواننده کد باید بتواند با نگاه کردن به کد بفهمد که شما دقیقا دارید درباره کدام قسمت توضیح میدهید.
861 | مثلا این کامنت از apache commons بیرون کشیده شده:
862 |
863 |
864 |
865 | ```java
866 | /*
867 | * start with an array that is big enough to hold all the pixels
868 | * (plus filter bytes), and an extra 200 bytes for header info
869 | */
870 | this.pngBytes = new byte[((this.width + 1) * this.height * 3) + 200];
871 | ```
872 |
873 |
874 |
875 | اینجا filter byte چیست؟ آیا مربوط میشود به +1 یا به *3؟ یا اصلا به هر دو؟ آیا هر پیکسل یک بایت است؟ چرا 200؟ کامنت برای کدی استفاده میشود که خودش، خودش را توضیح نمیدهد، اینجا باید کامنت دیگری بنویسیم که این کامنت را توضیح دهد!
876 |
877 | ## عناوین تابع
878 |
879 | توابع کوچک نیاز به توضیحات زیادی ندارند. یک اسم که خوب اتخاب شود برای یک تابع کوچک بسیار مفید تر از یک کامنت طولانی است.
880 |
881 | ## اسناد java در کد غیرعمومی
882 |
883 | همانقدر که jovadoc ها برای api های عمومی مناسب هستند، برای کد هایی که عمومی نیستند غیر مفیدند. تولید کردن javadoc برای کلاس ها و تابع ها در یک سیستم آنقدر ها هم مفید نیست، و زیاد بودن javadoc ها هم چیزی جز حواس پرتی به ارمغان نمیاورد.
884 |
885 | ## مثال
886 |
887 | من ماژولی که در Listing 4-7 هست را نوشته ام برای اولین تجربه شما. قصد این ماژول، بودن مثالی برای کدنویسی بد و سبک کامنت نویسی است. سپس Kent Beck این کد را جلوی چندین دانشجوی مشتاق به شکل بسیار پسندیده تری ریفکتور کرده. بعدتر من از این مثال برای کتاب خودم یعنی Agile Software Development, Principles, Patterns, and Practices استفاده کردم.
888 | چیزی که درمورد این کد جالب است این است که ما در ابتدا آن را کاملا مستند فرض میکردیم، در حالی که الان آن را یک آشفتگی کوچک میدانیم. ببینید چند مشکل مختلف در کامنت گذاری این کد میتوانید پیدا کنید.
889 |
890 |
891 |
892 | Listing 4-7
893 |
894 | GeneratePrimes.java
895 | ```java
896 | /**
897 | * This class Generates prime numbers up to a user specified
898 | * maximum. The algorithm used is the Sieve of Eratosthenes.
899 | *
900 | * Eratosthenes of Cyrene, b. c. 276 BC, Cyrene, Libya --
901 | * d. c. 194, Alexandria. The first man to calculate the
902 | * circumference of the Earth. Also known for working on
903 | * calendars with leap years and ran the library at Alexandria.
904 | *
905 | * The algorithm is quite simple. Given an array of integers
906 | * starting at 2. Cross out all multiples of 2. Find the next
907 | * uncrossed integer, and cross out all of its multiples.
908 | * Repeat untilyou have passed the square root of the maximum
909 | * value.
910 | *
911 | * @author Alphonse
912 | * @version 13 Feb 2002 atp
913 | */
914 | import java.util.*;
915 | public class GeneratePrimes
916 | {
917 | /**
918 | * @param maxValue is the generation limit.
919 | */
920 | public static int[] generatePrimes(int maxValue)
921 | {
922 | if (maxValue >= 2) // the only valid case
923 | {
924 | // declarations
925 | int s = maxValue + 1; // size of array
926 | boolean[] f = new boolean[s];
927 | int i;
928 | // initialize array to true.
929 | for (i = 0; i < s; i++)
930 | f[i] = true;
931 | // get rid of known non-primes
932 | f[0] = f[1] = false;
933 | // sieve
934 | int j;
935 | for (i = 2; i < Math.sqrt(s) + 1; i++)
936 | {
937 | if (f[i]) // if i is uncrossed, cross its multiples.
938 | {
939 | for (j = 2 * i; j < s; j += i)
940 | f[j] = false; // multiple is not prime
941 | }
942 | }
943 | // how many primes are there?
944 | int count = 0;
945 | for (i = 0; i < s; i++)
946 | {
947 | if (f[i])
948 | count++; // bump count.
949 | }
950 | int[] primes = new int[count];
951 | // move the primes into the result
952 | for (i = 0, j = 0; i < s; i++)
953 | {
954 | if (f[i])
955 | // if prime
956 | primes[j++] = i;
957 | }
958 | return primes; // return the primes
959 | }
960 | else // maxValue < 2
961 | return new int[0]; // return null array if bad input.
962 | }
963 | }
964 | ```
965 |
966 |
967 |
968 | در Listing 4-8 میتوانید یک نسخه بازنویسی شده از همان ماژول قبلی را ببینید. دقت کنید که استفاده از کامنت به طور قابل توجهی مهار شده و فقط دو کامنت در این کد دیده میشود. هر دو کامنت ماهیت توضیح دادن دارند.
969 |
970 |
971 |
972 | Listing 4-8
973 |
974 | PrimeGenerator.java (refactored)
975 | ```java
976 | /**
977 | * This class Generates prime numbers up to a user specified
978 | * maximum. The algorithm used is the Sieve of Eratosthenes.
979 | * Given an array of integers starting at 2:
980 | * Find the first uncrossed integer, and cross out all its
981 | * multiples. Repeat until there are no more multiples
982 | * in the array.
983 | */
984 | public class PrimeGenerator
985 | {
986 | private static boolean[] crossedOut;
987 | private static int[] result;
988 | public static int[] generatePrimes(int maxValue)
989 | {
990 | if (maxValue < 2)
991 | return new int[0];
992 | else
993 | {
994 | uncrossIntegersUpTo(maxValue);
995 | crossOutMultiples();
996 | putUncrossedIntegersIntoResult();
997 | return result;
998 | }
999 | }
1000 | private static void uncrossIntegersUpTo(int maxValue)
1001 | {
1002 | crossedOut = new boolean[maxValue + 1];
1003 | for (int i = 2; i < crossedOut.length; i++)
1004 | crossedOut[i] = false;
1005 | }
1006 | private static void crossOutMultiples()
1007 | {
1008 | int limit = determineIterationLimit();
1009 | for (int i = 2; i <= limit; i++)
1010 | if (notCrossed(i))
1011 | crossOutMultiplesOf(i);
1012 | }
1013 | private static int determineIterationLimit()
1014 | {
1015 | // Every multiple in the array has a prime factor that
1016 | // is less than or equal to the root of the array size,
1017 | // so we don't have to cross out multiples of numbers
1018 | // larger than that root.
1019 | double iterationLimit = Math.sqrt(crossedOut.length);
1020 | return (int) iterationLimit;
1021 | }
1022 | private static void crossOutMultiplesOf(int i)
1023 | {
1024 | for (int multiple = 2*i;
1025 | multiple < crossedOut.length;
1026 | multiple += i)
1027 | crossedOut[multiple] = true;
1028 | }
1029 | private static boolean notCrossed(int i)
1030 | {
1031 | return crossedOut[i] == false;
1032 | }
1033 | private static void putUncrossedIntegersIntoResult()
1034 | {
1035 | result = new int[numberOfUncrossedIntegers()];
1036 | for (int j = 0, i = 2; i < crossedOut.length; i++)
1037 | if (notCrossed(i))
1038 | result[j++] = i;
1039 | }
1040 | private static int numberOfUncrossedIntegers()
1041 | {
1042 | int count = 0;
1043 | for (int i = 2; i < crossedOut.length; i++)
1044 | if (notCrossed(i))
1045 | count++;
1046 | return count;
1047 | }
1048 | }
1049 | ```
1050 |
1051 |
1052 |
1053 | فهمیدنش راحت است که کامنت اول بیخودی انجا نوشته شده، چرا که خود اسم generatePrimes را توضیح داده. این اسم به اندازه کافی کاربرد تابع را بیان میکند. من فکر میکنم کامنتها برای راحت تر کردن کار خواننده نوشته میشوند، پس ترجیح میدهم این کامنت اضافی را آنجا قرار ندهم.
1054 | بحث دوم قطعا ضروری است. این منطق پشت استفاده از ریشه دوم به عنوان حد حلقه را توضیح میدهد.البته استفاده از ریشه دوم عدد ممکن است فقط از نظر تئوری جالب به نظر برسد، آیا واقعا با محاسبه ریشه دوم و محدود کردن حلقه به آن، زمان بیشتری ذخیره میکنیم؟
1055 | ارزش فکر کردن را دارد. استفاده از ریشه دوم برای محدود کردن تکرار حلقه، هکر قدیمی c و اسمبلی نویس درونم را راضی میکند، ولی فکر نمیکنم ارزش وقت و تلاشی که بقیه برای فهمیدن آن صرف میکنند را داشته باشد.
1056 |
1057 |
1058 |
1059 | * [فصل بعد](../5_Formatting(completed)/5_Formatting.md)
1060 |
1061 | * [فصل قبل](../3_Functions(completed)/3_Functions.md)
--------------------------------------------------------------------------------