تجربه‌هایی ارزشمند در توسعه نرم‌افزار

مدتی پیش این مقاله رو با عنوان اصلی «درس‌هایی که در توسعه نرم‌افزار آموختم» در وبلاگ Henrik Warne خوندم. نویسنده یک برنامه‌نویس باتجربه است و این مقاله‌اش خیلی مورد توجه قرار گرفته طوری که می‌تونید در لیست‌ «مقاله‌هایی که باید بخوانیم» توسعه‌دهنده‌ها پیداش کنید. خودش میگه اینها لیستی از اکتشافات و قوانین من برای توسعه نرم‌افزاره که در طول این سال‌ها ازشون استفاده کردم. پس بریم سراغ این اکتشاف‌ها که اگر یک برنامه‌نویس هستید، حسابی ارزش خوندن داره.

از کم شروع کنید، سپس گسترشش بدید. فرقی نمی‌کنه یک سیستم جدید ایجاد می‌شه یا یک فیچر (feature) جدید به سیستم موجوداضافه می‌شه، من همیشه با ساختن یک نسخه بسیار ساده با تقریباً هیچ یک از عملکردهای مورد نیاز شروع می‌کنم. سپس راه حل رو گام به گام توسعه می‌دم، تا وقتی که تبدیل به چیزی که انتظارش رو داریم بشه. من هیچ وقت نتونستم همه چیز رو از ابتدا و با جزئیات برنامه‌ریزی کنم. در عوض، همین طور که پیش میرم، یاد می گیرم و از این اطلاعات تازه کشف شده در راه حل خودم استفاده می‌کنم. این نقل قول رو دوست دارم که "سیستم پیچیده‌ای که درست کار می‌کنه همیشه از تکامل سیستم ساده‌ای که درست کار می‌کرده ایجاد شده."

در هر لحظه یک چیز واحد رو تغییر بدید. وقتی در حال توسعه هستید و برخی از تست‌ها با شکست مواجه می‌شن یا یک فیچر درست کار نمی‌کنه، پیدا کردن مشکل خیلی راحت‌تره اگر فقط یک چیز رو تغییر بدید. به عبارت دیگه از یک سری تکرارهای کوتاه استفاده کنید: یک تغییر مستقل و واحد انجام بدید، مطمئن شید که کد کار می‌کنه، و این چرخه رو تکرار کنید. این روش رو برای کامیت‌ها هم بکار ببرید. اگر باید قبل از اضافه کردن یک فیچر جدید، کد رو ریفکتور (refactor) کنید، ابتدا ریفکتور رو انجام بدید و کامیت کنید. بعد (در یک کامیت مجزا) فیچر جدید رو اضافه کنید.

ثبت لاگ (Logging) و مدیریت خطا (Error Handling) رو هر چه زودتر اضافه کنید. وقتی یک سیستم جدید رو توسعه میدم، یکی از اولین کارهایی که انجام می‌دم اضافه کردن گزارش و مدیریت خطاست، چون هر دو از همان ابتدای کار مفید هستن. برای همه‌ی سیستم‌ها نیاز به روشی داریم که بفهمیم در برنامه چه اتفاقی داره می‌افته. به محض اینکه برنامه طبق انتظار رفتار نکنه باید بتونیم ببینیم چه اتفاقی افتاده. همین قانون در مورد مدیریت خطا هم صادقه. خطاها و استثناها از همون ابتدای برنامه اتفاق می‌افتن، بنابراین هر چه زودتر اونها رو به روشی سیستماتیک مدیریت کنیم بهتره.

تمام خطوط جدید برنامه باید حداقل یک بار اجرا بشن. قبل از اینکه کارمون با یک فیچر تموم بشه، باید تستش کنیم. در غیر این صورت از کجا بفهمیم که کاری رو که باید، انجام میده؟ هر خط کد جدید باید حداقل یک بار اجرا بشه. گاهی اوقات ایجاد شرایط مناسب برای تست کد ممکنه سخت باشه. خوشبختانه اینجا می‌تونیم تقلب کنیم! مثلا شرط if رو موقتا معکوس کنیم تا شرایطی که به ندرت اتفاق می‌افته رو ایجاد کنیم. فقط برای اینکه مطمئن بشیم کد اجرا میشه و کاری که باید بکنه رو درست انجام میده.

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

