۹ عادت بد برنامهنویسی که ما دوست داریم
همهی ما گاهی قوانین برنامهنویسی خوب را زیرپا گذاشتیم، کد هایی نوشتیم که کاملا بد تلقی میشوند اما اتفاق بدی نیفتاد و ما هنوز زندهایم. کامپیوترهایمان منهدم نشده است. در واقع خیلی هم به خوبی کامپایل شده و مشتریها هم به اندازه کافی راضی به نظر میرسند.
در واقع برنامهنویسی بد مثل کشیدن دم شیر نیست! اغلب مواقع کار میکند. قوانین در حقیقت راهنما هستند نه قوانین سفت و سختی که حتما لازم است اطاعت شوند. در واقع خیلی غلط هم نیست که بگوییم گاهی بهتر است حتی قوانین را زیرپا گذاریم. کدها گاها تمیزتر و سادهتر و سریعتر خواهند شد. قوانین معمولا خیلی کلی هستند و یک برنامهنویس هنرمند میتواند با شکستن آنها کد خود را بهبود بخشد. بعضی اوقات خوب است به سبک و نظر خودتان برنامهنویسی کنید. در ادامه ۹ قانونی که خیلی از ما با رضایت و موفقیت زیر پا میگذاریم را معرفی میکنیم.
۱- استفاده از goto
ممنوعیت استفاده از goto به زمانی برمیگردد که خیلی از ابزارهای برنامهنویسی ساختیافته وجود نداشتند. اگر برنامهنویسی میخواست حلقهای ایجاد کند یا به متد دیگری بپرد لازم بود از goto به همراه شماره خط استفاده کند. بعد از چند سال، تیمهای کامپایلر به برنامهنویسان اجازه دادند از برچسب رشتهای به جای شماره خطوط استفاده کنند که خود یک ویژگی جذاب به شمار میرفت.
بعضی کد دارای goto را کد اسپاگتی مینامیدند که هیچکسی نمیتوانست بعدا کد را بخواند و مسیر اجرای آن را درک کند. به همین دلیل ادگار دایکسترا استفاده از این دستور را به طور کلی ممنوع اعلام کرد.
ایجاد انشعابات پیدرپی مشکل اصلی goto نبود بلکه درهم پیچیدگی که در نتیجه حاصل میشد مشکلساز بود. گاهی یک break یا return هنرمندانه یک عبارت خیلی تمیزی به وجود میآورد که بفهمیم کد در آن ناحیه چه میکند. گاهی اضافه کردن goto به عبارت case میتواند فهم ساختار آن را سادهتر کند.
البته مثالهای نقضی هم وجود دارد. حفره امنیتی در انباره SSL اپل، در استفاده از goto، یکی از بهترین نمونههاست. اما اگر همه این موارد را در نظر داشته باشیم، پرشهای قطعی میتواند در پارهای موارد فهم اتفاقی که میافتد را برای خواننده سادهتر کند.
۲- اجتناب از مستندسازی
ممکن است شما هم با رئیسی روبرو شده باشید که لزوما به ازای هرتابع، انتظار مستند دارد. اما بعضی از کلاسها و بیشتر توابع میتوانند به نحوی نامگذاری شده باشند که خود آنها برای مستند کافی به نظر برسند. توابعی با اسامی شبیه deleteAll یا cancelReservation یا insertReservation نیاز به سطری دیگر برای مستند ندارند و هرکجای کد برنامه نیز به کار گرفته شوند اسامی آنها نشاندهنده کاری است که انجام میدهند.
گاهی وجود مستندات میتواند بد هم باشد. وقتی کد به سرعت در حال تغییر است و تیم refactoring مدام در حال کار روی کد هستند، کد با مستند ممکن است در گذر زمان تطابق نداشته باشد. حتی ممکن است تیم refactoring بعد از تغییر یک تابع مستندات آن را نیز اصلاح کنند اما در نظر نگرفتهاند که این تغییر منجر به تغییری عمده در رفتار برنامه شده که در مستندی در ابتدای فایل توضیح آن آمده است. به این ترتیب کد با متن نوشته شده مطابقت نداشته و کامنتها ممکن است بیارزش و گاها خطرناک باشند.
۳- انباشتن کد زیاد در یک خط
مدیرانی هستند که همواره به وجود تنها یک عملیات، یک گام یا یک عبارت در هر سطر تاکید دارند. وجود زنجیره فراخوانی در توابع، تعریف چند متغیر در یک سطر و وجود دو یا بیشتر عبارت محاسباتی در یک خط را غیر مجاز میدانند. دلیل این مساله را هم ساده شدن عملیات دیباگ کردن تعریف میکنند.
اما واضح است که چنین قانون کلی همواره مفید نیست. گاهی تعریف چند متغیر در یک خط یا قراردادن چند عبارت برای عملیات منطقی and در یک سطر درک کد را راحتتر میکند. درواقع بدون اسکرول کردن پی در پی میتوان راحتتر خواند و سریعتر کد را فهمید.
۴- تعریف نکردن نوع دادهها
کسانی که عاشق زبانهای برنامهنویسی تایپدار هستند توصیه میکنند که برای داشتن یک برنامه فاقد باگ همهی نوع متغیرها را تعریف کنید اما زمان تغییر کرده است بسیاری از کامپایلرهای جدید انقدر هوشمند هستند که نوع یک متغیر را از روی کد استنتاج کنند و در صورتی که عدم تطابقی دیدند اعلام خطا کنند.
۵- کد یویو
برنامهنویسان چنین چیزی را کد یویو مینامند که در آن به عنوان مثال متغیرها در رشته ذخیره شوند سپس به عدد صحیح پردازش شوند و مجددا به رشته تبدیل شده و ذخیره شوند. مسلما چنین چیزی کارا نیست و برنامهنویسانی که این روند را دنبال نکنند کد سریعتر و کاراتری خواهند داشت.
اما بعضی مواقع چنین چیزی هم معنی دارد. به عنوان مثال کتابخانهای دارید که خیلی از قابلیتهای مورد نیاز شما برای بخشی از کار را دارد اما این کتابخانه روی نوع داده دیگری کار میکند پس شما ترجیح میدهید دادهی خود را تبدیل کرده و از کتابخانه استفاده کنید چرا که زمان انجام این تبدیل شاید وقت بسیار کمتری از بازنویسی آن کتابخانه ببرد یا شاید کد کتابخانه در دسترس نباشد.
۶- نوشتن دادهساختارهای خودتان
بعد از گذراندن درس دادهساختارها حتما به شما توصیه شده است که کدی برای ذخیره کردن داده دیگر یادداشت نکنید بلکه کسانی قبلا تمام دادهساختارهای مورد نیاز را نوشتهاند و از آنها میتوانید استفاده کنید. کد آنها بارها و بارها تست شده و کد شما ممکن است باگهایی داشته باشد.
اما گاهی دادهساختارهای موجود اندکی کند هستند. گاهی ما را مجبور به تغییر در دادههایمان میکنند. گاهی حاوی سیستمهای حفاظتی مثل قفلکردن ریسهها هستند که در کد ما اصلا لازم نیست. در اینصورت خیلی بهتر است که داده ساختار خودمان را یادداشت کنیم که سریعتر بوده و نیازی به کدی برای تغییر فرمت دادهها نخواهد داشت و به همین دلیل کد تمیزتر خواهد شد.
۷- خروج از میانه حلقهها
قانونی هست که میگوید در حلقهها به دنبال عبارت منطقی باشید که در طول حلقه درست است و وقتی درست نباشد از حلقه خارج میشود. این قانون ما را از داشتن break یا return در حلقه محروم میکند. اما رعایت این قانون میتواند پیچیدگی اضافه کند. مثلا کد زیر که آرایهای را برای یافتن یک ورودی اسکن میکند را در نظر بگیرید:
while (i<a.length){ ... if (test(a[i]) then return a[i]; ... }
اگر بخواهیم از invariantها و ثابتهای حلقه استفاده کنیم کد به شکل زیر در میآید:
while ((notFound) && (i<a.length){ ... if (test(a[i])) then notFound=false; ... }
واضح است که کد فوق پیچیدگی اضافی داشته و حافظه اضافی برای متغیر notFound درنظر گرفته است. هرچند اسم آن طوری است که از وجود مستند آن را بینیاز میکند.
۸- استفاده از اسامی کوتاه برای متغیرها
Edgar Allan Poe تاکید داشت که هر کلمه در کد باید به تنهایی معنا داشته باشد. به این ترتیب همه متغیرها باید مفهومی را به خواننده انتقال دهند و برنامهنویسانی هستند که از ۵،۶ یا حتی ۷ کلمه چسبیده به هم برای نام متغیر استفاده میکنند. اما یک برنامهنویس هوشمند میداند که i یک متغیر شناخته شده برای شمارنده حلقه است و یا گاهی استفاده از j و l برای نام شمارنده حلقه یا نام یک لیست خیلی راحتتر مفهوم را منتقل میکند.
۹- تعریف مجدد توابع و متغیرها
بعضی از زبانهای برنامهنویسی قابلیتهای جالبی به شما میدهند مثلا تعریف مجدد یک متغیر ثابت. به عنوان مثال پایتون حداقل در ورژن ۲.۷ و قبل آن به شما اجازه میدهد که تعریف کنید TRUE=FALSE چنین کاری مشکل منطقی ایجاد نمیکند و فقط معنای TRUE و FALSE را جابهجا میکند. شما میتوانید چنین کاری را با پیش پردازندههای C و زبانهای دیگر انجام دهید. زبانهایی هم هستند که اجازه میدهند به عنوان مثال معنی عملگر + را تغییر دهید.
گاهی اتفاق میافتد که تعریف مجدد این ثابتها کارتان را سریعتر راه بیندازد. مثلا رئیستان از شما کدی کاملا متفاوت میخواهد. مسلما اگر شما در کدی آماده کار کرده و هر رخداد را تغییر دهید یا حقایق را مجددا تعریف کنید خیلی سریعتر از نوشتن یک کتابخانه بزرگ به نظر میرسد و فرد بسیار باهوشی نیز به نظر میرسید.
البته لازم است بگوییم که مهم نیست چقدر این کار بامزه به نظر میرسد اما چنین کاری را در خانه هرگز انجام ندهید. میتواند خیلی خطرناک باشد…باور کنید.
منبع: