داشتن آگاهي در مورد ساختارهاي دادهها، الگوريتمها و يا عملگرهاي بيتي بسيار عالي است و يا تسلط بر نحوهي كاركرد ابزارهايي مانند SharePoint و امثال آن اين روزها ضروري است. اما بايد در نظر داشت، كدي كه امروز تهيه ميشود شايد فردا يا ماه ديگر يا چند سال بعد نياز به تغيير داشته باشد، بنابراين دانش زيبا نوشتن يك قطعه كد كه خواندن آنرا سادهتر ميكند و در آينده افرادي كه از آن نگهداري خواهند كرد زياد "زجر" نخواهند كشيد، نيز ضروري ميباشد. (اگر كامنتهاي سايت را خوانده باشيد يكي از دوستان پيغام گذاشته بود، اگر به من بگويند يك ميليون بگيريد و برنامه فعلي را توسعه دهيد يا رفع اشكال كنيد، حاضرم 10 هزارتومان بگيرم و آنرا از صفر بنويسم! متاسفانه اين يك واقعيت تلخ است كه ناشي از عدم خوانا بودن كدهاي نوشته شده ميباشد.)
در ادامه يك سري از اصول زيبا نويسي كدها را بررسي خواهيم كرد.
1- سعي كنيد ميزان تو در تو بودن كدهاي خود را محدود كنيد.
لطفا به مثال زير دقت نمائيد:
void SetA()
{
if(a == b)
{
foreach(C c in cs)
{
if(c == d)
{
a = c;
}
}
}
}
void SetA()
{
if(a != b)
return;
foreach(C c in cs)
a = GetValueOfA(c);
}
TypeOfA GetValueOfA(C c)
{
if(c == d)
return c;
return a;
}
افزونههاي CodeRush و refactor pro مجموعهي DevExpress از لحاظ مباحث refactoring در ويژوال استوديو حرف اول را ميزنند. فقط كافي است براي مثال قطعه كد if داخلي را انتخاب كنيد، بلافاصله سه نقطه زير آن ظاهر شده و با كليك بر روي آن امكان استخراج يك تابع از آنرا براي شما به سرعت فراهم خواهد كرد.
مثالي ديگر:
if (foo) {
if (bar) {
// do something
}
}
if (foo && bar) {
// do something
}
و يا يك مثال ديگر:
ميزان تو در تو بودن اين تابع جاوا اسكريپتي را ملاحظه نمائيد:
function findShape(flags, point, attribute, list) {
if(!findShapePoints(flags, point, attribute)) {
if(!doFindShapePoints(flags, point, attribute)) {
if(!findInShape(flags, point, attribute)) {
if(!findFromGuide(flags,point) {
if(list.count() > 0 && flags == 1) {
doSomething();
}
}
}
}
}
}
function findShape(flags, point, attribute, list) {
if(findShapePoints(flags, point, attribute)) {
return;
}
if(doFindShapePoints(flags, point, attribute)) {
return;
}
if(findInShape(flags, point, attribute)) {
return;
}
if(findFromGuide(flags,point) {
return;
}
if (!(list.count() > 0 && flags == 1)) {
return;
}
doSomething();
}
با وجود پيشرفتهاي زيادي كه در طراحي و پياده سازي IDE ها صورت گرفته و با بودن ابزارهاي تكميل سازي خودكار متن تايپ شده در آنها، اين روزها استفاده از نامهاي بلند براي توابع يا متغيرها مشكل ساز نيست و وقت زيادي را تلف نخواهد كرد. براي مثال به نظر شما اگر پس از يك سال به كدهاي زير نگاه كنيد كداميك خود توضيح دهندهتر خواهند بود (بدون مراجعه به مستندات موجود)؟
void UpdateBankAccountTransactionListWithYesterdaysTransactions()
//or?
void UpdateTransactions()
اگر مورد 2 را رعايت كرده باشيد، كمتر به نوشتن كامنت نياز خواهد بود. از توضيح موارد بديهي خودداري كنيد، زيرا آنها بيشتر سبب اتلاف وقت خواهند شد تا كمك به افراد ديگر يا حتي خود شما. همچنين هيچگاه قطعه كدي را كه به آن نياز نداريد به صورت كامنت شده به مخزن كد در يك سيستم كنترل نگارش ارسال نكنيد.
//function thisReallyHandyFunction() {
// someMagic();
// someMoreMagic();
// magicNumber = evenMoreMagic();
// return magicNumber;
//}
به صورت خلاصه جهت نگهداري سوابق كدهاي قديمي بايد از سورس كنترل استفاده كرد و نه به صورت كامنت قرار دادن آنها.
از كامنتهاي نوع زير پرهيز كنيد كه بيشتر سبب رژه رفتن روي اعصاب خواننده ميشود تا كمك به او! (خواننده را بيسواد فرض نكنيد)
// Get the student's id
thisId = student.getId();
// TODO: This is too bad. FIX IT!
4- عدم استفاده از عبارات شرطي بيمورد هنگام بازگشت دادن يك مقدار bool:
مثال زير را درنظر بگيريد:
if (foo>bar) {
return true;
} else {
return false;
}
return foo>bar;
براي مثال:
Something something = new Something(foo);
return something;
return new Something(foo);
6- در نگارشهاي جديد دات نت فريم ورك استفاده از ArrayList منسوخ شده است. بجاي آن بهتر است از ليستهاي جنريك استفاده شود. كدي كه در آن از ArrayList استفاده ميشود طعم دات نت فريم ورك 1 را ميدهد!
7- لطفا بين خطوط فاصله ايجاد كنيد. ايجاد فواصل مجاني است!
دو تابع جاوا اسكريپتي زير را (كه در حقيقت يك تابع هستند) در نظر بگيريد:
function getSomeAngle() {
// Some code here then
radAngle1 = Math.atan(slope(center, point1));
radAngle2 = Math.atan(slope(center, point2));
firstAngle = getStartAngle(radAngle1, point1, center);
secondAngle = getStartAngle(radAngle2, point2, center);
radAngle1 = degreesToRadians(firstAngle);
radAngle2 = degreesToRadians(secondAngle);
baseRadius = distance(point, center);
radius = baseRadius + (lines * y);
p1["x"] = roundValue(radius * Math.cos(radAngle1) + center["x"]);
p1["y"] = roundValue(radius * Math.sin(radAngle1) + center["y"]);
pt2["x"] = roundValue(radius * Math.cos(radAngle2) + center["y"]);
pt2["y"] = roundValue(radius * Math.sin(radAngle2) + center["y");
// Now some more code
}
function getSomeAngle() {
// Some code here then
radAngle1 = Math.atan(slope(center, point1));
radAngle2 = Math.atan(slope(center, point2));
firstAngle = getStartAngle(radAngle1, point1, center);
secondAngle = getStartAngle(radAngle2, point2, center);
radAngle1 = degreesToRadians(firstAngle);
radAngle2 = degreesToRadians(secondAngle);
baseRadius = distance(point, center);
radius = baseRadius + (lines * y);
p1["x"] = roundValue(radius * Math.cos(radAngle1) + center["x"]);
p1["y"] = roundValue(radius * Math.sin(radAngle1) + center["y"]);
pt2["x"] = roundValue(radius * Math.cos(radAngle2) + center["y"]);
pt2["y"] = roundValue(radius * Math.sin(radAngle2) + center["y");
// Now some more code
}
استفاده از فاصله بين خطوط در تابع دوم باعث بالا رفتن خوانايي آن شده است و اين طور به نظر ميرسد كه سطرهايي با عملكرد مشابه در يك گروه كنار هم قرار گرفتهاند.
8- توابع خود را كوتاه كنيد.
يك تابع نبايد بيشتر از 50 سطر باشد (البته در اين مورد بين علما اختلاف هست!). اگر بيشتر شد بدون شك نياز به refactoring داشته و بايد به چند قسمت تقسيم شود تا خوانايي كد افزايش يابد.
به صورت خلاصه يك تابع فقط بايد يك كار را انجام دهد و بايد بتوان عملكرد آنرا در طي يك جمله توضيح داد.
9- از اعداد جادويي در كدهاي خود استفاده نكنيد!
كد زير هيچ معنايي ندارد!
if(mode == 3){ ... }
else if(mode == 4) { ... }
if(mode == MyEnum.ShowAllUsers) { ... }
else if(mode == MyEnum.ShowOnlyActiveUsers) { ... }
اگر نياز به تعداد زيادي پارامتر ورودي وجود داشت (بيش از 6 مورد) از struct و يا كلاس جهت معرفي آنها استفاده كنيد.