چگونه تابع های بهتری بنویسیم و چرا؟

برای اکثر برنامه نویس های تازه کار ممکن است اهمیت تابع ها و استفاده ی درست از آن ها زیاد مشخص نباشد. حتی ممکن است در ابتدا تعریف کردن تابع ها کار بیهوده ای به نظر برسد و برنامه نویس ترجیح بدهد که تمام کدها را به صورت ترتیبی بنویسد. در این مطلب میخواهیم بررسی کنیم که چرا باید از تابع ها استفاده کنیم و چطور میتوانیم بیشترین بهره برداری را از ویژگی هایی که در اختیار ما قرار میدهند بکنیم.چرا باید از تابع ها استفاده کنیم؟تابع ها در واقع این امکان را به ما میدهند که قسمتی از کد را بسته بندی کنیم و به آن یک اسم دهیم. حالا هر وقت که نیاز به آن قسمت از کد بود میتوانیم اسمش را صدا بزنیم و کار موردنظر ما انجام می شود.زیاد مفهوم پیچیده ای نیست ولی همین ویژگی به ما این امکان را میدهد که تا حدودی راه حلمان را انتزاعی تر کنیم. همانطور که وقتی تلفنی پیتزا سفارش میدهیم میدانیم که باید پول را بدهیم و پیتزا را تحویل بگیریم و نه میدانیم پیتزا چطور آماده می شود و نه اهمیتی برایمان دارد در حال استفاده کردن از تابع ها هم لازم است بدانیم که تابع مورد استفاده چه آرگومان هایی دارد(چه اطلاعاتی نیاز دارد که بتواند کارش را انجام دهد.) و چه مقدار بازگشتی ای بر میگرداند و این که چطور این کار را میکند برای ما اهمیتی ندارد. اینطوری میتوانیم تمرکزمان را روی قسمتی که در حال کار کردن بر روی آن هستیم بگذاریم و اگر تابع مورد نظر آماده است که کار تمام است و در غیر این صورت بعدا به فکر پیاده سازی اش بیافتیم.اگر بخواهم مزایای استفاده کردن از تابع ها را نام ببرم موارد زیر را عنوان میکنم:1. متوجه شدن کد آسان تر است. چون به جای سینتکس های زبان بیشتر با فراخوانی تابع ها سر و کار داریم که اگر اسم آن ها به درستی انتخاب شود خواندن کد مثل خواندن یک متن انگلیسی آسان می شود.int main(){ int number, base; cin >> number >> base; int result = decimalToBaseX(number, base); cout << result; }شما تنها با خواندن اسم تابع متوجه خواهید شد که این برنامه عددی را میگیرد و به مبنای دلخواه کاربر میبرد و نمایش میدهد. در حالی که اگر از تابع استفاده نمیکردیم احتمالا از چندین متغییر و یک حلقه در این بین استفاده میکردیم که شاید برای فهمیدن کاربردشان نیاز به کمی فکر کردن بود.2. تست کردن کد آسان تر است. تصور کنید مثال بالا شامل چندین مرحله دیگر هم بود، مثلا عددی باید به مبنای دلخواه میرفت، رقم هایش برعکس میشد و تصور میشد عدد حاصل ده دهی است(یعنی رقم هایش همان بود ولی مبنا عوض میشد، کار معمولی نیست ولی توی تمرین ها از این کارها میکنیم :))) ) و در نهایت عوامل اول عدد حاصل نمایش داده میشد. اگر بخواهیم این کد را بدون تابع بنویسیم، یک کد اسپاگتی خوشمزه(کدی که بسیار شلوغ و وابسته به هم است، یعنی رفتار هر قسمت آن ممکن است روی قسمت دیگر تاثیر بذارد) خواهیم داشت که تست کردنش عملا شکنجه است. ولی اگر بخواهیم همان کد را با تابع ها بنویسیم نتیجه می شود:int main(){ int number, base; cin >> number >> base; int result = decimalToBaseX(number, base); int reversed = reverseNumber(result); int[] primeFactors = getPrimeFactors(reversed); printArrOfInts(primeFactors); }نه تنها کد باز هم به راحتی فهمیده می شود بلکه چون هر قسمت از آن توسط تابعی که کارش را مستقل از تابع های دیگر انجام میدهد اجرا می شود میتوان هر کدام از آن تابع ها را به طور مستقل بررسی کرد و اگر اشکالی وجود داشت تصحیح کرد و چون تابع های دیگر تنها به نتیجه ی همدیگر وابسته هستند و اهمیتی به پیاده سازی داخلی هم نمیدهند هیچ اتفاقی برایشان نمی افتد.3. استفاده مجدد از کدها ممکن می شود. اگر تابع های شما کار مشخصی را به درستی انجام دهند و به اطلاعاتی جز آرگومان های خود برای درست کار کردن وابسته نباشند میتوان به راحتی آن ها را به پروژه های دیگر منتقل کرد و مورد استفاده قرار داد که این باعث میشود وقت زیادی برای شما ذخیره شود و حتی احتمال ایجاد باگ هم کمتر می شود چون تابع قبلا تست شده و از کارکردش مطمئن هستید. علاوه بر آن حتی در خود پروژه ی موردنظر هم در صورتی که تابع هایتان را هوشمندانه تعریف کرده باشید میتوانید از تکرار کردن خیلی از مراحل جلوگیری کنید و اصطلاحا اصل DRY را رعایت کنید.4. روند حل کردن سوال ها برای شما سریعتر و آسان تر می شود. مثال آخر را دوباره نگاه کنید، بدون تلاش خاصی ما بدنه اصلی برنامه را نوشتیم، حالا برنامه ی ما که ممکن بود پیچیده به نظر بیاید به قسمت های کوچکتری شکسته شده که نوشتن هرکدام از آن ها(تعریف کردن تابع های مرتبط) آسان تر و سریعتر خواهد بود. در واقع این با خود ایده ی اصلی برنامه نویسی که شکستن مسائل پیچیده به زیر مسائل ساده تر تا حدی که مسائل به راحتی قابل حل باشند کاملا هماهنگ است.5. این آخرین دلیلی است که اینجا مطرح میکنم و بعد میرویم سراغ نکاتی که به ما کمک میکند تابع های خوبی بنویسیم. البته که دلایل بیشتری برای استفاده از تابع ها وجود دارد ولی آخرین دلیل ما این است که گاهی تابع ها به ما این امکان را میدهند که روش های جدیدی برای حل مسئله مان به کار بگیریم که میتواند ساده تر و سر راست تر و حتی بعضی وقت ها تنها راه باشد. دارم در مورد روش های بازگشتی صحبت میکنم. توابع بازگشتی مبحث مهم و مفصلی است که مطلب خودش را نیاز دارد پس فعلا از آن رد میشویم ولی بد نیست در موردش جستوجو و مطالعه کنید.چطور تابع های تمیز و کاربردی بنویسیم؟هر تابع باید یک و فقط یک کار را به درستی انجام دهد، اگر تابعی چند کار انجام میدهد، به تابع های کوچکتر بشکنیدش.نام تابع باید کاری که تابع میکند را به وضوح توضیح دهد، بهتر است نام تابع حالت فعل داشته باشد مثلا برای تابعی که مشخص میکند عدد اول است یا خیر isPrime اسم مناسبی است و برای تابعی که عددی را از مبنای ده به مبنای موردنظر میبرد، converFromDecimalToBaseX اسم مناسبی است.اگر نمیتوانید برای تابعتان اسم مناسبی انتخاب کنید احتمالا تابعتان دارد چند کار مختلف را انجام میدهد. برید سراغ نکته اوّل.تا جایی که مجبور نشده اید و راه دیگری ندارید سعی کنید تابعتان فقط به آرگومان هایش وابسته باشد و به هیچ وجه از محیط یا گلوبال ها تاثیری نگیرد چون در غیر این صورت پیشبینی خروجی تابع سخت می شود و تست کردن آن را سخت میکند.تا جایی که مجبور نشده اید و راه دیگری ندارید تابع هایی بنویسید که ساید افکت نداشته باشند، یعنی روی محیط و گلوبال ها تاثیر نذارند و هر تاثیری که دارند را از طریق مقدار بازگشتی شان اعمال کنند، دلیل این نکته با نکته بالا یکی است. در کل، هر چه تابع از این نظر ایزوله تر باشد بهتر است.مورد چهارم در بخش قبلی را یکبار دیگر با دقت بخوانید، با استفاده از این تکنیک میتوانید سریع تر توسعه دهید، کدهای با کیفیت تری بنویسید و احتمال خطا را کمتر کنید.اینا مواردی بودند که دانستنشان از نظر من برای کسی که میخواهد واقعا برنامه نویس باشد از نان شب هم واجب تر است. در فرصت مناسب در مورد قواعد دیگر نوشتن کدهای خوب هم خواهم نوشت، علی الحساب کداتون رو درست ایندنت کنید، به ولله نصف مشکلاتتون رو حل میکنه همین یه مورد :)موفق باشید.