سلام.
شاید یکم عنوان تاپیک یه جوری باشه. پس بهتره اول توضیح بدیم که منظورمون از کد تمیز و قابل توسعه چیه :smile:
کد تمیز در مقابل کد کثیف قرار میگیره :redface: برای نمونه به این کد دقت کنید :
این یه کد نسبتا کثیفه ! نسبتا چون راستش تو این چند خط زیاد تمیز و کثیف بودن کد مشخص نیست. بری این که بهتر متوجه بشید کد زیر رو نگاه کنید که یک همون کد بالا ولی نسخه تمیزش هست :
همونطور که میبینید به این کد خیلی خوانا تر از کد قبلیه. به عنوان مثال از روی اسم تابع به راحتی میشه تشخیص داد چه کاری انجام میده و یا اینکه در ورودی ها چه چیزی باید نمایش داده بشه.
خرورجی دو برنامه یکیه ولی تفاوتش وقتی مشخص میشه که شما قرار باشه یه برنامه نسبتا طولانی و یکم بزرگ تر از یک برنامه کوچیک مثل این بنویسید :read:
یا مثلا قرار باشه برنامتون یه لایبری باشه و کس دیگه ای بخواد ازش استفاده کنه. یا یک فاجعه بزرگ تر این که روزی نیاز داشته باشید برنامتون رو گسترش بدید یا چیزی رو از توی اون پیدا کنید.
مورد آخر معمولا شایع تر هست. و کد میتونه کثیف منجر به این میشه که برنامه نویس مجبور شه از اول همون برنامه رو با تغیراتی که میخاد بنویسیه. و اینکار تقریبا توی پروژه های بزرگ غیر ممکنه. چون یک پروژه بزرگ ( یک نرم افزار خاص رو مثلا در نظر بگیرید مثلا فوتوشاپ) خیلی چیزا در نسخه های مختلف ثابت هست ولی به مرور زمان به اون نرم افزار چیزای جدید اضافه میشه یا برخی از مشکلاتش رفع میشه. حالا اگه کد کثیف باشه نه میشه به راحتی گسترشش داد و نه به این راحتیا میشه عیبش رو پیدا و برطرف کرد.
و اگه کد کثیف بنویسید دیگه تقریبا باید بیخیال این بشید که یکی بیاد کدتون رو گسترش بده ....
خوب همه اینا رو گفتیم که بدونیم چرا باید سعی کنیم کدمون تمیز باشه ( راستی کد تمیز و کد کثیف که میگم لغت انگلیسیش اصطلاحه توی برنامه نویسی)
کد تمیز نوشتن کهر زیاد سختی نیست فقط کافیه یه سری نکات رو رعایت کنیم :read:
بنابر این میریم سر اصل مطلب. اینکه چجوری باید یک کد تمیز بنویسیم :smile:
✔ 1. استفاده از نام های معنی دار
یکی از چیزایی که واقعا کمک میکنه یک کد تمیز باشه اینه که برای متغیر ها , توابع , کلاس ها .... از نام های معنی دار استفاده کنید. بهتره تا میشه از کلمه کامل استفاده کنید. مگر اینکه کلمه خلاصش خیلی معروف باشه.
مثلا در مثال بالا به جای اینکه PlusOfTwoNumber رو اینجوری خلاصه کنیم و بنویسیم ptn بنویسیم همون PlusOfTwoNumber تا کد تمیز تر بشه. البته مثلا PlusOfTwoNumber رو میشه به این شکل هم نوشت که شاید بهتر هم باشه PlusTwoNum چون Num نسبتا چیز معروفی به نظر میاد Of هم زیاد مهم نیست. اصلا بهتره زیاد به گرامر دقت نکنید. همینکه منظورو واضح برسونه کافیه.
✔ 2. شتری بنویسید !!
نه این توهین نیست :redface: اگه تو گوگل سرچ کنید Camel Syntax یا Camel Case توی اولین نتیجه صفحهویکی پدیا رو میاره که یه توضیح کامل راجبه تاریخچه و .... توش هست. دقیق نمیدونم اولین بار از کجا مرسوم شد ولی فکر میکنم با اومدن زبان های سطح بالا و ویرایش گر های جدید این اتفاق افتاد.
ولی حالا چرا بش همچین اسمی دادند ؟
دلیلش به خاطر اینه که مثل این جور نوشتن کوهان های شتر فراز و نشیب داره. برای مثال بجای اینکه عبارت plus of two number رو به این اشکال برای اسم تابع استفاده کنیم :
plusoftwonumber
plus_of_two_number
...
به این شکل استفاده میکنیم : PlusOfTwoNumber
در واقع کلمات رو با حروف کوچیک و بزرگ از هم جدا میکنیم .
اگه جاوا کار کرده باشید یا C# احتمالا از این چیزا زیاد دیدید ( مثلا ()Console.WriteLine )
من شخصا با اینکه حتی توابع و متغیر هارو جدا میکنم. به این شکل که کلمه اول توابع و کلاس با حروف بزرگ شروع میشه ولی کلمه اول متغیر ها و شی ها با حروف کوچیک
✔ 3. حتما درخت کاری کنید !
اگه از زبان های سطح بالا مثل C# , یا java یا ... استفاده میکنید احتمالا دیگه به این بخش نیازی ندارید چون عموما ویرایش گر های این زبان ها خودشون زیاد اجازه آزادی عمل برای درخت نکاشتن نمیدن ! البته مگه اینکه سراغ تنظیماتشون رفته باشید. ولی اگه از زبان های مثل C++ استفاده میکنید حتما درختی نوشتن رو رعایت کنید. چون مطمعن باشید قطعا در جاهایی که از if ها یا ... تو در تو استفاده کرده باشید به مشکل میخورید. خیلی وقتا کامپایلر ها دقیق نمیگند کجا یک کروشه یا پرانتز کم گزاشتید و اصلا ممکنه خودشون هم قاطی کنند و ارور های مثل ( To Many Error ) یا ... بدند که دیگه پیدا کردن مشکل خیلی سخت میشه.
برای مثال یه قسمت از کد بازی 2048 هست که کد کاملش رو از اینجا میتونید ببینید. کافیه یکی از کروشه ه ارو کم و زیاد کنید تا ارور هایی که میده رو ببینید :smile:
یه نکته هم شاید بد نباشیه اینجا اشاره کنیم اینه خوب خیلی ها کاربرد Tab رو میدونند ولی کاربرد Shift + Tab رو نه :smile:
(راستی نمیدونم درختی نوشتن رو از خودم در اوردم یا همچین چیزی هست. فکر کنم باشه)
نمونه غیر درختی :
نمونه درختی :
✔ 4. هر شی نشان دهنده کلاسی باشد که از آن ساخته شده
فرض کنید کلاسی به نام Box داشته باشیم و قرار باشه 3 تا شی دیگه ازش تعریف کنیم. مثلا یه جعبه چوبی , سنگی , کاغذی
بهتره سه جعبه رو به این شکل تعریف کنیم تا بعدا هرجا دیدیمشون بدونیم از چه کلاسی هستند :
✔ 5. ثابت و تعریف تعریف کنید !
حتما سعی کنید جاهایی که از چیزی مثل عدد ثابت استفاده میکنید حتما از define یا اعداد ثابت استفاده کنید.
شخصا اگه از یه عدد ثابت بخام استاده کنم بیشتر از define استفاده میکنم (البته اگر جاوا نباشه) چون اینطوری دیگه در هنگام اجرا رم هم اشغال نمیشه (البته زیاد فرقی نداره چون معمولا یه داده ثابت چیز زیادی از رم اشغال نمیکنه) . این پیشنهاد بیشتر شخصی بود یعنی مثلا اگه قراره تو برنامه مدام از یه عدد ثابت مثلا 4 استفاده کنید بهتره یک define برای اون تعریف کنید. ولی یه پیشنهاد وِیژه هم دارم که شاید تو پروژه هایی مثل پردازش تصویر و ... که سرعت مهم باشه خیلی تاثیر داره. اون اینکه اگه عدد ثابتتون حاصل از یک محاسبه باشه حتما محاسبه رو در یک متغیر ثابت انجام بدید.
فکر کنم یکم پیچیده شد.
ببنید اگه قرار بود از یه عدد ثابت مثلا طول پنجره استفاده کنید میتونید به این شکل اونو تعریف کنید :
ولی اگه قرار بود نسبت طول به عرض صفحه رو بدست بیارید اونو به این شکل تعریف کنید تا اگه قرار بود پشت سر هم روش استفاده بشه فقط یک بار حاصل تقسیم محاسبه بشه و از CPU زمان نگیره :
برای مثال کلا میتونید به این شکل تعریف کنید که خیلی بهتره و به راحتی قابل تغیره :
✔ 6. نوشتن متغیر با تعریف ها فرق دارد
برای اینکه مشخص باشه یه چیز یک define هست یا نه میتونید همه define هارو با حروف بزرگ بنویسید و بین کلمات با _ فاصله ایجاد کنید
مثلا میتونیم یه define که یک اسم کتاب هست رو اینجوری تعریف کنیم :
✔ 7. کلا بین همه چیز فرق بگزارید
هرچی بیشتر بین اجزای مختلف کد تفاوت باشه کد جالب تر میشه (البته به شرطی که از حد نگزره )
مثلا متغیر های private کلاس رو اولش _ بزارید (البته من خودم اینکارو معمولا نمیکنم) :
✔ n. شرطی نشید !
تمام موارد بالا کاملا سلیغه اینه. شاید بیشترش هم نظر شخصی باشه. بنابر این لازم نیست همیشه این شکلی باشه. میتونید الگو های متفاوتی رو برای خودتون در نظر بگیرید فقط باید نهایتا خوانا باشه
-----------------------------------------------------------------------
اگه خوشتون اومد صلواتی برای تعجیل در فرج آقا صاحب الزمان بفرستید :smile:
ان شاءالله این پست به روز میشود.
شاید یکم عنوان تاپیک یه جوری باشه. پس بهتره اول توضیح بدیم که منظورمون از کد تمیز و قابل توسعه چیه :smile:
کد تمیز در مقابل کد کثیف قرار میگیره :redface: برای نمونه به این کد دقت کنید :
کد:
#include <iostream> using namespace std; int plt(int a, int b) { int w; w = a+b; return w; } int main(int a, char** b) { cout<<"10 + 30 : "<< plt(10,30)<<"\n"; system("pause"); }
کد:
#include <iostream> using namespace std; int PlusOfTwoNumber(int firstValue, int secondValue); int main(int a, char** b) { cout<<"10 + 30 : "<< PlusOfTwoNumber(10,30)<<"\n"; system("pause"); } int PlusOfTwoNumber(int firstValue, int secondValue) { int result; result = firstValue+secondValue; return result; }
خرورجی دو برنامه یکیه ولی تفاوتش وقتی مشخص میشه که شما قرار باشه یه برنامه نسبتا طولانی و یکم بزرگ تر از یک برنامه کوچیک مثل این بنویسید :read:
یا مثلا قرار باشه برنامتون یه لایبری باشه و کس دیگه ای بخواد ازش استفاده کنه. یا یک فاجعه بزرگ تر این که روزی نیاز داشته باشید برنامتون رو گسترش بدید یا چیزی رو از توی اون پیدا کنید.
مورد آخر معمولا شایع تر هست. و کد میتونه کثیف منجر به این میشه که برنامه نویس مجبور شه از اول همون برنامه رو با تغیراتی که میخاد بنویسیه. و اینکار تقریبا توی پروژه های بزرگ غیر ممکنه. چون یک پروژه بزرگ ( یک نرم افزار خاص رو مثلا در نظر بگیرید مثلا فوتوشاپ) خیلی چیزا در نسخه های مختلف ثابت هست ولی به مرور زمان به اون نرم افزار چیزای جدید اضافه میشه یا برخی از مشکلاتش رفع میشه. حالا اگه کد کثیف باشه نه میشه به راحتی گسترشش داد و نه به این راحتیا میشه عیبش رو پیدا و برطرف کرد.
و اگه کد کثیف بنویسید دیگه تقریبا باید بیخیال این بشید که یکی بیاد کدتون رو گسترش بده ....
خوب همه اینا رو گفتیم که بدونیم چرا باید سعی کنیم کدمون تمیز باشه ( راستی کد تمیز و کد کثیف که میگم لغت انگلیسیش اصطلاحه توی برنامه نویسی)
کد تمیز نوشتن کهر زیاد سختی نیست فقط کافیه یه سری نکات رو رعایت کنیم :read:
بنابر این میریم سر اصل مطلب. اینکه چجوری باید یک کد تمیز بنویسیم :smile:
✔ 1. استفاده از نام های معنی دار
یکی از چیزایی که واقعا کمک میکنه یک کد تمیز باشه اینه که برای متغیر ها , توابع , کلاس ها .... از نام های معنی دار استفاده کنید. بهتره تا میشه از کلمه کامل استفاده کنید. مگر اینکه کلمه خلاصش خیلی معروف باشه.
مثلا در مثال بالا به جای اینکه PlusOfTwoNumber رو اینجوری خلاصه کنیم و بنویسیم ptn بنویسیم همون PlusOfTwoNumber تا کد تمیز تر بشه. البته مثلا PlusOfTwoNumber رو میشه به این شکل هم نوشت که شاید بهتر هم باشه PlusTwoNum چون Num نسبتا چیز معروفی به نظر میاد Of هم زیاد مهم نیست. اصلا بهتره زیاد به گرامر دقت نکنید. همینکه منظورو واضح برسونه کافیه.
✔ 2. شتری بنویسید !!
نه این توهین نیست :redface: اگه تو گوگل سرچ کنید Camel Syntax یا Camel Case توی اولین نتیجه صفحهویکی پدیا رو میاره که یه توضیح کامل راجبه تاریخچه و .... توش هست. دقیق نمیدونم اولین بار از کجا مرسوم شد ولی فکر میکنم با اومدن زبان های سطح بالا و ویرایش گر های جدید این اتفاق افتاد.
ولی حالا چرا بش همچین اسمی دادند ؟
دلیلش به خاطر اینه که مثل این جور نوشتن کوهان های شتر فراز و نشیب داره. برای مثال بجای اینکه عبارت plus of two number رو به این اشکال برای اسم تابع استفاده کنیم :
plusoftwonumber
plus_of_two_number
...
به این شکل استفاده میکنیم : PlusOfTwoNumber
در واقع کلمات رو با حروف کوچیک و بزرگ از هم جدا میکنیم .
اگه جاوا کار کرده باشید یا C# احتمالا از این چیزا زیاد دیدید ( مثلا ()Console.WriteLine )
من شخصا با اینکه حتی توابع و متغیر هارو جدا میکنم. به این شکل که کلمه اول توابع و کلاس با حروف بزرگ شروع میشه ولی کلمه اول متغیر ها و شی ها با حروف کوچیک
✔ 3. حتما درخت کاری کنید !
اگه از زبان های سطح بالا مثل C# , یا java یا ... استفاده میکنید احتمالا دیگه به این بخش نیازی ندارید چون عموما ویرایش گر های این زبان ها خودشون زیاد اجازه آزادی عمل برای درخت نکاشتن نمیدن ! البته مگه اینکه سراغ تنظیماتشون رفته باشید. ولی اگه از زبان های مثل C++ استفاده میکنید حتما درختی نوشتن رو رعایت کنید. چون مطمعن باشید قطعا در جاهایی که از if ها یا ... تو در تو استفاده کرده باشید به مشکل میخورید. خیلی وقتا کامپایلر ها دقیق نمیگند کجا یک کروشه یا پرانتز کم گزاشتید و اصلا ممکنه خودشون هم قاطی کنند و ارور های مثل ( To Many Error ) یا ... بدند که دیگه پیدا کردن مشکل خیلی سخت میشه.
برای مثال یه قسمت از کد بازی 2048 هست که کد کاملش رو از اینجا میتونید ببینید. کافیه یکی از کروشه ه ارو کم و زیاد کنید تا ارور هایی که میده رو ببینید :smile:
یه نکته هم شاید بد نباشیه اینجا اشاره کنیم اینه خوب خیلی ها کاربرد Tab رو میدونند ولی کاربرد Shift + Tab رو نه :smile:
(راستی نمیدونم درختی نوشتن رو از خودم در اوردم یا همچین چیزی هست. فکر کنم باشه)
نمونه غیر درختی :
کد:
for(int i=0; i<4; i++) { for(int j=0; j<4; j++) { for(int _j=0; _j<j; _j++) { for(int __j=0; __j<j; __j++) { if(__j<3) { if(tiles[i][__j] == EMPTY_TILE) { tiles[i][__j] = tiles[i][__j+1]; tiles[i][__j+1] = EMPTY_TILE; moved=true; } else if((tiles[i][__j] == tiles[i][__j+1]) && !mergedTiles[__j+1]) { tiles[i][__j] *= 2; tiles[i][__j+1] = EMPTY_TILE; mergedTiles[__j] = true; moved=true; } } } } } }
کد:
for(int i=0; i<4; i++) { for(int j=0; j<4; j++) { for(int _j=0; _j<j; _j++) { for(int __j=0; __j<j; __j++) { if(__j<3) { if(tiles[i][__j] == EMPTY_TILE) { tiles[i][__j] = tiles[i][__j+1]; tiles[i][__j+1] = EMPTY_TILE; moved=true; } else if((tiles[i][__j] == tiles[i][__j+1]) && !mergedTiles[__j+1]) { tiles[i][__j] *= 2; tiles[i][__j+1] = EMPTY_TILE; mergedTiles[__j] = true; moved=true; } } } } } }
✔ 4. هر شی نشان دهنده کلاسی باشد که از آن ساخته شده
فرض کنید کلاسی به نام Box داشته باشیم و قرار باشه 3 تا شی دیگه ازش تعریف کنیم. مثلا یه جعبه چوبی , سنگی , کاغذی
بهتره سه جعبه رو به این شکل تعریف کنیم تا بعدا هرجا دیدیمشون بدونیم از چه کلاسی هستند :
کد:
Box woodBox; Box stoneBox; Box paperBox;
حتما سعی کنید جاهایی که از چیزی مثل عدد ثابت استفاده میکنید حتما از define یا اعداد ثابت استفاده کنید.
شخصا اگه از یه عدد ثابت بخام استاده کنم بیشتر از define استفاده میکنم (البته اگر جاوا نباشه) چون اینطوری دیگه در هنگام اجرا رم هم اشغال نمیشه (البته زیاد فرقی نداره چون معمولا یه داده ثابت چیز زیادی از رم اشغال نمیکنه) . این پیشنهاد بیشتر شخصی بود یعنی مثلا اگه قراره تو برنامه مدام از یه عدد ثابت مثلا 4 استفاده کنید بهتره یک define برای اون تعریف کنید. ولی یه پیشنهاد وِیژه هم دارم که شاید تو پروژه هایی مثل پردازش تصویر و ... که سرعت مهم باشه خیلی تاثیر داره. اون اینکه اگه عدد ثابتتون حاصل از یک محاسبه باشه حتما محاسبه رو در یک متغیر ثابت انجام بدید.
فکر کنم یکم پیچیده شد.
ببنید اگه قرار بود از یه عدد ثابت مثلا طول پنجره استفاده کنید میتونید به این شکل اونو تعریف کنید :
کد:
#define WINDOW_W 640
کد:
const float aspectRatio = 640/480;
کد:
#define WINDOW_W 640 #define WINDOW_H 480 const float aspectRatio = WINDOW_W/WINDOW_H;
برای اینکه مشخص باشه یه چیز یک define هست یا نه میتونید همه define هارو با حروف بزرگ بنویسید و بین کلمات با _ فاصله ایجاد کنید
مثلا میتونیم یه define که یک اسم کتاب هست رو اینجوری تعریف کنیم :
کد:
#define ABAS_DAST_TALA_BOOK "Abas Dast Tala"
هرچی بیشتر بین اجزای مختلف کد تفاوت باشه کد جالب تر میشه (البته به شرطی که از حد نگزره )
مثلا متغیر های private کلاس رو اولش _ بزارید (البته من خودم اینکارو معمولا نمیکنم) :
کد:
private: int _clickCounter;
تمام موارد بالا کاملا سلیغه اینه. شاید بیشترش هم نظر شخصی باشه. بنابر این لازم نیست همیشه این شکلی باشه. میتونید الگو های متفاوتی رو برای خودتون در نظر بگیرید فقط باید نهایتا خوانا باشه
-----------------------------------------------------------------------
اگه خوشتون اومد صلواتی برای تعجیل در فرج آقا صاحب الزمان بفرستید :smile:
ان شاءالله این پست به روز میشود.
دیدگاه