اول هر یک از ماژول‌ها رو به تنهایی تست کنید. قطعات کدی که به خوبی تست شدن باعث صرفه جویی در زمان می‌شن. وقتی ماژول‌های کد رو ادغام می‌کنیم احتمال بروز مشکل هست. مثلا به خاطر درک نادرست واسط (Interface) ماژول ها. اگر مطمئن باشیم که تک تک ماژول‌ها طبق انتظار کار می‌کنن، ردیابی مشکلات ناشی از ادغام اونها بسیار آسون‌تره.

همه چیز بیشتر از چیزی که فکر کنید طول می‌کشه. مخصوصا در برنامه نویسی. تخمین این که یک فیچر چقدر زمان می‌بره، حتی اگر همه چیز به خوبی پیش بره، خیلی سخته. هنگام توسعه نرم‌افزار خیلی مواقع با مشکلات غیرمنتظره مواجه می‌شیم: یک مرج ساده باعث ایجاد یک باگ می‌شه یا ارتقاء یک فریم‌ورک باعث می‌شه بعضی فراخوانی‌های توابع نیاز به تغییر داشته باشن. به نظرم قانون هافستاتر خیلی درسته: همیشه بیشتر از چیزی که انتظار دارین طول می‌کشه، حتی اگر قانون هافستاتر رو در نظر بگیرین!

اول کد فعلی رو درک کنید. کدنویسی اکثرا نیازمند تغییر کد موجوده. حتی اگر دارید یک فیچر جدید توسعه می‌دید در نهایت باید در برنامه فعلی بشینه. و قبل از اینکه بتونید فیچر جدیدی به سیستم اضافه کنید، باید راه حل فعلی رو درک کنید. وگرنه ممکنه تصادفا بعضی از عملکردهای فعلی رو خراب کنید. این یعنی خوندن کد مهارتیه که به اندازه نوشتن کد ضروریه. این هم یک دلیل دیگه که چرا تغییرات به ظاهر کوچیک می‌تونه زمان زیادی طول بکشه چون باید قبلش بستری (context) که در اون تغییر ایجاد می‌کنید رو درک کنید.

بخونید و اجرا کنید. دو روش مکمل برای درک کد وجود داره: کد رو بخوانید و کد رو اجرا کنید. اجرای کد می‌تونه کمک بزرگی باشه تا بفهمید کد داره چه کاری انجام می‌ده اما حتما همزمان از هر دو روش استفاده کنید.

همیشه باگ وجود داره. من رویکردهای توسعه‌ی نرم‌افزاری که ادعا می‌کنند «بار اول کار درست رو انجام بده» دوست ندارم. مهم نیست چقدر تلاش کنیم، همیشه باگ‌هایی وجود دارن. تعریف باگ هم تقریباً همینه: «فکرش رو نکرده بودیم!». رویکرد بهتر اینه که سیستمی داشته باشیم که باگ‌ها رو سریع پیدا و رفع کنیم.

مشکلات گزارش شده رو حل کنید. هر توسعه‌دهنده‌ای باید بخشی از زمانش رو صرف رسیدگی به مشکلات گزارش شده مشتریان و رفع اشکال اونها کنه. این کار درک بسیار بهتری از نحوه استفاده‌ کاربران از سیستم و تناسب طراحی سیستم با نیاز کاربران بهتون می‌ده. این کار یک روش عالی هم هست برای قبول مسئولیت سیستمی که توسعه دادین. هیچ کدوم از این مزایا رو از دست ندید.

مشکل رو بازتولید (reproduce) کنید. اولین قدم در رفع یک باگ، بازتولیدشه. اینطوری وقتی رفع باگ انجام شد، می‌تونید مطمئن باشید که مشکل برطرف شده. این قانون ساده کمک می‌کنه چیزی رو به اشتباه مشکل فرض نکنید و مطمئن باشید که راه‌حل‌تون واقعاً همون کاری رو که فکر می‌کنین انجام می‌ده.

