Writing code is about making your computer do what you need.
Writing good code is about enabling teams of strangers 5 years from now to make their computers do what they need.
François Chollet
Writing code is about making your computer do what you need.
Writing good code is about enabling teams of strangers 5 years from now to make their computers do what they need.
François Chollet
پیشگفتار:
مدتی است که با خود میاندیشم تجربیاتم را در حوزهی نرمافزار در اینجا بنویسم، هم ماندگار خواهد شد و هم شاید به دوستی کمک کند. نمیدانم “الگوی ایجاد نرمافزار” عبارت مناسبی هست یا نه، ولی تا یافتن عبارت مناسبتر از آن استفاده خواهم کرد.
قرارداد:
قرارداد یا عقد یا پیمان یا کنترات یک توافق الزامآور میان اشخاص است که حقوق و تکالیف طرفین آن را تعیین میکند. در تعبیر حقوقی به توافق دو یا چند اراده در جهت ایجاد یک اثر حقوقی گویند. [ویکی پدیا]
همان طور که از متن تعریف بر میآید قرارداد، “حقوق” و “تکالیف” طرفین را تعیین میکند. برای نمونه در قرارداد پروژه بین پیمانکار و کارفرما تعیین میشود که پیمانکار چه “تکالیف” و چه “حقوقی” دارد و همین طور کارفرما چه “تکالیف” و “حقوقی” دارد. برای مثال در یک پروژهی نرمافزاری، پیمانکار مکلف است تا پایان ماه اول، پروتوتایپ سیستم را به کارفرما تحویل دهد و تحویل پروتوتایپ در پایان ماه اول، حق کارفرماست. برای انجام پروتوتایپ، کارفرما مکلف است تا مستندات تعیینشده را در اختیار پیمانکار قراردهد (تکلیف کارفرما).
به زبان سادهتر:
– کار: تهیه پروتوتایپ
– تکالیف کارفرما: تحویل مستندات تعیینشده به پیمانکار
– تکالیف پیمانکار: تحویل پروتوتایپ در مدت یک ماه
قراردادها در برنامهنویسی:
تا جایی که میدانم هر سیستم نرمافزاری از مجموعهای از عناصر یا المانها تشکیل شده است. این عناصر میتوانند اجزایی مانند تابع (function)، کلاس (class) یا رویهها (procedure) باشند. این عناصر با مکانیزمهایی میتوانند با همدیگر تعامل کنند. یک تابع میتواند تابع دیگری را صدا کند و آن تابع نیز به نوبهی خود میتواند تابع بعدی را صدا کند. این زنجیرهی تعامل یعنی کنش و واکنش بین اجزای سیستم، رفتار آن را شکل میدهد.
اجازه بدهید در سادهترین حالت ممکن بحث را ادامه بدهیم. فرض بفرمایید دو تابع f و g وجود دارند. تابع f برای انجام کاری تابع g را صدا میکند. کار مورد درخواست را هم محاسبه ریشهی دوم یک عدد طبیعی (1,2,3,…) تعریف مینماییم.
در این حالت میتوانیم فرض کنیم که تابع f مانند کارفرما و تابع g مانند پیمانکار عمل خواهند کرد. نتیجه:
– کارفرما: تابع f
– پیمانکار: تابع g
– موضوع قرارداد: محاسبه ریشهی دوم یک عدد طبیعی
حالا بیایید کمک کنیم تا بین تابع f و g قراردادی منعقد شود:
– کارفرما مکلف است که فقط اعداد طبیعی را ارسال کنید
– کارفرما محق است که ریشهی دوم عدد ارسال شده را به صورت یک عدد با دو رقم اعشار دریافت کند
– پیمانکار مکلف است که ریشهی دوم عدد را به دو رقم اعشار گرد کند (round)
– پیمکانکار محق است که عدد طبیعی دریافت کند در غیر این صورت مکلف است خطا یا استثناء (Exception) را گزارش نماید.
حالا که قرارداد بین کارفرما و پیمانکار منعقد شد، میتوانیم پیادهسازی تابع g را شروع کنیم. پیادهسازی را میتوان به سه بخش تفکیک کرد:
– بخش اول: تابع g ابتدا باید کنترل کند که عددی که دریافت کرده، یک عدد طبیعی (صحیح و بزرگتر از صفر) است. طبق قرارداد، اگر عدد دریافتی، یک عدد طبیعی نباشد، تابع g باید خطا یا استثناء را گزارش کند (بازگرداندن کد خطا یا پرتاب استثناء (Throw Exception)).
– بخش دوم: تابع g باید روشی برای محاسبه ریشهی دوم یک عدد طبیعی پیادهسازی کند. برای انجام این کار، میتوان از “تقریب” در ریاضیات استفاده کرد.
– بخش سوم: مطابق قرارداد، نتیجهی به دست آمده در مرحلهی قبل باید به دو رقم اعشار گرد شود و به کارفرما یعنی تابع f بازگردانده شود.
تمام!
پسگفتار:
این شیوهی نگاه به اجزای نرمافزاری در قالب یک کارفرما، یک پیمانکار و یک قرارداد، روشی ساده، مفید و کاربردی برای طراحی و پیادهسازی در نرمافزار است. ایدهی اصلی این الگو از روش “طراحی با قرارداد” (Design By Contract) است. این روش که توسط برتراند مایر ابداع شده است در دنیای شیءگرایی بسیار معروف و جاافتاده است.

