برنامه نویسی تابعی (Functional) در جاوا اسکریپت – راهنمای کاربردی


برنامهنویسی تابعی مفهومی فوقالعاده است. در حال حاضر، با معرفی React، بسیاری از کدهای فرانت-اند جاوا اسکریپت با ذهنیتی ناشی از مفاهیم «برنامهنویسی تابعی» نوشته میشوند. اما سؤال این است که چگونه میتوانیم ذهنیتهای برنامهنویسی تابعی را در کدهای روزمره خود پیادهسازی کنیم؟

بیان مسئله
تصور کنید یک کاربر به صفحه login/ ما میآید و به طور اختیاری یک پارامتر کوئری redirect_to دارد. برای مثال لینک وی به صورت login?redirect_to=%2Fmy-page/ است. دقت کنید که %2Fmy-page در واقع همان my-page/ است که در URL کدگذاری شده است. ما باید این رشته کوئری را استخراج کنیم و آن را در یک متغیر محلی طوری ذخیره کنیم که وقتی عمل login صورت گرفت، کاربر بتواند به صفحه my-page ریدایرکت کند.
گام 0: رویکرد دستوری
اگر ما میخواستیم راهحل را به سادهترین وجه و با استفاده از صادر کردن یک فهرست از دستورها حل کنیم، آن را چگونه مینوشتیم؟ در این صورت ما به موارد زیر نیاز داشتیم؟
- تجزیه رشته کوئری
- دریافت مقدار redirect_to
- کدگشایی از این مقدار
- ذخیرهسازی مقدار کدگشایی شده در یک متغیر محلی
همچنین باید بلوکهای try catch را پیرامون تابع «unsafe» نیز قرار دهیم. بدین ترتیب بلوک کد ما چیزی شبیه زیر خواهد بود:
گام 1: نوشتن همه مراحل به صورت تابع
برای لحظهای بلوکهای try catch را فراموش کنید و تلاش کنید همه چیز را به صورت یک تابع بیان کنید:
زمانی که شروع به بررسی همه خروجیها به صورت مقادیر بازگشتی یک تابع بکنیم، میبینیم که میتوانیم بدنه تابع اصلی خودمان را بازنویسی بکنیم. زمانی که این اتفاق رخ میدهد، درک تابع ما بسیار آسانتر و تست کردن آن نیز سادهتر میشود.
در بخشهای پیشین، ما باید تابع اصلی خود را به صورت یک مجموعه کلی تست میکردیم؛ اما اینک 4 تابع کوچکتر داریم و برخی از آنها صرفاً واسطههایی برای تابعهای دیگر هستند و از این رو آن چه باید تست شود نیز کاهش یافته است.
در ادامه این تابعهای واسطه را پیدا کرده و آنها را حذف میکنیم و بدین ترتیب کد کمتری خواهیم داشت:
گام 2: تلاش برای ترکیب تابعها
اینک میبینیم که تابع persistRedirectToParams یک ترکیب از 4 تابع دیگر است. در ادامه بررسی میکنیم که آیا میتوانیم این تابع را به صورت یک ترکیب بنویسیم و بدین ترتیب نتایج درونی را که در const به نام s ذخیره میشوند را حذف کنیم.
این وضعیت خوبی است، اما ممکن است کسی که آن را میخواند، یک تابع تو در تو را تصور کند. اگر این شلوغی را نیز بتوانیم رفع کنید بسیار مناسب خواهد بود.
گام 3: یک ترکیب خواناتر
اگر با redux یا recompose آشنایی داشته باشید احتمالاً تاکنون با compose مواجه شدهاید. compose یک تابع کاربردی است که چندین تابع میپذیرد و یک تابع بازگشت میدهد. compose تابعهای تشکیلدهنده خود را یک به یک فراخوانی میکند. با توجه به این که منابع مناسب دیگری برای یادگیری compose وجود دارند در این نوشته وارد جزئیات آن نمیشویم. کد ما با استفاده از compose به صورت زیر درمیآید:
یک نکته در مورد compose این است که تابعها را به صورت راست به چپ اجرا میدهد. بدین ترتیب نخستین تابعی که در زنجیره compose فراخوانی شود همان تابع آخر است.
اگر یک ریاضیدان باشید و با مفهوم قضیه نیز آشنایی داشته باشید، این وضعیت مشکلی ایجاد نخواهد کرد، چون به طور طبیعی آن را راست به چپ میخوانید. اما برای بقیه افراد که به کدهای دستوری آشنایی ندارند، باید آن را طوری بنویسیم که از چپ به راست بخوانند.
گام 4: pipe کردن و مسطحسازی
برای حل مشکلی در که در گام قبل اشاره کردیم، مفهومی به نام pipe وجود دارد. pipe چیزی است که همان کار compose را، اما این بار در جهت عکس انجام میدهد. بنابراین نخستین تابع در زنجیره، نخستین تابعی است که نتیجه را پردازش خواهد کرد.
همچنین این طور به نظر میرسد که تابع persistRedirectToParams ما به پوششی برای تابع دیگر به نام op تبدیل شده است. به بیان دیگر تنها کاری که این تابع انجام میدهد، اجرای op است. ما میتوانیم با مسطح سازی تابع خودمان (flattening) از این وضعیت رهایی بیابیم.
بدین ترتیب به نتیجه دلخواه رسیدهایم. به خاطر داشته باشید که ما به سهولت بلوک try-catch خود را کنار گذاردیم تا به وضعیت کنونی برسیم. اما اینک مجبور هستیم آن را به نحوی مجدداً وارد کنیم، چون qs.parse نیز مانند storeRedirectToQuery ناامن است. یک گزینه این است که آنها را به تابعهای پوششی تبدیل کرده و آنها را در بلوکهای try-catch قرار دهیم. روش دیگر که با ذهنیت برنامهنویسی تابعی مطابقت بیشتری دارد، آن است که آن را به صورت یک تابع try-catch بیان کنیم.
گام 5: مدیریت استثنا به صورت یک تابع
برخی ابزارهای خاص به این منظور وجود دارند؛ اما سعی میکنیم خودمان یک تابع بنویسیم.
تابع ما یک شیء opts میگیرد که شامل تابعهای tryer و catcher است. این تابع یک تابع دیگر بازگشت میدهد و هنگامی که با آرگومانها فراخوانی شود، tryer را با آرگومانهای مذکور فراخوانی کرده. همچنین در صورت ناموفق بودن catcher را فراخوانی میکند. اینک وقتی که عملیات ناامنی داشته باشیم، میتوانیم آنها را در بخش tryer قرار دهیم و در صورت ناموفق بودن، از این وضعیت نجات یابیم و نتیجه امنی را از بخش section به دست آوریم و حتی خطا را نیز log کنیم.
گام 6: جمعبندی
بدین ترتیب و با جمعبندی همه مواردی پیشگفته، کد نهایی ما چیزی مانند زیر خواهد بود:
این کد همان چیزی است که کمابیش میخواستیم؛ اما باید مطمئن شویم که قابلیت استفاده مجدد و تست پذیری کد بهبود یافته است و میتوانیم تابعهای «امن» بسازیم.
اینک ما یک پیادهسازی بسیار بزرگتر از تابع داریم که از 4 تابع منفرد تشکیل یافته است که ارتباط زیادی با هم دارند. با این حال این تابعها پیوستگی اندکی با هم دارند، میتوانند به طور مستقل تست شوند، به طور مستقل مورد استفاده مجدد قرار گیرند، در موارد بروز استثنا پاسخگو باشند و کاملاً اعلانی (declarative) هستند.
اگر این مطلب برای شما مفید بوده است، آموزشهای زیر نیز به شما پیشنهاد میشوند:
- مجموعه آموزشهای برنامهنویسی
- مجموعه آموزشهای طراحی و توسعه پروژه های وب
- 12 نکته کلیدی برای ارزیابی کتابخانه های جدید جاوا اسکریپت
- چگونه برنامه نویس وب شویم؟ – بخش اول: فرانتاند (FrontEnd)
- بهینهسازی کدهای جاوا اسکریپت در سال 2۰1۸ — راهنمای جامع
==