واقعیتش من چند وقتی بود که داشتم کتاب “هنر کدنویسی خوانا” یا همان The Art of Readable Code را میخوندم و دیدم خیلی کتاب مفیدی هست و بد نیست که برنامهنویسان عزیز این کتاب را بخوانند، برای همین تصمیم گرفتم کتاب را ترجمه کنم و چند فصل از کتاب را هم اینجا منتشر کنم. امیدوارم مفید باشه و برنامه نویسان عزیزی مثل شما بعد از خوندن این کتاب کدهای تمیزتری بنویسید و کمی به شما در مسیر پیشرفت توی حوزه برنامهنویسی کمک کند.
خب در این پست فصل اول کتاب هنر کدنویسی خوانا را با موضوع کد باید به آسانی قابل درک باشد، با هم دنبال میکنیم:
فصل اول: کد باید به آسانی قابل درک باشد

حدود پنج سال قبل، ما هزاران مثال از کدهای بد را جمع آوری کردیم( که البته اکثرشان متعلق به خود ما بود)، سپس آنها را از این جهت که چه عاملی سبب بد شدن آنها شده بود و نیز قوانین و تکنیکهایی که برای بهتر شدن آنها استفاده کرده بودیم را مورد بررسی قرار دادیم. آنچه متوجه شدیم این بود که همه اصول ناشی از یک مورد واحد است.
کلید طلایی:
کد باید به آسانی درک شود.
ما معتقدیم این کلید طلایی، مهمترین اصل راهنمایی است که میتوانید هنگام تصمیم گیری در مورد نوشتن کد خود استفاده کنید.در طول این کتاب، نشان خواهیم داد که چگونه میتوانید این اصل را در جنبههای مختلف کدنویسیهای روزانه خود بکار ببرید. اما قبل از شروع، اجازه دهید در این مورد که چرا این اصل اینقدر مهم است، توضیح دهیم.
چه چیزی باعث بهتر شدن کد میشود؟
اکثر برنامهنویسان(از جمله خود من) تصمیمات برنامهنویسی را بر اساس احساسات و دریافت ناگهانی میگیرند.
همه ما میدانیم که کدی شبیه این:
for (Node* node = list->head; node != NULL; node = node->next) Print(node->data);
بهتر از کدی شبیه به این یکی است:
Node* node = list->head; if (node == NULL) return; while (node->next != NULL) { Print(node->data); node = node->next; } if (node != NULL) Print(node->data);
حتی اگر فکر کنید که هر دو مثال دقیقاً شبیه هم عمل میکنند، اما در بسیاری از مواقع این انتخاب سخت است، برای مثال کد زیر را ببینید:
return exponent >= 0 ? mantissa * (1 << exponent) : mantissa / (1 << -exponent);
نسخه اول فشردهتر است، اما نسخه دوم کمتر ترسناک است. به نظر شما کدام معیار اهمیت بیشتری دارد؟ فشردگی یا ترسناک نبودن؟ به طور کلی چگونه تصمیم میگیرید که با چه معیاری چیزی را کدنویسی کنید؟
if (exponent >= 0) { return mantissa * (1 << exponent); } else { return mantissa / (1 << -exponent); }
قضیه بنیادی خوانایی
بعد از مطالعه کدهای زیادی شبیه کدهای بالا، ما به این نتیجه رسیدیم که یک معیار برای خوانایی وجود دارد که مهمتر از بقیه موارد است. این معیار خیلی مهم است به همین دلیل آن را قضیه بنیادی خوانایی نام گذاری میکنیم.
کلید طلایی
کد باید به گونهای نوشته شود که زمان فهمیدن آن توسط شخص دیگر، کمترین میزان ممکن باشد.
منظور ما از این جمله چیست؟ به معنی واقعی کلمه اگر شما از یک همکار معمولی خود بخواهید که کدتان را بخواند و در همان زمان مقدار زمانی که او کد شما را خوانده و درک میکند را اندازه بگیرید، این «زمان تا فهمیدن» معیاری تئوری خواهد بود که شما برای حداقل بودن زمان درک کدتان نیاز دارید.
زمانی که میگوییم «درک کردن»، این کلمه بار معنایی زیادی دارد. برای اینکه کسی کد شما را به طور کامل درک کند، باید بتواند در آن تغییرات ایجاد کرده، اشکالات آن را پیدا کند و نحوه تعامل این کد با بقیه برنامه شما را بفهمد.
ممکن است به این فکر کنید که چه کسی اهمیت میدهد که شخص دیگری بتواند کد را درک کند یا نه؟ من تنها کسی هستم که از این کد استفاده میکنم! ولی بدانید که حتی اگر در یک پروژه تک نفری هستید، دنبال کردن این هدف ارزشش را دارد، چراکه ممکن است شش ماه بعد، یعنی زمانی که کدتان برای شما ناآشنا شده، آن شخص دیگر، خود شما باشید، همچنین ممکن است شخص دیگری به پروژه شما بپیوندد یا کد بی مصرف شما در پروژه دیگری مجدداً استفاده شود، پس هم اکنون ارزش دارد که کد خود را قابل درک بنویسید.
آیا همیشه کوتاهتر بودن بهتر است؟
به طور کلی، هرچه کد کمتری برای حل یک مسئله بنویسید، بهتر است.(به فصل ۱۳ مراجعه کنید). بیشک درک یک کلاس ۲۰۰۰ خطی نسبت به یک کلاس ۵۰۰۰خطی زمان کمتری از شما میگیرد.
اما خطوط کمتر همیشه هم بهتر نیست! در مواقع زیادی شما با یک عبارت تک خطی، شبیه این عبارت مواجه میشوید:
assert((!(bucket = FindBucket(key))) || !bucket->IsOccupied());
این حالت، نسبت به حالتی که عبارت دو خطی است، زمان بیشتری برای درک کد از شما میگیرد:
bucket = FindBucket(key); if (bucket != NULL) assert(!bucket->IsOccupied());
به طور مشابه، یک کامنت میتواند سبب درک سریعتر کد شود، حتی اگر کد بیشتری را به فایل اضافه کند:
// Fast version of "hash = (65599 * hash) + c" hash = (hash << 6) + (hash << 16) - hash + c;
بنابراین هر چند داشتن خطوط کد کمتر هدف خوبی است، ولی به حداقل رساندن زمان درک کردن[1] کد، هدفی بهتر است.
آیا معیار «زمان درک کردن کد» با دیگر اهداف تداخل دارد؟
احتمالا به این فکر میکنید که، پس سایر محدودیتها را چه کنیم؟ مثلاً کارآمدی[2] بهتر کد، یا معماری بهتر یا ساده بودن کد برای تست، یا دیگر موارد؟ آیا گاهی اوقات، این موارد با کاری که میخواهید برای راحتتر درک شدن کد انجام دهید، تداخل ندارند؟
ما متوجه شدیم هیچ تداخلی با اهداف دیگر وجود ندارد. حتی در حوزه کدهای بسیار بهینه، هنوز میشود با روشهایی آنها را بسیار خواناتر نمود. نوشتن کد به شکلی که سادهتر درک شود، در موارد زیادی کدهایی را نتیجه میدهد که معماری خوبی داشته و تست آنها نیز سادهتر است.
در ادامه کتاب در مورد چگونگی «ساده خوانده شدن کد» در شرایط مختلف بحث خواهد شد. اما هر زمان که دچار تردید شدید، به یاد داشته باشید که «قضیه اساسیِ خوانایی»، هر قانون یا اصل دیگری در این کتاب را به زیر کشده و همیشه حرف اول را میزند.
همچنین برخی از برنامهنویسها برای تصحیح کدهایی که به خوبی بازسازی نشدهاند نیاز به اجبار دارند. همیشه این سوال مهم است که برگردیم و بپرسیم، آیا این کد برای درک شدن آسان است؟ اگر بله، احتمالاً خوب است، پس بررسی کدهای دیگر را ادامه میدهیم.
بخش سخت
بله، شما به تمرینهای زیادی نیاز دارید. این تمرین که باید به طور دائم شخصی خیالی را که بتواند به راحتی کد شما را درک کند، در نظر بگیرید. انجام این کار مستلزم روشن کردن بخشی از مغز است که ممکن است قبلاً هنگام کدنویسی روشن نشده باشد.
اگر این هدف را در نظر داشته باشید(همانگونه که هدف ما است)، یقین داریم که به یک کدنویس بهتر تبدیل خواهید شده و کمتر باگ خواهید داشت. همچنین بیشتر به کار خود افتخار نموده و کدی تولید خواهید کرد که هر شخص دیگری مشتاقانه از آن استفاده خواهد نمود. پس بیاید شروع کنیم!
[1] Time-Till-Understanding
[2] efficient