چگونه زیبا کدنویسی کنیم؟

یکی از مشکلات اساسی برنامه نویسان مخصوصاً در کارهای گروهی ناتوانی در نوشتن کدهای زیبا و اصولی است. حال اولین سؤالی که با مواجهه با چنین مسئله ای پیش می آید این است که اساساً به چه نوع کدی زیبا گفته می شود؟ در جواب به این سؤال بایستی گفت کد زیبا به کدی گفته می شود که تمیز، خوانا، مرتب و اصولی نوشته ‌شده باشد و به ‌گونه‌ ای باشد که خواننده‌ کد بتواند آن را بدون نیاز به‌ دقت زیاد و یا سردرگمی درک کند. در این مقاله قصد داریم تا شما را با 7 روش برای نوشتن کدی زیبا آشنا کنیم.

۱. خروج سریع از شرط‌ ها برای مثال کد جاوا اسکریپت زیر را مد نظر قرار دهید (این ‌یک فاجعه‌ وحشتناک در کدنویسی است):


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();
}

همانطور که مشاهده کردید چنانچه از به وجود آمدن شرط‌ های تو در تو جلوگیری شود، می‌توانیم صاحب کدی زیباتر و قابل‌ درک‌ تر باشیم.

۲. برای توابع بولین که یک شرط ساده دارند بهتر است به جای استفاده از (if-else) خود شرط را return کنید. برای روشن شدن این مسئله مجدد مثالی می زنیم:


function isStringEmpty(str)
{
    if(str === "") { 
        return true;
    }
    else {
        return false;
    }
}

و حال اگر کد بالا را کمی اصلاح کنیم، نتیجه‌ حاصل کد زیر خواهد بود:


function isStringEmpty(str)
{
    return (str === "");
}

می بینیم که کدی بسیار ساده‌ تر، زیباتر و همچنین کم ‌حجم‌ تر داریم.

۳. لطفاً از اینتر استفاده کنید شاید باور نکنید اما افرادی وجود دارند (ممکن است خود شما جزو این گروه باشید) که به ‌طورکلی از اینتر استفاده نمی‌کنند مگر در آخر هر خط، و این در حالی است که استفاده‌ به جا و به ‌موقع از اینتر در کدنویسی باعث می‌شود که بخش‌ های مختلف کد از هم مجزا شوند و کد در آینده راحت‌ تر قابل‌ تحلیل و بررسی باشد. باز هم یک مثال دیگر:


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
}

۴. کامنت بدون استفاده ممنوع این بخش کمی چالشی‌تر است چرا که اکثر افراد در استفاده از کامنت به افراط و تفریط گراییده اند. هرچند استفاده از کامنت بسیار مفید است و بسیار در درک کد کمک می‌کند اما در برخی موارد هم واقعاً استفاده از آن‌ها زائد بوده و هیچ فایده‌ ای ندارد و تنها کد را شلوغ می‌کند. برای مثال در کد زیر همه‌ ما با اولین نگاه می‌فهمیم که در این کد id دانش آموز را دریافت خواهیم کرد:


function existsStudent(id, list) 
{
    for(i = 0; i < list.length; i++) {
       student = list[i];
       // Get the student's id
       thisId = student.getId();
       if(thisId === id) {
           return true;
       }
    }
    return false;   
}

بنابراین نیازی به کامنت گذاری برای این بخش از کد نخواهیم داشت.

۵. کدهای کامنت شده را در وسط سورس کد نهایی رها نکنید و حتما آن‌ها را پاک‌ کنید. برخی مواقع برای همه‌ ما پیش می آید که متوجه می‌شویم بخشی از کدها به ‌درستی کار نکرده و یا نیازی به آن‌ها نیست و از آن‌ها استفاده نمی‌شود لذا در اکثر مواقع به خصوص در مرحله‌ خطا گیری، کدهای زائد را کامنت کرده تا تغییرات حاصل را راحت تر بتوانید بررسی نمایید. اما باید توجه داشت که حتماً پس از اتمام کار کدهای اضافه و کامنت شده را حتماً از سورس کد پاک‌ کنید تا سورس کدی تمیزتر داشته باشیم:


//function thisReallyHandyFunction() 
//{
//      someMagic();
//      someMoreMagic();
//      magicNumber = evenMoreMagic();
//      return magicNumber;
//}

۶. هیچ‌ چیز بدتر از کدهای چند خطی (طولانی‌تر از یک خط که نیاز به اسکرول کردن دارند) نیست. همیشه سعی کنید تا کدهایی که استفاده می‌کنید و به بیشتر از یک خط فضا نیاز دارند را با استفاده از اینتر در یک خط جای دهید. برای مثال تا به ‌حال حتماً پیش‌آمده که کدی مثل کد زیر در اینترنت دیده اید و با خود گفته اید ".... ا ه ه ه ه":


public static EnumMap<Category, IntPair> getGroupCategoryDistribution(EnumMap<Category, Integer> sizes, int groups) {
        EnumMap<Category, IntPair> categoryGroupCounts = new EnumMap<Category,IntPair>(Category.class);
        for(Category cat : Category.values()) {
            categoryGroupCounts.put(cat, getCategoryDistribution(sizes.get(cat), groups));
        }

توصیه نمی‌کنیم که از استاندارد 70 کارکتری ترمینال‌ های یونیکس استفاده کنید اما حداقل می‌توانید محدودیتی 120 کاراکتری برای خودتان بگذارید تا کدی زیباتر داشته باشید.

۷. حذف توابع و متدهای طولانی؟ چند سال پیش برخی از افراد معتقد بودن که ویژوال سی ++ یک ‌زبان افتضاح است چون به شما توانایی ساخت متد و تابع با بیش از 10 هزار خط را نمی‌دهد! با این تفاسیر چه کسی می تواند به توضیح این مسئله بپردازد که برای چه ما به 10 هزار خط تابع نیاز داریم؟ حتی بزرگ‌ ترین توابع هم قابل گنجاندن در استانداردهای 50 خطی می باشند. به طور حتم 50 خط هم طولانی است اما حدی استاندارد و قابل ‌قبول است اما حد معمول یک تابع 30 تا 35 خط است و حد مناسب آن 10 تا 15 خط است.

توصیه می کنیم توابع طولانی را به چند تابع با اندازه استاندارد (برای مثال 50 تا 60 خطی) تقسیم کنید چرا که با این روش نه تنها توابع قابلیت دسته‌ بندی دارند بلکه خطایابی آن‌ ها نیز آسان‌ تر خواهد شد. امیدواریم این مقاله برای افرادی که همیشه با کدهای خودشان مشکل‌دارند مفید بوده باشد.

0







از طریق این فرم، می توانید بدون ثبت نام نظر دهید و یا اگر قبلا ثبت نام کرده اید، با ورود ناحیه ی کاربری می توانید علاوه بر ثبت نظر، به مدیریت نظرات خود نیز بپردازید.
(فیلد اجباری)
(فیلد اجباری)
(فیلد اجباری)
(فیلد اجباری)