خطاهای شناخته شده رو رفع کنید بعد ببینید چی باقی مونده. گاهی اوقات چندتا مشکل وجود داره که براتون شناخته شده هستن. اشکالات مختلف ممکنه با هم تعامل داشته باشن و باعث اتفاقات عجیب و غریب بشن. پس به جای اینکه برای پیدا کردن دلیل این اتفاق‌ها تلاش کنید، اول مشکلات شناخته شده رو رفع کنید و بعد ببینید چه علائمی هنوز باقی مونده.

چیزی رو تصادفی فرض نکنید. وقتی در حال تست و عیب یابی هستید هرگز چیزی رو اتفاقی درنظر نگیرین. شما یک مقدار تایمر رو تغییر دادید حالا سیستم بیشتر ری‌استارت می‌شه؟ این تصادفی نیست. یک فیچر جدید اضافه شد و یک فیچر نامرتبط کندتر شد؟ این تصادفی نیست. به جای این فرضیه‌ها تحقیق کنید.

با Timestampها ارتباط برقرار کنید. وقتی دیباگ می‌کنید از timestamp رویدادها کمک بگیرید. مثلا اگر سیستم ری‌استارت شده و ریکوئستی حدود 3000 میلی ثانیه قبلش ارسال شده، احتمالا یک تایمر رویدادی رو راه‌اندازی کرده که منجر به ری‌استارت شدن سیستم شده.

ارتباط چهره به چهره بیشترین پهنای باند رو داره. وقتی بحث چگونگی حل یک مشکل در میونه، چهره به چهره بودن ارتباط به تماس ویدیویی، چت یا ایمیل برتری داره. اغلب از اینکه چقدر راه حل‌ها پس از بحث حضوری با همکاران باکیفیت‌تر هستن شگفت زده می‌شم.

اردک پلاستیکی. هر وقت گیر کردید، پیش یکی از همکاران‌تون برید و مشکل رو براش توضیح بدید. خیلی وقت‌ها حین صحبت متوجه می‌شید مشکل چیه. حتی اگر همکارتون یک کلمه هم حرف نزنه. شبیه جادو به نظر میاد اما این کار به طرز شگفت انگیزی تاثیر می‌ذاره.

بپرسید. خواندن و اجرای کد معمولا برای فهمیدن اینکه کد چه کاری انجام می‌ده یا چطور کار می‌کنه عالیه. اما اگر براتون مقدوره که از شخصی آگاه (شاید برنامه‌نویس قبلی کد) سوال بپرسید، گزینه‌ی خوبی دارین. توانایی پرسیدن سؤالات درست می‌تونه در عرض چند دقیقه اطلاعاتی رو بهتون بده که شاید پیدا کردنشون با روش‌های دیگه روزها طول می‌کشید.

اعتبار رو به اشتراک بذارید. جایی که اعتبار دادن ارزش محسوب می‌شه حتما به همکارتون اعتبار بدید. مثلا بگید: «امیر ایده داد که این رو امتحان کنیم...» (اگر این کار رو کرده بود البته)، به جای اینکه بگید «ما این رو امتحان کردیم ...». به این که کی کمک و کی مشارکت کرده اشاره کنید.

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

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

تغییر ایجاد کنید. از تغییر نقش یا شغل نترسید. کار با افراد مختلف، روی یک محصول متفاوت یا در یک شرکت متفاوت، نوعی محرکه.

به یادگیری ادامه دهید. یکی از خوبی‌های توسعه نرم‌افزار اینه که همیشه فضایی برای یادگیری و دانستن بیشتر وجود داره. زبان‌ها و ابزارهای برنامه‌نویسی مختلف رو امتحان کنید، کتاب‌هایی در زمینه توسعه نرم‌افزار بخوانید، در دوره‌های MOOC شرکت کنید. به زودی پیشرفت‌های کوچکی ایجاد می‌شن که تفاوتی واقعی در دانش و توانایی‌هاتون ایجاد می‌کنند.