نکتهای که در این الگو به آن افزوده شده این است که با در نظر نگرفتن شیگرایی و انتقال این ایده به عناصری مانند تابع (function)، این الگو برای زبانهایی که ماهیت شیءگرایی هم ندارند قابل استفاده است از جمله پایتون و جاوا اسکریپت.
امیدوارم که قراردادهای بسیار باارزشی منعقید کنید!
گزیده:
اگر میخواهید سریعتر پیش بروید، اگر میخواهید سریعتر کارها را تمام کنید، اگر میخواهید نوشتن کد برایتان آسان و راحت باشد، کاری کنید که خواندن کدتان آسان و راحت باشد.
رابرت سی. مارتین
پیشگفتار:
مانند هر انسان دیگری، از دیرباز یک سری پرسش در ذهنام نقش بسته است، و از آنجا که پاسخهای یافتهشده قانعام نکرده، هر از گاهی دوباره فرصتی پیدا میکنند و خودشان به سر صف میرسانند و فرصتی پیدا میکنند تا بخشی از ظرفیت مغزم را به خود اختصاص دهند. من هم به مانند بسیاری از انسانها هم از سر علاقه و هم از سر ناچاری برای رضایت آنها، کمی دنبال منابع جدید میگردم و آنها را مطالعه میکنم و هم از دوستان باتجربهام کمک میگیرم شاید به نقطهی قابل قبولی برسم.
پرسشها:
دیروز از چند تن از دوستانم که در جمعی حاضر بودند خواهش کردم که به سه پرسش زیر فکر کنند و به آن پاسخ بدهند.
پرسش اول: اگر پیادهسازی یک ویژگی جدیدِ سیستم به شما سپرده شود، چگونه و طی چه گامهایی آن را به کد تبدیل میکنید؟ (تاکید روی بخش طراحی است)
پرسش دوم: اگر قرار باشد راهنمای یک برنامهنویس باشید تا ویژگی جدید را پیادهسازی کند، مراحل انجام این کار را در قالب چه گامهایی به او خواهید آموخت؟ (تاکید روی آموزش طراحی حین کار است)
پرسش دوم: اگر قرار باشد پیادهسازی یک ویژگی جدید را در یک کلاس آموزشی به شاگردان آموزش دهید، آموزش شما شامل چه بخشهایی خواهد بود؟ (تاکید روی آموزش عمومی طراحی است)
گزیده:
اعمال یک تغییر در کد ممکن است منجر به ایجاد زنجیرهای از تغییرات در نرمافزار شود که دلیل آن، وجود وابستگی (coupling) بین اجزای نرمافزاری است. در نتیجه هزینهی این تغییر برابر است با جمع هزینهی کل این تغییرات. از سوی دیگر، کاهش یا حذف وابستگی بین این اجزای وابسته (decoupling) نیز نیازمند صرف هزینه است.
از این رو به عنوان برنامهنویس همواره ناچارید بین هزینهی تجمیعی زنجیرهی تغییرات ناشی از وابستگی (coupling) و هزینهی لازم برای جداسازی آنها (decoupling)، یکی را انتخاب کنید (trade-off).
کنت بک
پیشگفتار:
[…] یکی از دوستان محبوب من است که سالهاست او را ندیدهام و چند سالی است که در کشور دیگری زندگی میکند. او بیشتر از آن که مهندس باشد، فیلسوف است. نگاهی متفاوت به دنیا دارد. این تفاوت نگاه در کنار دوستی خالصانه و گفتار بیرنگ و لعابش باعث شده تا گفتگو با او همواره برای من آموزنده همراه با حس خوب باشد.
او یکی از خوانندگان قدیمی وبلاگ است. پس از انتشار مطالب اخیر وبلاگ، این پیامها را از او دریافت کردم. آن قدر دلنشین بود که با کسب اجازه از او و با کمی تغییرات، آن را در اینجا آوردهام.
در این پیام، او به یک کار مشترک، یک دوست مشترک و یک خودروی پراید اشاره میکند. ما با هم چند کار مشترک انجام دادیم. برای انجام یکی از این کارها، دوست دیگرمان که خودروی پراید داشت، مانند سرویس مدرسه، یکی یکی ما را از درب منزل سوار ماشین میکرد تا به محل انجام کارمان برسیم. تفاوت این سرویس با سرویس مدرسه در این بود که سرویس مدرسهی ما صبح روزهای تعطیل کار میکرد. یادش به خیر!
متن پیام:
مهندس مهرداد گل سلام..
کمی قبل داشتم نوشته هاتون رو میخوندم.. از گرمای هوا و به افتخار هانیه.
روز قبل وارد ۳۸ سالگیم شدم. هر از چند گاهی فکر میکنم به این راهی که توی این سالها رفتم و سفر زندگی خودم و برخی دوستانم رو مرور میکنم.
اگه میتونستم برگردم عقب و به […] ۲۵ ساله یه پیغام بدم اون این بود که “کلا مهم نیست. زیاد زندگی رو، دلخوریها رو، شکستها و موفقیتها رو جدی نگیر“.
اگه بر میگشتم عقب، به جای اینکه به این فکر کنم که کی کار […] تموم میشه، بیشتر سعی میکردم از دورهمیهامون توی پراید […] لذت ببرم. به جای اینکه به موفقیت محض و کار کردن توی بهترین شرکتها تمرکز کنم، بیشتر سعی میکردم از تکتک لحظههای با هم بودنمون لذت ببرم.
بیشتر سعی میکردم از حال و هوای صبحونهای مادرم و نونی که پدرم میخرید لذت ببرم.
تخته وایت برد هانیه رو دیدم و یادم افتاد اون وقتها چند تا از این نمودارهای بازدهی کشیده بودم. اگه عقب بر میگشتم سعی میکردم بیشتر لحظات سادهتر رو زندگی کنم.
مهندس جان دارم شهرم رو عوض کنم و جا به جا میشم.
میرم به یه شهر دیگه.. یه شهر آرومتر هست. اینجا […] مثل نیویورک میمونه. قلب قاره […]. همه در حال رقابت و در حال رسیدن به هدفها. یه شهر ایدهآل برای آدمی مثل من.
چند ماه قبل فرصتی پیش اومد که برم به یه شهر شمالی. جایی که از این رقابتها خبری نیست. دیدم ای بابا، زندگی جریان داره بدون رقابت، بدون هوش مصنوعی، بدون دویدن دنبال هدفهای بزرگ، بدون کار کردن توی بزرگترین شرکتهای دنیا. هیچ کم و کسری هم نیست. مردم […] خواب ندارن. در واقع مشکل خواب دارن. استرس دارن. فقط و فقط واسه اینکه شب میخوابن با هدف اینکه فردا برن و یه هدف دیگر رو هم بزنن.
به سماموس فکر کن. مردم زندگی میکنن، هیچ کم و کسری هم ندارن بدون هوش مصنوعی و داشتن ۱۰۰ هدف. واسه همین تصمیم گرفتم برم به یه شهر آرامتر.
گزیده:
هرچه از عمرتان بیشتر میگذرد، کمتر تلاش میکنید تا ثابت کنید فرد خوبی هستید. والا افشار
مقدمه: بازسازی کد
بازسازی کد یا refactoring، یک واژهی تخصصی است که معنی آن، بهبود کیفیت کد یک سیستم است بدون آن که تغییری در رفتار خارجی آن ایجاد شود. مشابه غیرافزاری بازسازی کد، بازسازی داخلی یک خانه است که بدون آن نمای خارجی خانه دچار تغییر شود، اجزای داخلی آن مانند تاسیسات و چیدمان وسایل تغییر میکنند.
حالا اگر بهبود کیفیت کد منجر به خطاهای جدید یا تغییرات در رفتار سیستم گردد، آیا چنین کاری، بهبود یا بازسازی کد است؟ مسلما خیر! پاسخ این پرسش از این بابت اهمیت دارد که هر تغییری در کد، بازسازی محسوب نمیشود ولی بازسازی حتما با تغییر کد همراه است: هر گردی گردو نیست!
در بازسازی کد، بهترین رویکرد، اعمال تغییرات هدفمند و کوچک است. برعکس رویکرد ایجاد تغییرات بزرگ و گسترده، بازسازی کد اقدامی درازمدت و پیوسته است (آهسته و پیوسته). دلیل چنین رویکردی این است که اعمال یکبارهی تغییرات بزرگ و گسترده، موجب ریسک بیشتر و نیازمند زمان طولانیتری است.
رهرو آن نیست
که گه تند و گهی خسته رود
رهرو آن اسـت که آهستـــــه و پیـــوسته رود
بدیهی است که یکی از مزایای بازسازی کد این است که وقت گذاشتن پیشاپیش و تدریجی برای افزایش کیفیت کد باعث افزایش سرعت تیم در آینده میشود.
پرسش:
به تازگی، نمونهی آموزنده و جالبی از بازسازی کد خواندم که در اینجا با شما در میان میگذارم. ابتدا صورت پرسش را مطرح میکنم تا آن را بررسی نمایید.
آیا پیشنهادی برای بازسازی کد زیر دارید؟ قبل از ارائه پیشنهاد، چه پرسشهایی برای شما مطرح است؟ لطفا با پاسخهای پیشفرض خود، کد زیر را بازنویسی نمایید و اگر دوست داشتید آن را اینجا به اشتراک بگذارید.
if(user.role === "admin" && user.isActive && user.permissions.some(p => p === "edit")) {
// Do stuff
}پ.ن.
شاید ترجمه بهتر این باشد: حرف زدن که مالیات نداره، کدت رو نشون بده!
شهرت برایان کرنیگان در کنار دنیس ریچی به دلیل کتاب معروف برنامهنویسی C است.
منبع کد: کتاب Refactoring TypeScript نوشتهی James Hickey